├── src ├── views │ ├── exception │ │ └── empty.vue │ ├── demo │ │ ├── test2.vue │ │ └── test1.vue │ ├── vab │ │ ├── iconfont.vue │ │ ├── workflow.vue │ │ ├── dialog.vue │ │ ├── editor.vue │ │ ├── cron.vue │ │ ├── qrcode.vue │ │ ├── filterBar.vue │ │ ├── drag.vue │ │ ├── chart.vue │ │ ├── iconselect.vue │ │ ├── fileselect.vue │ │ ├── statistic.vue │ │ ├── print.vue │ │ ├── watermark.vue │ │ ├── select.vue │ │ ├── mini.vue │ │ ├── video.vue │ │ ├── tableselect.vue │ │ ├── form.vue │ │ └── cropper.vue │ ├── template │ │ ├── blank.vue │ │ └── list │ │ │ └── save.vue │ ├── other │ │ ├── fullpage.vue │ │ ├── viewTags.vue │ │ ├── about.vue │ │ └── directive.vue │ ├── home │ │ ├── widgets │ │ │ └── components │ │ │ │ ├── index.js │ │ │ │ ├── about.vue │ │ │ │ ├── progress.vue │ │ │ │ ├── ver.vue │ │ │ │ ├── time.vue │ │ │ │ ├── welcome.vue │ │ │ │ └── echarts.vue │ │ ├── work │ │ │ └── index.vue │ │ └── index.vue │ ├── test │ │ ├── codebug.vue │ │ └── autocode.vue │ ├── setting │ │ ├── log │ │ │ ├── info.vue │ │ │ └── index.vue │ │ ├── client │ │ │ └── index.vue │ │ ├── table │ │ │ └── index.vue │ │ ├── useSetData.js │ │ ├── dic │ │ │ ├── dic.vue │ │ │ └── list.vue │ │ ├── role │ │ │ └── save.vue │ │ └── task │ │ │ └── save.vue │ └── login │ │ └── login.scss ├── assets │ ├── logo.png │ ├── img │ │ ├── logo.png │ │ ├── avatar.jpg │ │ ├── logo-r.png │ │ ├── avatar2.gif │ │ ├── avatar3.gif │ │ └── auth_banner.jpg │ ├── style │ │ ├── index.scss │ │ ├── transition.scss │ │ ├── pages.scss │ │ └── media.scss │ └── icons │ │ ├── Vue.vue │ │ ├── index.js │ │ ├── Code.vue │ │ ├── FilePpt.vue │ │ ├── FileWord.vue │ │ ├── FileExcel.vue │ │ ├── BugFill.vue │ │ ├── BugLine.vue │ │ └── Wechat.vue ├── components │ ├── Wrapper │ │ └── index.vue │ ├── SwitchTheme │ │ └── index.vue │ ├── Title │ │ └── index.vue │ ├── ContextMenu │ │ ├── index.css │ │ ├── item.vue │ │ └── index.vue │ ├── Form │ │ └── tableselect.vue │ ├── ColorPicker │ │ └── index.vue │ ├── SvgIcon │ │ └── index.vue │ ├── Filterbar │ │ └── PySelect.vue │ ├── Echarts │ │ ├── echarts-theme-T.js │ │ └── index.vue │ ├── Mini │ │ ├── StatusIndicator.vue │ │ └── Trend.vue │ ├── PageHeader │ │ └── index.vue │ ├── WaterMark │ │ └── index.vue │ ├── Cropper │ │ └── index.vue │ ├── Qrcode │ │ └── index.vue │ ├── Statistic │ │ └── index.vue │ ├── SelectAsync │ │ └── index.vue │ ├── TableSelect │ │ └── index.vue │ ├── Editor │ │ └── index.vue │ └── FormTable │ │ └── index.vue ├── directives │ ├── index.js │ ├── role.js │ ├── auth.js │ ├── time.js │ ├── copy.js │ └── drag.js ├── service │ ├── demo.js │ ├── file.js │ ├── user.js │ └── system.js ├── store │ ├── index.js │ ├── userInfo.js │ ├── keepalive.js │ ├── iframe.js │ ├── tags.js │ └── config.js ├── plugins │ ├── element-plus.js │ └── message.js ├── config │ ├── select.js │ ├── upload.js │ ├── tableSelect.js │ ├── filterbar.js │ ├── route.js │ ├── fileSelect.js │ ├── workflow.js │ ├── index.js │ └── table.js ├── hooks │ ├── useGlobalProperties.js │ ├── useTheme.js │ ├── useWindowSize.js │ └── useTabs.js ├── main.js ├── router │ ├── basicRoute.js │ ├── guard.js │ ├── util.js │ └── index.js ├── utils │ ├── permission.js │ ├── errorHandler.js │ ├── type.js │ ├── color.js │ ├── constant.js │ ├── local.js │ └── date.js ├── App.vue ├── scui.js └── layout │ └── components │ ├── NavMenu.vue │ ├── IframeView.vue │ ├── Headerbar.vue │ ├── Setting.vue │ └── SideMenu.vue ├── public ├── logo.png ├── favicon.ico ├── tinymce │ └── skins │ │ ├── ui │ │ ├── oxide │ │ │ ├── fonts │ │ │ │ └── tinymce-mobile.woff │ │ │ ├── content.mobile.min.css │ │ │ ├── skin.shadowdom.min.css │ │ │ ├── content.mobile.css │ │ │ └── skin.shadowdom.css │ │ └── oxide-dark │ │ │ ├── fonts │ │ │ └── tinymce-mobile.woff │ │ │ ├── content.mobile.min.css │ │ │ ├── skin.shadowdom.min.css │ │ │ ├── content.mobile.css │ │ │ └── skin.shadowdom.css │ │ └── content │ │ ├── default │ │ ├── content.min.css │ │ └── content.css │ │ ├── writer │ │ ├── content.min.css │ │ └── content.css │ │ ├── dark │ │ ├── content.min.css │ │ └── content.css │ │ └── document │ │ ├── content.min.css │ │ └── content.css └── config.js ├── babel.config.js ├── .gitignore ├── jsconfig.json ├── README.md ├── package.json └── vue.config.js /src/views/exception/empty.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/public/logo.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/views/demo/test2.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/Wrapper/index.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/demo/test1.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/src/assets/img/logo.png -------------------------------------------------------------------------------- /src/assets/img/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/src/assets/img/avatar.jpg -------------------------------------------------------------------------------- /src/assets/img/logo-r.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/src/assets/img/logo-r.png -------------------------------------------------------------------------------- /src/assets/img/avatar2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/src/assets/img/avatar2.gif -------------------------------------------------------------------------------- /src/assets/img/avatar3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/src/assets/img/avatar3.gif -------------------------------------------------------------------------------- /src/assets/img/auth_banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/src/assets/img/auth_banner.jpg -------------------------------------------------------------------------------- /src/assets/style/index.scss: -------------------------------------------------------------------------------- 1 | @import 'app.scss'; 2 | @import 'fix.scss'; 3 | @import 'pages.scss'; 4 | @import 'media.scss'; 5 | @import 'transition.scss'; -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide/fonts/tinymce-mobile.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/public/tinymce/skins/ui/oxide/fonts/tinymce-mobile.woff -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide-dark/fonts/tinymce-mobile.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/XuJianChen1999/scui-restructure/HEAD/public/tinymce/skins/ui/oxide-dark/fonts/tinymce-mobile.woff -------------------------------------------------------------------------------- /src/views/vab/iconfont.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/views/template/blank.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /src/components/SwitchTheme/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /src/views/vab/workflow.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/views/other/fullpage.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/config.js: -------------------------------------------------------------------------------- 1 | // 此文件非必要,在生产环境下此文件配置可覆盖运行配置,开发环境下不起效 2 | // 详情见 src/config/index.js 3 | 4 | // eslint-disable-next-line no-unused-vars 5 | const APP_CONFIG = { 6 | //标题 7 | APP_NAME: "SCUI", 8 | 9 | //接口地址,如遇跨域需使用nginx代理 10 | API_URL: "https://www.fastmock.site/mock/5039c4361c39a7e3252c5b55971f1bd3/api" 11 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /src/assets/style/transition.scss: -------------------------------------------------------------------------------- 1 | /* 路由主视图过渡动画 */ 2 | .fade-transform-enter-active, 3 | .fade-transform-leave-active { 4 | transition: all .5s; 5 | } 6 | 7 | .fade-transform-enter-from { 8 | opacity: 0; 9 | transform: translateX(-30px) 10 | } 11 | 12 | .fade-transform-leave-to { 13 | opacity: 0; 14 | transform: translateX(30px) 15 | } -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/directives/index.js: -------------------------------------------------------------------------------- 1 | import drag from './drag' 2 | import auth from './auth' 3 | import time from './time' 4 | import copy from './copy' 5 | import role from './role' 6 | 7 | export default app => { 8 | app.directive('drag', drag) 9 | app.directive('auth', auth) 10 | app.directive('time', time) 11 | app.directive('copy', copy) 12 | app.directive('role', role) 13 | } -------------------------------------------------------------------------------- /src/views/vab/dialog.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/other/viewTags.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/service/demo.js: -------------------------------------------------------------------------------- 1 | import request from './request' 2 | import config from '@/config' 3 | 4 | // 获取分页列表 5 | export const getPagelist = params => request({ 6 | url: `${config.API_URL}/demo/page`, 7 | params 8 | }) 9 | 10 | export const page = { 11 | url: `${config.API_URL}/demo/post`, 12 | name: '分页列表', 13 | post: async function(data){ 14 | return await request.get(this.url, data) 15 | } 16 | } -------------------------------------------------------------------------------- /src/views/vab/editor.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /src/assets/icons/Vue.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/index.js: -------------------------------------------------------------------------------- 1 | export {default as Vue} from './Vue.vue' 2 | export {default as Code} from './Code.vue' 3 | export {default as Wechat} from './Wechat.vue' 4 | export {default as BugFill} from './BugFill.vue' 5 | export {default as BugLine} from './BugLine.vue' 6 | export {default as FileWord} from './FileWord.vue' 7 | export {default as FileExcel} from './FileExcel.vue' 8 | export {default as FilePpt} from './FilePpt.vue' -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import configStore from './config' 2 | import userStore from './userInfo' 3 | import keepAliveStore from './keepalive' 4 | import iframeStore from './iframe' 5 | const appStore = {} 6 | 7 | export const registerStore = () => { 8 | appStore.configStore = configStore() 9 | appStore.userStore = userStore() 10 | appStore.keepAliveStore = keepAliveStore() 11 | appStore.iframeStore = iframeStore() 12 | } 13 | 14 | export default appStore -------------------------------------------------------------------------------- /src/views/home/widgets/components/index.js: -------------------------------------------------------------------------------- 1 | import {markRaw} from 'vue' 2 | 3 | const resultComps = {} 4 | let requireComponent = require.context( 5 | './', // 在当前目录下查找 6 | false, // 不遍历子文件夹 7 | /\.vue$/ // 正则匹配 以 .vue结尾的文件 8 | ) 9 | requireComponent.keys().forEach(fileName => { 10 | let comp = requireComponent(fileName) 11 | resultComps[fileName.replace(/^\.\/(.*)\.\w+$/, '$1')] = comp.default 12 | }) 13 | 14 | export default markRaw(resultComps) -------------------------------------------------------------------------------- /src/assets/icons/Code.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/plugins/element-plus.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 10:03:36 4 | * @LastEditTime: 2022-03-10 10:05:46 5 | * @LastEditors: xjc 6 | * @Description: 全局注册element-plus组件 7 | */ 8 | import {ElButton} from 'element-plus' 9 | 10 | const components = [ElButton] 11 | const ElementPlus = { 12 | install: (App) => { 13 | components.forEach(component => App.component(component.name, component)) 14 | } 15 | } 16 | 17 | export default ElementPlus -------------------------------------------------------------------------------- /src/components/Title/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | -------------------------------------------------------------------------------- /src/config/select.js: -------------------------------------------------------------------------------- 1 | import {getDicData} from '@/service/system' 2 | 3 | export default { 4 | dicApiObj: async params => await getDicData(params), //获取字典接口对象 5 | parseData: function (res) { 6 | return { 7 | data: res.data, //分析行数据字段结构 8 | msg: res.message, //分析描述字段结构 9 | code: res.code //分析状态字段结构 10 | } 11 | }, 12 | request: {name: 'name'}, //规定搜索字段 13 | props: { 14 | label: 'label', //映射label显示字段 15 | value: 'value', //映射value值字段 16 | } 17 | } -------------------------------------------------------------------------------- /src/directives/role.js: -------------------------------------------------------------------------------- 1 | import {rolePermission} from '@/utils/permission' 2 | import {isArray} from '@/utils/type' 3 | 4 | export default { 5 | mounted(el, binding) { 6 | const {value} = binding 7 | if (isArray(value)) { 8 | let ishas = false 9 | value.forEach(item => { 10 | if (rolePermission(item)) { 11 | ishas = true 12 | } 13 | }) 14 | if (!ishas){ 15 | el.parentNode.removeChild(el) 16 | } 17 | } else{ 18 | if (!rolePermission(value)) { 19 | el.parentNode.removeChild(el) 20 | } 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/store/userInfo.js: -------------------------------------------------------------------------------- 1 | import {ref} from 'vue' 2 | import {defineStore} from 'pinia' 3 | import {getToken, getItem} from '@/utils/local' 4 | import {USER_INFO, MENU, PERMISSIONS} from '@/utils/constant' 5 | 6 | const userStore = defineStore(USER_INFO, () => { 7 | const token = ref(getToken() || '') 8 | const userInfo = ref(getItem(USER_INFO) || {}) 9 | const menus = ref(getItem(MENU) || []) 10 | const permissions = ref(getItem(PERMISSIONS) || []) 11 | 12 | return {token, userInfo, menus, permissions} 13 | }) 14 | 15 | export default userStore -------------------------------------------------------------------------------- /src/config/upload.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-15 17:10:40 4 | * @LastEditTime: 2022-03-15 17:11:51 5 | * @LastEditors: xjc 6 | * @Description: 上传配置 7 | */ 8 | import {uplaodFile} from '@/service/file' 9 | 10 | export default { 11 | apiObj: uplaodFile, //上传请求API对象 12 | successCode: 200, //请求完成代码 13 | maxSize: 10, //最大文件大小 默认10MB 14 | parseData: function (res) { 15 | return { 16 | code: res.code, //分析状态字段结构 17 | src: res.data.src, //分析图片远程地址结构 18 | msg: res.message //分析描述字段结构 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/config/tableSelect.js: -------------------------------------------------------------------------------- 1 | export default { 2 | pageSize: 20, // 表格每一页条数 3 | parseData: function (res) { 4 | return { 5 | data: res.data, 6 | rows: res.data.rows, // 分析行数据字段结构 7 | total: res.data.total, // 分析总数字段结构 8 | msg: res.message, // 分析描述字段结构 9 | code: res.code // 分析状态字段结构 10 | } 11 | }, 12 | request: { 13 | page: 'page', // 规定当前分页字段 14 | pageSize: 'pageSize', // 规定一页条数字段 15 | keyword: 'keyword' // 规定搜索字段 16 | }, 17 | props: { 18 | label: 'label', // 映射label显示字段 19 | value: 'value', // 映射value值字段 20 | } 21 | } -------------------------------------------------------------------------------- /src/hooks/useGlobalProperties.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 11:03:41 4 | * @LastEditTime: 2022-03-11 10:21:34 5 | * @LastEditors: xjc 6 | * @Description: 通过hooks获取全局app实例对象 7 | */ 8 | import {getCurrentInstance} from 'vue' 9 | import {ElMessageBox} from 'element-plus' 10 | 11 | export default function useGlobalProperties() { 12 | const {appContext: {app: {config: {globalProperties}}}} = getCurrentInstance() 13 | 14 | function confirm(title, options) { 15 | return ElMessageBox.confirm(title, options) 16 | } 17 | 18 | return {...globalProperties, confirm} 19 | } -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide/content.mobile.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | .tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{background-color:green;display:inline-block;opacity:.5;position:absolute}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%}body{font-family:sans-serif}table{border-collapse:collapse} 8 | -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide-dark/content.mobile.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | .tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{background-color:green;display:inline-block;opacity:.5;position:absolute}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%}body{font-family:sans-serif}table{border-collapse:collapse} 8 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import {createApp} from 'vue' 2 | import {createPinia} from 'pinia' 3 | import ElementPlus from 'element-plus' 4 | import App from './App' 5 | import router from './router' 6 | import {registerStore} from '@/store' 7 | import scui from './scui' 8 | import directives from './directives' 9 | 10 | import 'element-plus/dist/index.css' 11 | import 'element-plus/theme-chalk/display.css' 12 | 13 | const app = createApp(App) 14 | 15 | app.use(router) 16 | app.use(ElementPlus, {size: 'default'}) 17 | app.use(scui) 18 | app.use(createPinia()) 19 | app.use(directives) 20 | registerStore() 21 | 22 | app.mount('#app') 23 | -------------------------------------------------------------------------------- /src/router/basicRoute.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 15:20:41 4 | * @LastEditTime: 2022-03-10 15:24:03 5 | * @LastEditors: xjc 6 | * @Description: 系统级基本路由 7 | */ 8 | import config from '@/config' 9 | 10 | export default [ 11 | { 12 | name: 'layout', 13 | path: '/', 14 | component: () => import(/* webpackChunkName: "layout" */ '@/layout'), 15 | redirect: config.DASHBOARD_URL || '/dashboard', 16 | children: [] 17 | }, 18 | { 19 | path: '/login', 20 | component: () => import(/* webpackChunkName: "login" */ '@/views/login'), 21 | meta: { 22 | title: '登录' 23 | } 24 | } 25 | ] -------------------------------------------------------------------------------- /src/views/home/work/index.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | -------------------------------------------------------------------------------- /src/utils/permission.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-14 10:18:45 4 | * @LastEditTime: 2022-03-14 10:22:05 5 | * @LastEditors: xjc 6 | * @Description: 是否有xxx权限, 暂时不对传入的值做类型判断 7 | */ 8 | import {getItem} from './local' 9 | import {PERMISSIONS, USER_INFO} from './constant' 10 | 11 | export function permission(data) { 12 | let permissions = getItem(PERMISSIONS) 13 | if (!permissions) return false 14 | return permissions.includes(data) 15 | } 16 | 17 | export function rolePermission(data) { 18 | let userInfo = getItem(USER_INFO) 19 | if (!userInfo) return false 20 | let role = userInfo.role 21 | if (!role) return false 22 | return role.includes(data) 23 | } -------------------------------------------------------------------------------- /src/hooks/useTheme.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-14 15:37:41 4 | * @LastEditTime: 2022-03-14 15:41:05 5 | * @LastEditors: xjc 6 | * @Description: 监听切换主题,设置样式 7 | */ 8 | import {ref, watch} from 'vue' 9 | import {getItem} from '@/utils/local' 10 | import {APP_THEME} from '@/utils/constant' 11 | import useConfigStore from '@/store/config' 12 | 13 | export default function useTheme() { 14 | const {SET_theme} = useConfigStore() 15 | const theme = ref(getItem(APP_THEME) || 'default') 16 | 17 | watch(theme, newTheme => { 18 | document.body.setAttribute('data-theme', newTheme) 19 | SET_theme(newTheme) 20 | }, {immediate: true}) 21 | 22 | return theme 23 | } 24 | -------------------------------------------------------------------------------- /src/directives/auth.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-14 14:47:59 4 | * @LastEditTime: 2022-03-21 09:25:55 5 | * @LastEditors: xjc 6 | * @Description: 当前元素是否有某个权限 7 | */ 8 | import {permission} from '@/utils/permission' 9 | import {isArray} from '@/utils/type' 10 | 11 | export default { 12 | mounted(el, binding) { 13 | const {value} = binding 14 | if (isArray(value)) { 15 | let ishas = false 16 | value.forEach(item => { 17 | if (permission(item)) { 18 | ishas = true 19 | } 20 | }) 21 | if (!ishas) { 22 | el.parentNode.removeChild(el) 23 | } 24 | } else { 25 | if (!permission(value)) { 26 | el.parentNode.removeChild(el) 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/views/home/widgets/components/about.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /src/plugins/message.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 16:42:49 4 | * @LastEditTime: 2022-03-10 16:44:00 5 | * @LastEditors: xjc 6 | * @Description: 重写element-plus的ElMessage组件防止重复点击重复弹出message弹框 7 | */ 8 | import {ElMessage} from 'element-plus' 9 | let instance = null 10 | 11 | const resetMessageFn = options => { 12 | if (instance) instance.close() 13 | instance = ElMessage(options) 14 | } 15 | 16 | ['error', 'success', 'info', 'warning'].forEach(type => { 17 | resetMessageFn[type] = options => { 18 | if (typeof options === 'string') { 19 | options = {message: options} 20 | } 21 | options.type = type 22 | return resetMessageFn(options) 23 | } 24 | }) 25 | 26 | export default resetMessageFn -------------------------------------------------------------------------------- /src/directives/time.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-21 08:45:48 4 | * @LastEditTime: 2022-03-21 08:52:16 5 | * @LastEditors: xjc 6 | * @Description: v-time全局指令 7 | */ 8 | import {dateFormat, getFormateTime} from '@/utils/date' 9 | 10 | export default { 11 | mounted(el, binding) { 12 | let { value, modifiers} = binding 13 | if(value.toString().length == 10){ 14 | value = value * 1000 15 | } 16 | if (modifiers.tip) { 17 | el.innerHTML = getFormateTime(value) 18 | el.__timeout__ = setInterval(() => { 19 | el.innerHTML = getFormateTime(value) 20 | }, 60000) 21 | } else { 22 | const format = el.getAttribute('format') || undefined 23 | el.innerHTML = dateFormat(value, format) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/service/file.js: -------------------------------------------------------------------------------- 1 | import request from './request' 2 | import config from '@/config' 3 | 4 | // 文件上传 5 | export const uplaodFile = { 6 | url: `${config.API_URL}/upload`, 7 | name: '文件上传', 8 | post: async function(data, config = {}) { 9 | return await request.post(this.url, data, config); 10 | } 11 | } 12 | 13 | // 获取文件列表 14 | export const getFilelist = { 15 | url: `${config.API_URL}/file/list`, 16 | name: '获取文件列表', 17 | get: async function(params) { 18 | return await request.get(this.url, params) 19 | } 20 | } 21 | 22 | // 获取文件分类 23 | export const getFileCategory = { 24 | url: `${config.API_URL}/file/menu`, 25 | name: '获取文件分类', 26 | get: async function() { 27 | return await request.get(this.url) 28 | } 29 | } -------------------------------------------------------------------------------- /src/assets/icons/FilePpt.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/FileWord.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/hooks/useWindowSize.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-22 10:57:36 4 | * @LastEditTime: 2022-03-22 11:02:32 5 | * @LastEditors: xjc 6 | * @Description: 监听屏幕变化 7 | */ 8 | import {ref, onMounted, onUnmounted, onDeactivated} from 'vue' 9 | 10 | export default function useWindowSize() { 11 | const width = ref(0) 12 | const height = ref(0) 13 | 14 | function onResize() { 15 | width.value = window.innerWidth 16 | height.value = window.innerHeight 17 | } 18 | 19 | onMounted(() => { 20 | window.addEventListener('resize', onResize) 21 | onResize() 22 | }) 23 | onUnmounted(() => { 24 | window.removeEventListener('resize', onResize) 25 | }) 26 | onDeactivated(() => { 27 | window.removeEventListener('resize', onResize) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /src/utils/errorHandler.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 10:31:23 4 | * @LastEditTime: 2022-03-10 17:13:36 5 | * @LastEditors: xjc 6 | * @Description: 全局代码错误捕捉 7 | */ 8 | export default (error, vm)=>{ 9 | //过滤HTTP请求错误 10 | if (error.status) return false 11 | 12 | const errorMap = { 13 | InternalError: 'Javascript引擎内部错误', 14 | ReferenceError: '未找到对象', 15 | TypeError: '使用了错误的类型或对象', 16 | RangeError: '使用内置对象时,参数超范围', 17 | SyntaxError: '语法错误', 18 | EvalError: '错误的使用了Eval', 19 | URIError: 'URI错误' 20 | } 21 | const errorName = errorMap[error.name] || '未知错误' 22 | 23 | console.warn(`[SCUI error]: ${error}`) 24 | console.error(error) 25 | 26 | vm.$nextTick(() => { 27 | vm.$notify.error({ 28 | title: errorName, 29 | message: error 30 | }) 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /src/views/home/widgets/components/progress.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 20 | 21 | -------------------------------------------------------------------------------- /src/assets/icons/FileExcel.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide/skin.shadowdom.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;left:0;margin:0;overflow:hidden;-ms-scroll-chaining:none;overscroll-behavior:none;padding:0;position:fixed;top:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox.tox-tinymce.tox-fullscreen{background-color:transparent;z-index:1200}.tox-shadowhost.tox-fullscreen{z-index:1200}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201} 8 | -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;left:0;margin:0;overflow:hidden;-ms-scroll-chaining:none;overscroll-behavior:none;padding:0;position:fixed;top:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox.tox-tinymce.tox-fullscreen{background-color:transparent;z-index:1200}.tox-shadowhost.tox-fullscreen{z-index:1200}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201} 8 | -------------------------------------------------------------------------------- /src/service/user.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 16:59:15 4 | * @LastEditTime: 2022-03-21 10:53:40 5 | * @LastEditors: xjc 6 | * @Description: 用户模块请求 7 | */ 8 | import request from './request' 9 | import config from '@/config' 10 | 11 | // 获取登录token 12 | export const getAuthToken = data => request({ 13 | url: `${config.API_URL}/token`, 14 | method: 'post', 15 | data 16 | }) 17 | 18 | // 获取我的菜单 19 | export const getMyMenus = () => request({url: `${config.API_URL}/system/menu/my/1.5.0`,}) 20 | 21 | // 获取普通用户菜单 22 | export const getOrdinaryMenus = () => request({url: `${config.API_URL}/demo/menu`}) 23 | 24 | // 获取用户列表 25 | export const getUserlist = { 26 | url: `${config.API_URL}/system/user/list`, 27 | name: '获取用户列表', 28 | get: async function(params){ 29 | return await request.get(this.url, params) 30 | } 31 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scui 重构版 2 | 3 | 4 | ## 感谢scui的开源,本项目是在原有基础上的重构,原仓库代码在下方链接 5 | 6 | ## Customary 7 | 1. 代码原仓库:scui原仓库代码 (https://gitee.com/lolicode/scui) 8 | 2. 预览地址:在线预览地址 (https://lolicode.gitee.io/scui-doc/demo/#/dashboard) 9 | 10 | ## Different 11 | 1. 与原版不同的是,本次重构采用了setup语法 + hooks + pinia 12 | 13 | 2. 原版虽然使用了vue3,但是写法上还是延续了Options API,并没有充分发挥出Composition API的优势 14 | 15 | 3. scui原版的代码中由于采用了Options API,全局的实例挂载了太多,每次刷新都会加载,不太友好 16 | 17 | 4. 对缓存、请求、工具库做了抽离化的封装 18 | ## Different 19 | ``` 20 | npm install 21 | ``` 22 | 23 | ### Compiles and hot-reloads for development 24 | ``` 25 | npm run serve 26 | ``` 27 | 28 | ### Compiles and minifies for production 29 | ``` 30 | npm run build 31 | ``` 32 | 33 | ### Lints and fixes files 34 | ``` 35 | npm run lint 36 | ``` 37 | 38 | ### Customize configuration 39 | See [Configuration Reference](https://cli.vuejs.org/config/). 40 | -------------------------------------------------------------------------------- /src/views/home/index.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | -------------------------------------------------------------------------------- /src/utils/type.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 11:44:55 4 | * @LastEditTime: 2022-03-10 11:44:55 5 | * @LastEditors: xjc 6 | * @Description: 检查变量类型 7 | */ 8 | const toString = Object.prototype.toString 9 | const checkTypeFn = type => { 10 | return function isType(value) { 11 | return toString.call(value) === `[object ${type}]` 12 | } 13 | } 14 | 15 | export const isFunc = checkTypeFn('Function') 16 | export const isUndefined = checkTypeFn('Undefined') 17 | export const isArray = checkTypeFn('Array') 18 | export const isString = checkTypeFn('String') 19 | export const isObject = checkTypeFn('Object') 20 | export const isNumber = checkTypeFn('Number') 21 | export const isDate = checkTypeFn('Date') 22 | export const isHtmlElement = node => node && node.nodeType === Node.ELEMENT_NODE 23 | export const isDefined = val => val !== undefined && val !== null -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide/content.mobile.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | .tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection { 8 | /* Note: this file is used inside the content, so isn't part of theming */ 9 | background-color: green; 10 | display: inline-block; 11 | opacity: 0.5; 12 | position: absolute; 13 | } 14 | body { 15 | -webkit-text-size-adjust: none; 16 | } 17 | body img { 18 | /* this is related to the content margin */ 19 | max-width: 96vw; 20 | } 21 | body table img { 22 | max-width: 95%; 23 | } 24 | body { 25 | font-family: sans-serif; 26 | } 27 | table { 28 | border-collapse: collapse; 29 | } 30 | -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide-dark/content.mobile.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | .tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection { 8 | /* Note: this file is used inside the content, so isn't part of theming */ 9 | background-color: green; 10 | display: inline-block; 11 | opacity: 0.5; 12 | position: absolute; 13 | } 14 | body { 15 | -webkit-text-size-adjust: none; 16 | } 17 | body img { 18 | /* this is related to the content margin */ 19 | max-width: 96vw; 20 | } 21 | body table img { 22 | max-width: 95%; 23 | } 24 | body { 25 | font-family: sans-serif; 26 | } 27 | table { 28 | border-collapse: collapse; 29 | } 30 | -------------------------------------------------------------------------------- /src/router/guard.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 14:23:09 4 | * @LastEditTime: 2022-03-14 15:47:07 5 | * @LastEditors: xjc 6 | * @Description: 路由导航守卫 7 | */ 8 | import {nextTick} from 'vue' 9 | import useViewTagStore from '@/store/tags' 10 | 11 | export function beforeEach(to) { 12 | const {updateViewTags} = useViewTagStore() 13 | const adminMain = document.querySelector('#adminui-main') 14 | if (!adminMain) return false 15 | updateViewTags({ 16 | fullPath: to.fullPath, 17 | scrollTop: adminMain.scrollTop 18 | }) 19 | } 20 | 21 | export function afterEach(to){ 22 | const adminMain = document.querySelector('#adminui-main') 23 | const {viewTags} = useViewTagStore() 24 | if (!adminMain) return false 25 | nextTick(()=>{ 26 | const beforeRoute = viewTags.filter(v => v.fullPath == to.fullPath)[0] 27 | if (beforeRoute) { 28 | adminMain.scrollTop = beforeRoute.scrollTop || 0 29 | } 30 | }) 31 | } -------------------------------------------------------------------------------- /src/utils/color.js: -------------------------------------------------------------------------------- 1 | // hex颜色转rgb颜色 2 | export function HexToRgb(str) { 3 | str = str.replace('#', '') 4 | let hxs = str.match(/../g) 5 | for (let i = 0; i < 3; i++) hxs[i] = parseInt(hxs[i], 16) 6 | return hxs 7 | } 8 | 9 | // rgb颜色转hex颜色 10 | export function RgbToHex(a, b, c) { 11 | let hexs = [a.toString(16), b.toString(16), c.toString(16)] 12 | for (let i = 0; i < 3; i++) { 13 | if (hexs[i].length == 1) hexs[i] = '0' + hexs[i] 14 | } 15 | return '#' + hexs.join(''); 16 | } 17 | 18 | // 加深 19 | export function darken(color, level) { 20 | let rgbc = HexToRgb(color) 21 | for (let i = 0; i < 3; i++) rgbc[i] = Math.floor(rgbc[i] * (1 - level)) 22 | return RgbToHex(rgbc[0], rgbc[1], rgbc[2]) 23 | } 24 | 25 | // 变淡 26 | export function lighten(color, level) { 27 | let rgbc = HexToRgb(color) 28 | for (let i = 0; i < 3; i++) rgbc[i] = Math.floor((255 - rgbc[i]) * level + rgbc[i]) 29 | return RgbToHex(rgbc[0], rgbc[1], rgbc[2]) 30 | } -------------------------------------------------------------------------------- /src/utils/constant.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 10:23:33 4 | * @LastEditTime: 2022-03-22 16:41:33 5 | * @LastEditors: xjc 6 | * @Description: 集中管理常量 7 | */ 8 | export const baseName = 'SCUI_RESTRUCTURE' 9 | 10 | // 本地缓存常量 11 | export const TOKEN = `${baseName}--TOKEN` 12 | export const MENU = `${baseName}--MENU` 13 | export const USER_INFO = `${baseName}--USER-INFO` 14 | export const APP_THEME = `${baseName}--APP_THEME` 15 | export const APP_COLOR = `${baseName}--APP_COLOR` 16 | export const APP_LAYOUT = `${baseName}--APP_LAYOUT` 17 | export const PERMISSIONS = `${baseName}--PERMISSIONS` 18 | export const GRID = `${baseName}--GRID` 19 | export const MY_MODS = `${baseName}--MY_MODS` 20 | 21 | // store常量 22 | export const APP = `${baseName}--APP` 23 | export const VIEW_TAGS = `${baseName}--VIEW_TAGS` 24 | export const KEEPALIVE = `${baseName}--KEEPALIVE` 25 | export const IFRAME = `${baseName}--IFRAME` 26 | 27 | // 屏幕宽度阀值 28 | export const SCREEN_WIDTH = 992 -------------------------------------------------------------------------------- /src/views/vab/cron.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 28 | 29 | 33 | -------------------------------------------------------------------------------- /src/assets/icons/BugFill.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/views/home/widgets/components/ver.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /src/components/ContextMenu/index.css: -------------------------------------------------------------------------------- 1 | .sc-contextmenu {position: fixed;z-index: 3000;} 2 | .sc-contextmenu__menu {display: inline-block;min-width: 120px;border: 1px solid #e4e7ed;background: #fff;box-shadow: 0 2px 12px 0 rgba(0,0,0,.1);z-index: 3000;list-style-type: none;padding: 10px 0;} 3 | .sc-contextmenu__menu > hr {margin:5px 0;border: none;height: 1px;font-size: 0px;background-color: #ebeef5;} 4 | .sc-contextmenu__menu > li {margin:0;cursor: pointer;line-height: 30px;padding: 0 17px 0 10px;color: #606266;display: flex;justify-content: space-between;white-space: nowrap;text-decoration: none;position: relative;} 5 | .sc-contextmenu__menu > li:hover {background-color: #ecf5ff;color: #66b1ff;} 6 | .sc-contextmenu__menu > li.disabled {cursor: not-allowed;color: #bbb;background: transparent;} 7 | .sc-contextmenu__icon {display: inline-block;width: 14px;font-size: 14px;margin-right: 10px;} 8 | .sc-contextmenu__suffix {margin-left: 40px;color: #999;} 9 | .sc-contextmenu__menu li ul {position: absolute;top:0px;left:100%;display: none;margin: -11px 0;} -------------------------------------------------------------------------------- /src/directives/copy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-21 08:52:55 4 | * @LastEditTime: 2022-03-21 08:57:51 5 | * @LastEditors: xjc 6 | * @Description: 全局copy指令 7 | */ 8 | import {ElMessage} from 'element-plus' 9 | 10 | export default { 11 | mounted(el, binding) { 12 | el.$value = binding.value 13 | el.handler = () => { 14 | const textarea = document.createElement('textarea') 15 | textarea.readOnly = 'readonly' 16 | textarea.style.position = 'absolute' 17 | textarea.style.left = '-9999px' 18 | textarea.value = el.$value 19 | document.body.appendChild(textarea) 20 | textarea.select() 21 | textarea.setSelectionRange(0, textarea.value.length) 22 | const result = document.execCommand('Copy') 23 | result && ElMessage.success('复制成功') 24 | document.body.removeChild(textarea) 25 | } 26 | el.addEventListener('click', el.handler) 27 | }, 28 | updated(el, binding){ 29 | el.$value = binding.value 30 | }, 31 | unmounted(el){ 32 | el.removeEventListener('click', el.handler) 33 | } 34 | } -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide/skin.shadowdom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | body.tox-dialog__disable-scroll { 8 | overflow: hidden; 9 | } 10 | .tox-fullscreen { 11 | border: 0; 12 | height: 100%; 13 | left: 0; 14 | margin: 0; 15 | overflow: hidden; 16 | -ms-scroll-chaining: none; 17 | overscroll-behavior: none; 18 | padding: 0; 19 | position: fixed; 20 | top: 0; 21 | touch-action: pinch-zoom; 22 | width: 100%; 23 | } 24 | .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { 25 | display: none; 26 | } 27 | .tox.tox-tinymce.tox-fullscreen { 28 | background-color: transparent; 29 | z-index: 1200; 30 | } 31 | .tox-shadowhost.tox-fullscreen { 32 | z-index: 1200; 33 | } 34 | .tox-fullscreen .tox.tox-tinymce-aux, 35 | .tox-fullscreen ~ .tox.tox-tinymce-aux { 36 | z-index: 1201; 37 | } 38 | -------------------------------------------------------------------------------- /public/tinymce/skins/ui/oxide-dark/skin.shadowdom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | body.tox-dialog__disable-scroll { 8 | overflow: hidden; 9 | } 10 | .tox-fullscreen { 11 | border: 0; 12 | height: 100%; 13 | left: 0; 14 | margin: 0; 15 | overflow: hidden; 16 | -ms-scroll-chaining: none; 17 | overscroll-behavior: none; 18 | padding: 0; 19 | position: fixed; 20 | top: 0; 21 | touch-action: pinch-zoom; 22 | width: 100%; 23 | } 24 | .tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { 25 | display: none; 26 | } 27 | .tox.tox-tinymce.tox-fullscreen { 28 | background-color: transparent; 29 | z-index: 1200; 30 | } 31 | .tox-shadowhost.tox-fullscreen { 32 | z-index: 1200; 33 | } 34 | .tox-fullscreen .tox.tox-tinymce-aux, 35 | .tox-fullscreen ~ .tox.tox-tinymce-aux { 36 | z-index: 1201; 37 | } 38 | -------------------------------------------------------------------------------- /src/store/keepalive.js: -------------------------------------------------------------------------------- 1 | import {ref} from 'vue' 2 | import {defineStore} from 'pinia' 3 | import {KEEPALIVE} from '@/utils/constant' 4 | 5 | const keepAliveStore = defineStore(KEEPALIVE, () => { 6 | const keepLiveRoute = ref([]) 7 | const routeKey = ref(null) 8 | const routeShow = ref(true) 9 | 10 | function pushKeepLive(component) { 11 | if (!keepLiveRoute.value.includes(component)) { 12 | keepLiveRoute.value.push(component) 13 | } 14 | } 15 | function removeKeepLive(component) { 16 | const index = keepLiveRoute.value.indexOf(component) 17 | if(index !== -1){ 18 | keepLiveRoute.value.splice(index, 1) 19 | } 20 | } 21 | function clearKeepLive(){ 22 | keepLiveRoute.value = [] 23 | } 24 | function setRouteKey(key){ 25 | routeKey.value = key 26 | } 27 | function setRouteShow(key){ 28 | routeShow.value = key 29 | } 30 | 31 | return { 32 | keepLiveRoute, routeKey, routeShow, 33 | pushKeepLive, removeKeepLive, clearKeepLive, setRouteKey, setRouteShow 34 | } 35 | }) 36 | 37 | export default keepAliveStore -------------------------------------------------------------------------------- /src/components/Form/tableselect.vue: -------------------------------------------------------------------------------- 1 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /src/components/ColorPicker/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /src/views/home/widgets/components/time.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 34 | 35 | 40 | -------------------------------------------------------------------------------- /src/views/vab/qrcode.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 37 | 38 | -------------------------------------------------------------------------------- /src/views/vab/filterBar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 31 | -------------------------------------------------------------------------------- /src/scui.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 10:29:52 4 | * @LastEditTime: 2022-03-15 11:56:52 5 | * @LastEditors: xjc 6 | * @Description: 7 | */ 8 | import config from './config' 9 | 10 | import errorHandler from './utils/errorHandler' 11 | import {permission, rolePermission} from './utils/permission' 12 | 13 | import SvgIcon from '@/components/SvgIcon' 14 | import ComWrapper from '@/components/Wrapper' 15 | 16 | import * as elicons from '@element-plus/icons' 17 | import * as myicons from './assets/icons' 18 | 19 | export default { 20 | install(app) { 21 | //挂载全局对象 22 | app.config.globalProperties.$CONFIG = config 23 | app.config.globalProperties.$AUTH = permission 24 | app.config.globalProperties.$ROLE = rolePermission 25 | 26 | //注册全局组件 27 | app.component('SvgIcon', SvgIcon) 28 | app.component('ComWrapper', ComWrapper) 29 | 30 | //统一注册el-icon图标 31 | for (let icon in elicons) { 32 | app.component(`ElIcon${icon}`, elicons[icon]) 33 | } 34 | //统一注册sc-icon图标 35 | for (let icon in myicons) { 36 | app.component(`ScIcon${icon}`, myicons[icon]) 37 | } 38 | 39 | //全局代码错误捕捉 40 | app.config.errorHandler = errorHandler 41 | } 42 | } -------------------------------------------------------------------------------- /src/assets/style/pages.scss: -------------------------------------------------------------------------------- 1 | /* USERCENTER */ 2 | .user-info {padding:20px 40px;} 3 | .user-info-top {text-align: center;} 4 | .user-info-top h2 {margin-top:10px;font-size: 24px;} 5 | .user-info-top p {color: #999;margin-top:5px;} 6 | .user-info-top button {margin-top:10px;} 7 | .user-info-main {padding:20px 0;} 8 | .user-info-main li {list-style-type:none;line-height: 2;font-size: 14px;} 9 | .user-info-main li i {margin-right: 10px;} 10 | .user-info-bottom {border-top: 1px solid #e6e6e6;} 11 | .user-info-bottom h2 {font-size: 14px;margin:15px 0;} 12 | 13 | /*static-table*/ 14 | .static-table {border-collapse: collapse;width: 100%;font-size: 14px;margin-bottom: 45px;line-height: 1.5em;} 15 | .static-table th {text-align: left;white-space: nowrap;color: #909399;font-weight: 400;border-bottom: 1px solid #dcdfe6;padding: 15px;max-width: 250px;} 16 | .static-table td {border-bottom: 1px solid #dcdfe6;padding: 15px;max-width: 250px;color: #606266;} 17 | 18 | /*header-tabs*/ 19 | .header-tabs {padding:0;display:block;border:0!important;height:auto;} 20 | .header-tabs .el-tabs {border:0;box-shadow:none;} 21 | .header-tabs .el-tabs__content {display: none;} 22 | .header-tabs .el-tabs__item {font-size: 12px;} 23 | -------------------------------------------------------------------------------- /src/assets/icons/BugLine.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /src/views/test/codebug.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | -------------------------------------------------------------------------------- /src/config/filterbar.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // 运算符 3 | operator: [ 4 | {label: '等于', value: '='}, 5 | {label: '不等于', value: '!='}, 6 | {label: '大于', value: '>'}, 7 | {label: '大于等于', value: '>='}, 8 | {label: '小于', value: '<'}, 9 | {label: '小于等于', value: '<='}, 10 | {label: '包含', value: 'include'}, 11 | {label: '不包含', value: 'notinclude'} 12 | ], 13 | // 过滤结果运算符的分隔符 14 | separator: '|', 15 | // 获取我的常用 16 | getMy: function (name) { 17 | return new Promise(resolve => { 18 | console.log(`这里可以根据${name}参数请求接口`) 19 | let list = [] 20 | const timer = setTimeout(() => resolve(list), 500) 21 | clearTimeout(timer) 22 | }) 23 | }, 24 | /** 25 | * 常用保存处理 返回resolve后继续操作 26 | * @name scFilterBar组件的props->filterName 27 | * @obj 过滤项整理好的对象 28 | */ 29 | saveMy: function (name, obj) { 30 | return new Promise(resolve => { 31 | console.log(name, obj) 32 | const timer = setTimeout(() => resolve(true), 500) 33 | clearTimeout(timer) 34 | }) 35 | }, 36 | /** 37 | * 常用删除处理 返回resolve后继续操作 38 | * @name scFilterBar组件的props->filterName 39 | */ 40 | delMy: function (name) { 41 | return new Promise(resolve => { 42 | console.log(name) 43 | const timer = setTimeout(() => resolve(true), 500) 44 | clearTimeout(timer) 45 | }) 46 | } 47 | } -------------------------------------------------------------------------------- /src/views/vab/drag.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 30 | 31 | -------------------------------------------------------------------------------- /src/components/SvgIcon/index.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 37 | 38 | -------------------------------------------------------------------------------- /src/components/Filterbar/PySelect.vue: -------------------------------------------------------------------------------- 1 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /src/layout/components/NavMenu.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | -------------------------------------------------------------------------------- /src/store/iframe.js: -------------------------------------------------------------------------------- 1 | import {ref} from 'vue' 2 | import {defineStore} from 'pinia' 3 | import {IFRAME} from '@/utils/constant' 4 | 5 | const iframeStore = defineStore(IFRAME, () => { 6 | const iframeList = ref([]) 7 | 8 | function setIframeList(route){ 9 | iframeList.value = [] 10 | iframeList.value.push(route) 11 | } 12 | function pushIframeList(route){ 13 | let target = iframeList.value.find(item => item.path === route.path) 14 | if (!target) { 15 | iframeList.value.push(route) 16 | } 17 | } 18 | function removeIframeList(route){ 19 | iframeList.value.forEach((item, index) => { 20 | if (item.path === route.path){ 21 | iframeList.value.splice(index, 1) 22 | } 23 | }) 24 | } 25 | function refreshIframe( route){ 26 | iframeList.value.forEach((item) => { 27 | if (item.path === route.path){ 28 | var url = route.meta.url 29 | item.meta.url = '' 30 | const timer = setTimeout(function() { 31 | item.meta.url = url 32 | }, 200) 33 | clearTimeout(timer) 34 | } 35 | }) 36 | } 37 | function clearIframeList(){ 38 | iframeList.value = [] 39 | } 40 | 41 | return { 42 | iframeList, 43 | setIframeList, pushIframeList, removeIframeList, refreshIframe, clearIframeList 44 | } 45 | }) 46 | 47 | export default iframeStore -------------------------------------------------------------------------------- /src/views/other/about.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 30 | 31 | -------------------------------------------------------------------------------- /src/components/Echarts/echarts-theme-T.js: -------------------------------------------------------------------------------- 1 | const T = { 2 | "color": [ 3 | "#409EFF", 4 | "#36CE9E", 5 | "#f56e6a", 6 | "#626c91", 7 | "#edb00d", 8 | "#909399" 9 | ], 10 | 'grid': { 11 | 'left': '3%', 12 | 'right': '3%', 13 | 'bottom': '10', 14 | 'top': '40', 15 | 'containLabel': true 16 | }, 17 | "legend": { 18 | "textStyle": { 19 | "color": "#999" 20 | }, 21 | "inactiveColor": "rgba(128,128,128,0.4)" 22 | }, 23 | "categoryAxis": { 24 | "axisLine": { 25 | "show": true, 26 | "lineStyle": { 27 | "color": "rgba(128,128,128,0.2)", 28 | "width": 1 29 | } 30 | }, 31 | "axisTick": { 32 | "show": false, 33 | "lineStyle": { 34 | "color": "#333" 35 | } 36 | }, 37 | "axisLabel": { 38 | "color": "#999" 39 | }, 40 | "splitLine": { 41 | "show": false, 42 | "lineStyle": { 43 | "color": [ 44 | "#eee" 45 | ] 46 | } 47 | }, 48 | "splitArea": { 49 | "show": false, 50 | "areaStyle": { 51 | "color": [ 52 | "rgba(255,255,255,0.01)", 53 | "rgba(0,0,0,0.01)" 54 | ] 55 | } 56 | } 57 | }, 58 | "valueAxis": { 59 | "axisLine": { 60 | "show": false, 61 | "lineStyle": { 62 | "color": "#999" 63 | } 64 | }, 65 | "splitLine": { 66 | "show": true, 67 | "lineStyle": { 68 | "color": "rgba(128,128,128,0.2)" 69 | } 70 | } 71 | } 72 | } 73 | 74 | export default T 75 | -------------------------------------------------------------------------------- /src/config/route.js: -------------------------------------------------------------------------------- 1 | // 静态路由配置 2 | // 书写格式与动态路由格式一致,全部经由框架统一转换 3 | // 比较动态路由在meta中多加入了role角色权限,为数组类型。一个菜单是否有权限显示,取决于它以及后代菜单是否有权限。 4 | // routes 显示在左侧菜单中的路由(显示顺序在动态路由之前) 5 | // 示例如下 6 | 7 | // const routes = [ 8 | // { 9 | // name: "demo", 10 | // path: "/demo", 11 | // meta: { 12 | // icon: "el-icon-eleme-filled", 13 | // title: "演示", 14 | // role: ["SA"] 15 | // }, 16 | // children: [{ 17 | // name: "demopage", 18 | // path: "/demopage", 19 | // component: "test/autocode/index", 20 | // meta: { 21 | // icon: "el-icon-menu", 22 | // title: "演示页面", 23 | // role: ["SA"] 24 | // } 25 | // }] 26 | // } 27 | // ] 28 | 29 | const routes = [ 30 | { 31 | name: 'demo', 32 | path: '/demo', 33 | meta: { 34 | icon: 'el-icon-eleme-filled', 35 | title: '静态路由', 36 | role: ['SA'] 37 | }, 38 | children: [ 39 | { 40 | name: 'testpage', 41 | path: '/testpage', 42 | component: 'demo/test1', 43 | meta: { 44 | icon: "el-icon-menu", 45 | title: "演示页面1", 46 | role: ["SA"] 47 | } 48 | } 49 | ] 50 | }, 51 | { 52 | name: 'testpage2', 53 | path: '/testpage2', 54 | meta: { 55 | icon: "el-icon-menu", 56 | title: "静态路由2", 57 | role: ["SA"] 58 | }, 59 | component: 'demo/test2', 60 | } 61 | ] 62 | 63 | export default routes -------------------------------------------------------------------------------- /src/views/vab/chart.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | -------------------------------------------------------------------------------- /src/config/fileSelect.js: -------------------------------------------------------------------------------- 1 | import {uplaodFile, getFilelist, getFileCategory} from '@/service/file' 2 | 3 | export default { 4 | apiObj: uplaodFile, 5 | menuApiObj: getFileCategory, 6 | listApiObj: getFilelist, 7 | successCode: 200, 8 | maxSize: 30, 9 | max: 99, 10 | uploadParseData: res => ({ 11 | id: res.data.id, 12 | fileName: res.data.fileName, 13 | url: res.data.src 14 | }), 15 | listParseData: res=> ({ 16 | rows: res.data.rows, 17 | total: res.data.total, 18 | msg: res.message, 19 | code: res.code 20 | }), 21 | request: { 22 | page: 'page', 23 | pageSize: 'pageSize', 24 | keyword: 'keyword', 25 | menuKey: 'groupId' 26 | }, 27 | menuProps: { 28 | key: 'id', 29 | label: 'label', 30 | children: 'children' 31 | }, 32 | fileProps: { 33 | key: 'id', 34 | fileName: 'fileName', 35 | url: 'url' 36 | }, 37 | files: { 38 | doc: { 39 | icon: 'sc-icon-file-word-2-fill', 40 | color: '#409eff' 41 | }, 42 | docx: { 43 | icon: 'sc-icon-file-word-2-fill', 44 | color: '#409eff' 45 | }, 46 | xls: { 47 | icon: 'sc-icon-file-excel-2-fill', 48 | color: '#67C23A' 49 | }, 50 | xlsx: { 51 | icon: 'sc-icon-file-excel-2-fill', 52 | color: '#67C23A' 53 | }, 54 | ppt: { 55 | icon: 'sc-icon-file-ppt-2-fill', 56 | color: '#F56C6C' 57 | }, 58 | pptx: { 59 | icon: 'sc-icon-file-ppt-2-fill', 60 | color: '#F56C6C' 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /public/tinymce/skins/content/default/content.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem} 8 | -------------------------------------------------------------------------------- /public/tinymce/skins/content/writer/content.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem auto;max-width:900px}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem} 8 | -------------------------------------------------------------------------------- /src/store/tags.js: -------------------------------------------------------------------------------- 1 | import {ref} from 'vue' 2 | import {defineStore} from 'pinia' 3 | import {VIEW_TAGS} from '@/utils/constant' 4 | 5 | const viewTagsStore = defineStore(VIEW_TAGS, () => { 6 | const viewTags = ref([]) 7 | 8 | function pushViewTags(route) { 9 | console.log(route) 10 | let target = viewTags.value.find(item => item.fullPath === route.fullPath) 11 | let isName = route.name 12 | if(!target && isName){ 13 | viewTags.value.push(route) 14 | } 15 | } 16 | 17 | function removeViewTags(route){ 18 | viewTags.value.forEach((item, index) => { 19 | if (item.fullPath === route.fullPath){ 20 | viewTags.value.splice(index, 1) 21 | } 22 | }) 23 | } 24 | 25 | function updateViewTags(route){ 26 | viewTags.value.forEach(item => { 27 | if (item.fullPath === route.fullPath){ 28 | item = {...item, ...route} 29 | } 30 | }) 31 | console.log('viewTags.value', viewTags.value) 32 | } 33 | 34 | function updateViewTagsTitle(title = ''){ 35 | const nowFullPath = location.hash.substring(1) 36 | viewTags.value.forEach(item => { 37 | if (item.fullPath === nowFullPath){ 38 | item.meta.title = title 39 | } 40 | }) 41 | } 42 | 43 | function clearViewTags(){ 44 | viewTags.value = [] 45 | } 46 | 47 | return { 48 | viewTags, 49 | pushViewTags, removeViewTags, updateViewTags, updateViewTagsTitle, clearViewTags 50 | } 51 | }) 52 | 53 | export default viewTagsStore -------------------------------------------------------------------------------- /src/config/workflow.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-17 15:00:00 4 | * @LastEditTime: 2022-03-17 15:38:59 5 | * @LastEditors: xjc 6 | * @Description: 审批工作流人员 / 组织选择器配置 7 | */ 8 | import {role} from '@/service/system' 9 | import {getPagelist} from '@/service/demo' 10 | 11 | export default { 12 | // 配置接口正常返回代码 13 | successCode: 200, 14 | // 配置组织 15 | group: { 16 | // 请求接口对象 17 | apiObj: role, 18 | // 接受数据字段映射 19 | parseData: res =>({ 20 | rows: res.data, 21 | msg: res.message, 22 | code: res.code 23 | }), 24 | // 显示数据字段映射 25 | props: { 26 | key: 'id', 27 | label: 'label', 28 | children: 'children' 29 | } 30 | }, 31 | // 配置用户 32 | user: { 33 | apiObj: async params => getPagelist(params), 34 | pageSize: 20, 35 | parseData: res => ({ 36 | rows: res.data.rows, 37 | total: res.data.total, 38 | msg: res.message, 39 | code: res.code 40 | }), 41 | props: { 42 | key: 'id', 43 | label: 'user', 44 | }, 45 | request: { 46 | page: 'page', 47 | pageSize: 'pageSize', 48 | groupId: 'groupId', 49 | keyword: 'keyword' 50 | } 51 | }, 52 | //配置角色 53 | role: { 54 | //请求接口对象 55 | apiObj: async params => getPagelist(params), 56 | //接受数据字段映射 57 | parseData: res => ({ 58 | rows: res.data, 59 | msg: res.message, 60 | code: res.code 61 | }), 62 | //显示数据字段映射 63 | props: { 64 | key: 'id', 65 | label: 'label', 66 | children: 'children' 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/store/config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: xjc 3 | * @Date: 2022-03-10 14:27:18 4 | * @LastEditTime: 2022-03-22 16:47:03 5 | * @LastEditors: xjc 6 | * @Description: 7 | */ 8 | import {ref} from 'vue' 9 | import {defineStore} from 'pinia' 10 | import {APP, APP_THEME, APP_LAYOUT} from '@/utils/constant' 11 | import {setItem, getItem} from '@/utils/local' 12 | import config from '@/config' 13 | 14 | const configStore = defineStore(APP, () => { 15 | const isMobile = ref(false) // 移动端布局 16 | const layout = ref(getItem(APP_LAYOUT) || config.LAYOUT) // 布局 17 | const collapse = ref(config.MENU_IS_COLLAPSE) // 菜单是否折叠 18 | const layoutTags = ref(config.LAYOUT_TAGS) // 多标签栏 19 | const theme = ref(config.THEME) // 主题 20 | const primaryColor = '#346fff' // 全局主色 21 | 22 | function SET_isMobile(isMobiled) { 23 | isMobile.value = isMobiled 24 | } 25 | function SET_layout(value) { 26 | setItem(APP_LAYOUT, value) 27 | layout.value = value 28 | } 29 | function SET_theme(value) { 30 | theme.value = value 31 | setItem(APP_THEME, value) 32 | } 33 | function TOGGLE_collapse() { 34 | collapse.value = !collapse.value 35 | } 36 | function TOGGLE_layoutTags() { 37 | layoutTags.value = !layoutTags.value 38 | } 39 | 40 | return { 41 | isMobile, layout, collapse, layoutTags, theme, primaryColor, 42 | SET_isMobile, SET_layout, SET_theme, TOGGLE_collapse, TOGGLE_layoutTags 43 | } 44 | }) 45 | 46 | export default configStore -------------------------------------------------------------------------------- /public/tinymce/skins/content/dark/content.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Tiny Technologies, Inc. All rights reserved. 3 | * Licensed under the LGPL or a commercial license. 4 | * For LGPL see License.txt in the project root for license information. 5 | * For commercial licenses see https://www.tiny.cloud/ 6 | */ 7 | body{background-color:#2f3742;color:#dfe0e4;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem} 8 | -------------------------------------------------------------------------------- /src/layout/components/IframeView.vue: -------------------------------------------------------------------------------- 1 |