diff --git a/.env b/.env
new file mode 100644
index 0000000..873997e
--- /dev/null
+++ b/.env
@@ -0,0 +1,7 @@
+# port
+VITE_PORT =8848
+VITE_SYS_NAME =心理测评系统后台管理
+
+VITE_BASE_API = '/api'
+VITE_ADMIN_API = '/admin-api'
+
diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..91924b9
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,9 @@
+# 本地环境
+NODE_ENV = 'development'
+
+# 本地环境接口地址
+
+VITE_BASE_ENV = 'stage'
+VITE_BASE_PATH = ''
+VITE_BASE_PORT = '9012'
+VITE_DG_PROJECT_SYSTEM = 'http://localhost:8091'
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..72fadc6
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,9 @@
+# 线上环境
+NODE_ENV = "production"
+
+# 线上环境接口地址
+VITE_BASE_ENV = 'prod'
+VITE_BASE_PATH = ''
+VITE_BASE_PORT = '9015'
+VITE_DG_PROJECT_SYSTEM = 'https://nk.cqdg.xyz:9086'
+
diff --git a/.env.stage b/.env.stage
new file mode 100644
index 0000000..78b3ff4
--- /dev/null
+++ b/.env.stage
@@ -0,0 +1,9 @@
+# 测试环境
+NODE_ENV = "test"
+
+
+# 测试环境接口地址
+VITE_BASE_ENV = 'stage'
+VITE_BASE_PATH = ''
+VITE_BASE_PORT = '9012'
+VITE_DG_PROJECT_SYSTEM = 'http://222.179.96.190:8091'
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..348631b
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,15 @@
+
+*.sh
+node_modules
+*.md
+*.woff
+*.ttf
+.vscode
+.idea
+dist
+/public
+/docs
+.husky
+.local
+/bin
+Dockerfile
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..aacc9af
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,25 @@
+module.exports = {
+ "env": {
+ "browser": true,
+ "es2021": true,
+ "node": true
+ },
+ "extends": [
+ "eslint:recommended",
+ "plugin:vue/vue3-essential",
+ "plugin:@typescript-eslint/recommended",
+ 'plugin:prettier/recommended'
+ ],
+ "parser": "vue-eslint-parser",
+ "parserOptions": {
+ "ecmaVersion": "latest",
+ "parser": "@typescript-eslint/parser",
+ "sourceType": "module"
+ },
+ "plugins": [
+ "vue",
+ "@typescript-eslint"
+ ],
+ "rules": {
+ }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..82b8b1b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,25 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist-ssr
+dist
+*.local
+package-lock.json
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..f7e39e6
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,9 @@
+/dist/*
+.local
+.output.js
+/node_modules/**
+
+**/*.svg
+**/*.sh
+
+/public/*
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..637a5cf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,42 @@
+## 简介
+本项目是基于Vue3 + Vite + TS 的多页面大型MPA项目, 他目前提供了pc用户端模块和后台管理模块的开发编译和打包。
+项目支持模块的扩展、支持单独模块运行和打包、也支持全部模块一起运行和打包。
+
+## 技术栈
+- [Vue](https://cn.vuejs.org/guide/introduction.html) 现代前端框架,使应用界面开发简单高效,提供流畅的用户体验。
+- [Vite](https://cn.vitejs.dev/) 快速构建工具,为项目带来更快的开发速度和响应性能。
+- [Typescript](https://github.com/microsoft/TypeScript) 静态类型的JavaScript超集,确保代码质量和可维护性,减少潜在错误。
+- [Element-plus](https://element-plus.gitee.io/zh-CN/component/button.html) 基于Vue的精美UI组件库,提供漂亮、功能丰富的界面元素,加速开发进度,让项目外观更专业。
+- [Tailwind CSS](https://www.tailwindcss.cn/docs/installation) 强大的CSS框架,提供丰富的可定制样式,快速构建独特的现代界面。
+- [Pinia](https://pinia.vuejs.org/zh/introduction.html) 现代化的Vue状态管理库,简单易用,让应用状态管理更高效可靠。
+- [Axios](https://github.com/axios/axios) 流行的HTTP客户端,使数据交互更简单,提供稳定的网络请求和响应处理。
+
+
+## 开发运行
+
+```bash
+ # 安装依赖
+ npm run install
+
+ # 本地开发 开启所有模块服务
+ npm run dev
+
+ # 本地开发 开启单个模块服务
+ npm run dev --page=admin
+
+ # 测试环境打包
+ npm run build:stage
+ # 单个模块打包
+ npm run build:stage --page=admin
+
+ # 生产环境打包
+ npm run build:prod
+ # 单个模块打包
+ npm run build:prod --page=admin
+
+ # 创建新模块
+ npm run new:page
+
+```
+
+
diff --git a/commitlint.config.js b/commitlint.config.js
new file mode 100644
index 0000000..171d0c3
--- /dev/null
+++ b/commitlint.config.js
@@ -0,0 +1,81 @@
+// 文档参考:https://cz-git.qbb.sh/zh/config/
+// cz.config.js kk
+/** @type {import('cz-git').CommitizenGitOptions} */
+module.exports = {
+ ignores: [commit => commit.includes("init")],
+ extends: ["@commitlint/config-conventional"],
+ // alias: { fd: 'docs: fix typos' },
+ // messages: {
+ // type: 'Select the type of change that you\'re committing:',
+ // scope: 'Denote the SCOPE of this change (optional):',
+ // customScope: 'Denote the SCOPE of this chang e:',
+ // subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
+ // body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
+ // breaking: 'List any BREAKING CHANGES (optional). Use "|" to break new line:\n',
+ // footerPrefixsSelect: 'Select the ISSUES type of changeList by this change (optional):',
+ // customFooterPrefixs: 'Input ISSUES prefix:',
+ // footer: 'List any ISSUES by this change. E.g.: #31, #34:\n',
+ // confirmCommit: 'Are you sure you want to proceed with the commit above?'
+ // },
+ prompt: {
+ // 中英文对照版
+ messages: {
+ type: '选择你要提交的类型 :',
+ scope: '选择一个提交范围(可选):',
+ customScope: '请输入自定义的提交范围 :',
+ subject: '填写简短精炼的变更描述 :\n',
+ body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
+ breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
+ footerPrefixesSelect: '选择关联issue前缀(可选):',
+ customFooterPrefix: '输入自定义issue前缀 :',
+ footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
+ confirmCommit: '是否提交或修改commit ?'
+ },
+ types: [
+ { value: '特性', name: '特性: 新增功能' },
+ { value: '修复', name: '修复: 修复缺陷' },
+ { value: '文档', name: '文档: 文档变更' },
+ { value: '格式', name: '格式: 代码格式(不影响功能,例如空格、分号等格式修正)' },
+ { value: '重构', name: '重构: 代码重构(不包括 bug 修复、功能新增)' },
+ { value: '性能', name: '性能: 性能优化' },
+ { value: '测试', name: '测试: 添加疏漏测试或已有测试改动' },
+ { value: '构建', name: '构建: 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)' },
+ { value: '集成', name: '集成: 修改 CI 配置、脚本' },
+ { value: '回退', name: '回退: 回滚 commit' },
+ { value: '其他', name: '其他: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)' },
+ ],
+ // emptyScopesAlias: 'empty: 不填写',
+ // customScopesAlias: 'custom: 自定义',
+
+ useEmoji: true,
+ // emojiAlign: 'center',
+ themeColorCode: '',
+ scopes: [],
+ allowCustomScopes: true,
+ allowEmptyScopes: true,
+ customScopesAlign: 'bottom',
+ customScopesAlias: 'custom',
+ emptyScopesAlias: 'empty',
+ upperCaseSubject: false,
+ markBreakingChangeMode: false,
+ allowBreakingChanges: ['feat', 'fix'],
+ breaklineNumber: 100,
+ breaklineChar: '|',
+ skipQuestions: [],
+ issuePrefixs: [{ value: 'closed', name: 'closed: ISSUES has been processed' }],
+ customIssuePrefixsAlign: 'top',
+ emptyIssuePrefixsAlias: 'skip',
+ customIssuePrefixsAlias: 'custom',
+ allowCustomIssuePrefixs: true,
+ allowEmptyIssuePrefixs: true,
+ confirmColorize: true,
+ maxHeaderLength: Infinity,
+ maxSubjectLength: Infinity,
+ minSubjectLength: 0,
+ scopeOverrides: undefined,
+ defaultBody: '',
+ defaultIssues: '',
+ defaultScope: '',
+ defaultSubject: ''
+ }
+}
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..0acb9bd
--- /dev/null
+++ b/index.html
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+ %VITE_SYS_NAME%
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..0508492
--- /dev/null
+++ b/package.json
@@ -0,0 +1,96 @@
+{
+ "name": "dg-project",
+ "private": true,
+ "version": "1.0.1",
+ "author": "dangc",
+ "scripts": {
+ "dev": "vite",
+ "build:dev": "vite build --mode development",
+ "build:stage": "vite build --mode stage",
+ "build:prod": "vite build --mode production",
+ "commit": "git add -A && czg ",
+ "build": "vite build",
+ "preview": "vite preview",
+ "build:ts": "vue-tsc --noEmit --skipLibCheck && vite build",
+ "new:page": "node ./scripts/index.mjs",
+ "lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
+ "lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\""
+ },
+ "dependencies": {
+ "@better-scroll/core": "^2.4.2",
+ "@vueuse/core": "^9.1.1",
+ "@wangeditor/editor": "^5.1.14",
+ "@wangeditor/editor-for-vue": "^5.1.12",
+ "await-to-js": "^3.0.0",
+ "axios": "^0.27.2",
+ "clipboard": "^2.0.10",
+ "core-js": "^3.6.5",
+ "crypto-js": "^4.1.1",
+ "dayjs": "^1.11.4",
+ "echarts": "^5.3.1",
+ "element-plus": "^2.2.28",
+ "file-saver": "^2.0.5",
+ "fuse.js": "^6.6.2",
+ "highlight.js": "^9.18.5",
+ "js-cookie": "^3.0.5",
+ "nprogress": "^0.2.0",
+ "path-browserify": "^1.0.1",
+ "path-to-regexp": "^6.2.0",
+ "pinia": "^2.0.21",
+ "pinia-plugin-persistedstate": "^2.1.1",
+ "raf": "^3.4.1",
+ "resize-observer-polyfill": "^1.5.1",
+ "sass": "^1.54.0",
+ "svg-sprite-loader": "^6.0.11",
+ "vkbeautify": "^0.99.3",
+ "vue": "^3.2.39",
+ "vue-cropper": "^1.0.3",
+ "vue-cropperjs": "^5.0.0",
+ "vue-fuse": "^4.1.1",
+ "vue-qr": "^4.0.6",
+ "vue-router": "^4.1.6",
+ "workflow-bpmn-modeler": "^0.2.8"
+ },
+ "devDependencies": {
+ "@commitlint/cli": "^17.3.0",
+ "@commitlint/config-conventional": "^17.3.0",
+ "@tailwindcss/typography": "^0.5.9",
+ "@types/chalk": "^2.2.0",
+ "@types/crypto-js": "^4.1.1",
+ "@types/file-saver": "^2.0.5",
+ "@types/js-cookie": "^3.0.3",
+ "@typescript-eslint/eslint-plugin": "^5.32.0",
+ "@typescript-eslint/parser": "^5.32.0",
+ "@vitejs/plugin-vue": "^3.0.0",
+ "autoprefixer": "^10.4.14",
+ "commitizen": "^4.2.5",
+ "consola": "^2.15.3",
+ "cz-git": "^1.3.12",
+ "czg": "^1.3.12",
+ "dart-sass": "^1.25.0",
+ "dotenv": "^16.3.1",
+ "eslint": "^8.21.0",
+ "eslint-config-prettier": "^8.5.0",
+ "eslint-plugin-prettier": "^4.2.1",
+ "eslint-plugin-vue": "^9.3.0",
+ "fast-glob": "^3.2.11",
+ "postcss": "^8.4.23",
+ "prettier": "^2.7.1",
+ "tailwindcss": "^3.3.2",
+ "typescript": "^4.6.4",
+ "unplugin-auto-import": "^0.10.3",
+ "unplugin-vue-components": "^0.21.2",
+ "unplugin-vue-define-options": "^0.7.3",
+ "vite": "^4.3.8",
+ "vite-plugin-compression": "^0.5.1",
+ "vite-plugin-style-import": "^2.0.0",
+ "vite-plugin-svg-icons": "^2.0.1",
+ "vite-plugin-vue-setup-extend": "^0.4.0",
+ "vue-tsc": "^1.6.5"
+ },
+ "config": {
+ "commitizen": {
+ "path": "node_modules/cz-git"
+ }
+ }
+}
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 0000000..33ad091
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ tailwindcss: {},
+ autoprefixer: {},
+ },
+}
diff --git a/prettier.config.js b/prettier.config.js
new file mode 100644
index 0000000..fe640cd
--- /dev/null
+++ b/prettier.config.js
@@ -0,0 +1,14 @@
+module.exports = {
+ // 一行的字符数,如果超过会进行换行,默认为80
+ printWidth: 150,
+ // 行位是否使用分号,默认为true
+ semi: false,
+ vueIndentScriptAndStyle: true,
+ // 字符串是否使用单引号,默认为false,使用双引号
+ singleQuote: true,
+ // 是否使用尾逗号,有三个可选值""
+ trailingComma: 'all',
+ proseWrap: 'never',
+ htmlWhitespaceSensitivity: 'strict',
+ endOfLine: 'auto',
+};
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..54e49ae
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/log.png b/public/log.png
new file mode 100644
index 0000000..1f20ee0
Binary files /dev/null and b/public/log.png differ
diff --git a/public/static/screen/bg.jpg b/public/static/screen/bg.jpg
new file mode 100644
index 0000000..164d641
Binary files /dev/null and b/public/static/screen/bg.jpg differ
diff --git a/public/static/screen/bg.png b/public/static/screen/bg.png
new file mode 100644
index 0000000..4d00e1a
Binary files /dev/null and b/public/static/screen/bg.png differ
diff --git a/public/static/screen/footer2.png b/public/static/screen/footer2.png
new file mode 100644
index 0000000..8bb531b
Binary files /dev/null and b/public/static/screen/footer2.png differ
diff --git a/public/static/screen/header-bg.png b/public/static/screen/header-bg.png
new file mode 100644
index 0000000..7ae3251
Binary files /dev/null and b/public/static/screen/header-bg.png differ
diff --git a/public/static/screen/server-bg.png b/public/static/screen/server-bg.png
new file mode 100644
index 0000000..a0a8963
Binary files /dev/null and b/public/static/screen/server-bg.png differ
diff --git a/scripts/index.mjs b/scripts/index.mjs
new file mode 100644
index 0000000..b8e19ac
--- /dev/null
+++ b/scripts/index.mjs
@@ -0,0 +1,64 @@
+import chalk from 'chalk'
+import path from 'path'
+import fs from 'fs'
+
+const resolve = (__dirname, ...file) => path.resolve(__dirname, ...file)
+const log = (message) => console.log(chalk.green(`${message}`))
+const successLog = (message) => console.log(chalk.blue(`${message}`))
+const errorLog = (error) => console.log(chalk.red(`${error}`))
+log('请输入要生成的"模块名称"、会生成在 /src/modules 目录下')
+process.stdin.on('data', async (chunk) => {
+ const pagePath = 'src/modules'
+ const pages = fs.readdirSync(path.resolve('./src/modules'))
+ // 获取输入的信息
+ const projectName = String(chunk).trim().toString()
+
+
+ if(!projectName || pages.includes(projectName)){
+ errorLog('模块已经存在,请重新输入')
+ return
+ }
+ successLog(`将在 /src/modules 目录下创建 ${projectName} 文件夹`)
+ const targetPath = resolve('./src/modules', projectName)
+ fs.mkdirSync(targetPath)
+ copyFile('./scripts/template', targetPath)
+ setFile()
+ async function setFile() {
+ // 修改项目中/router/inbex.ts的文件内容
+ const routerPath = resolve(targetPath, './router/index.ts')
+ const data = await fs.promises.readFile(routerPath, 'utf8');
+ const modifiedData = data.replace(/\${pagaPath}/, `/${projectName}`);
+ await fs.promises.writeFile(routerPath, modifiedData, 'utf8');
+
+ successLog(`${projectName}模块已创建`);
+ process.stdin.emit('end')
+ }
+})
+
+process.stdin.on('end', () => {
+ process.exit()
+})
+
+
+// 判断文件夹是否存在,不存在创建一个
+const isExist = (path) => {
+ if (!fs.existsSync(path)) {
+ fs.mkdirSync(path)
+ }
+}
+//递归复制模版文件夹内的文件
+const copyFile = (sourcePath, targetPath) => {
+ const sourceFile = fs.readdirSync(sourcePath, { withFileTypes: true })
+
+ sourceFile.forEach((file) => {
+ const newSourcePath = path.resolve(sourcePath, file.name)
+ const newTargetPath = path.resolve(targetPath, file.name)
+ //isDirectory() 判断这个文件是否是文件夹,是就继续递归复制其内容
+ if (file.isDirectory()) {
+ isExist(newTargetPath)
+ copyFile(newSourcePath, newTargetPath)
+ } else {
+ fs.copyFileSync(newSourcePath, newTargetPath)
+ }
+ })
+}
diff --git a/scripts/template/App.vue b/scripts/template/App.vue
new file mode 100644
index 0000000..8484259
--- /dev/null
+++ b/scripts/template/App.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/scripts/template/index.html b/scripts/template/index.html
new file mode 100644
index 0000000..9a39a7f
--- /dev/null
+++ b/scripts/template/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/template/main.ts b/scripts/template/main.ts
new file mode 100644
index 0000000..b184618
--- /dev/null
+++ b/scripts/template/main.ts
@@ -0,0 +1,6 @@
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from './router'
+
+const app = createApp(App)
+app.use(router).mount('#app')
diff --git a/scripts/template/router/index.ts b/scripts/template/router/index.ts
new file mode 100644
index 0000000..3d153ab
--- /dev/null
+++ b/scripts/template/router/index.ts
@@ -0,0 +1,24 @@
+import { createRouter, createWebHistory, createWebHashHistory } from "vue-router";
+
+
+const routes: any = [
+ {
+ path: '/',
+ redirect: '/home'
+ },
+ {
+ path: '/home',
+ component: () => import("../views/index.vue")
+ },
+]
+
+const router = createRouter({
+ history: createWebHistory('${pagaPath}'),
+ routes: [...routes],
+});
+
+router.beforeEach((to, from, next) => {
+ (document as any).title = to.meta.title || "德工建设";
+ next();
+});
+export default router;
\ No newline at end of file
diff --git a/scripts/template/views/index.vue b/scripts/template/views/index.vue
new file mode 100644
index 0000000..095db3d
--- /dev/null
+++ b/scripts/template/views/index.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
首页
+
+
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 0000000..fb1433a
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
diff --git a/src/libs/components/icons/SvgIcon/index.vue b/src/libs/components/icons/SvgIcon/index.vue
new file mode 100644
index 0000000..72813f7
--- /dev/null
+++ b/src/libs/components/icons/SvgIcon/index.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/libs/icons/element/iconNames.json b/src/libs/icons/element/iconNames.json
new file mode 100644
index 0000000..019a7cf
--- /dev/null
+++ b/src/libs/icons/element/iconNames.json
@@ -0,0 +1,349 @@
+[
+ {
+ "code": "System",
+ "name": "系统",
+ "icons": [
+ "Plus",
+ "Minus",
+ "CirclePlus",
+ "Search",
+ "Female",
+ "Male",
+ "Aim",
+ "House",
+ "FullScreen",
+ "Loading",
+ "Link",
+ "Service",
+ "Pointer",
+ "Star",
+ "Notification",
+ "Connection",
+ "ChatDotRound",
+ "Setting",
+ "Clock",
+ "Position",
+ "Discount",
+ "Odometer",
+ "ChatSquare",
+ "ChatRound",
+ "ChatLineRound",
+ "ChatLineSquare",
+ "ChatDotSquare",
+ "View",
+ "Hide",
+ "Unlock",
+ "Lock",
+ "RefreshRight",
+ "RefreshLeft",
+ "Refresh",
+ "Bell",
+ "MuteNotification",
+ "User",
+ "Check",
+ "CircleCheck",
+ "Warning",
+ "CircleClose",
+ "Close",
+ "PieChart",
+ "More",
+ "Compass",
+ "Filter",
+ "Switch",
+ "Select",
+ "SemiSelect",
+ "CloseBold",
+ "EditPen",
+ "Edit",
+ "Message",
+ "MessageBox",
+ "TurnOff",
+ "Finished",
+ "Delete",
+ "Crop",
+ "SwitchButton",
+ "Operation",
+ "Open",
+ "Remove",
+ "ZoomOut",
+ "ZoomIn",
+ "InfoFilled",
+ "CircleCheckFilled",
+ "SuccessFilled",
+ "WarningFilled",
+ "CircleCloseFilled",
+ "QuestionFilled",
+ "WarnTriangleFilled",
+ "UserFilled",
+ "MoreFilled",
+ "Tools",
+ "HomeFilled",
+ "UploadFilled",
+ "Avatar",
+ "HelpFilled",
+ "menuIcon",
+ "Share",
+ "StarFilled",
+ "Comment",
+ "Histogram",
+ "Grid",
+ "Promotion",
+ "DeleteFilled",
+ "RemoveFilled",
+ "CirclePlusFilled"
+ ]
+ },
+ {
+ "code": "Arrow",
+ "name": "箭头",
+ "icons": [
+ "ArrowLeft",
+ "ArrowUp",
+ "ArrowRight",
+ "ArrowDown",
+ "ArrowLeftBold",
+ "ArrowUpBold",
+ "ArrowRightBold",
+ "ArrowDownBold",
+ "DArrowRight",
+ "DArrowLeft",
+ "Download",
+ "Upload",
+ "Top",
+ "Bottom",
+ "Back",
+ "Right",
+ "TopRight",
+ "TopLeft",
+ "BottomRight",
+ "BottomLeft",
+ "Sort",
+ "SortUp",
+ "SortDown",
+ "Rank",
+ "CaretLeft",
+ "CaretTop",
+ "CaretRight",
+ "CaretBottom",
+ "DCaret",
+ "Expand",
+ "Fold"
+ ]
+ },
+ {
+ "code": "Document",
+ "name": "文档",
+ "icons": [
+ "DocumentAdd",
+ "Document",
+ "Notebook",
+ "Tickets",
+ "Memo",
+ "Collection",
+ "Postcard",
+ "ScaleToOriginal",
+ "SetUp",
+ "DocumentDelete",
+ "DocumentChecked",
+ "DataBoard",
+ "DataAnalysis",
+ "CopyDocument",
+ "FolderChecked",
+ "Files",
+ "Folder",
+ "FolderDelete",
+ "FolderRemove",
+ "FolderOpened",
+ "DocumentCopy",
+ "DocumentRemove",
+ "FolderAdd",
+ "FirstAidKit",
+ "Reading",
+ "DataLine",
+ "Management",
+ "Checked",
+ "Ticket",
+ "Failed",
+ "TrendCharts",
+ "List"
+ ]
+ },
+ {
+ "code": "Media",
+ "name": "媒体",
+ "icons": [
+ "Microphone",
+ "Mute",
+ "Mic",
+ "VideoPause",
+ "VideoCamera",
+ "VideoPlay",
+ "Headset",
+ "Monitor",
+ "Film",
+ "Camera",
+ "Picture",
+ "PictureRounded",
+ "Iphone",
+ "Cellphone",
+ "VideoCameraFilled",
+ "PictureFilled",
+ "Platform",
+ "CameraFilled",
+ "BellFilled"
+ ]
+ },
+ {
+ "code": "Traffic",
+ "name": "交通",
+ "icons": [
+ "Location",
+ "LocationInformation",
+ "DeleteLocation",
+ "Coordinate",
+ "Bicycle",
+ "OfficeBuilding",
+ "School",
+ "Guide",
+ "AddLocation",
+ "MapLocation",
+ "Place",
+ "LocationFilled",
+ "Van"
+ ]
+ },
+ {
+ "code": "Food",
+ "name": "食物",
+ "icons": [
+ "Watermelon",
+ "Pear",
+ "NoSmoking",
+ "Smoking",
+ "Mug",
+ "GobletSquareFull",
+ "GobletFull",
+ "KnifeFork",
+ "Sugar",
+ "Bowl",
+ "MilkTea",
+ "Lollipop",
+ "Coffee",
+ "Chicken",
+ "Dish",
+ "IceTea",
+ "ColdDrink",
+ "CoffeeCup",
+ "DishDot",
+ "IceDrink",
+ "IceCream",
+ "Dessert",
+ "IceCreamSquare",
+ "ForkSpoon",
+ "IceCreamRound",
+ "Food",
+ "HotWater",
+ "Grape",
+ "Fries",
+ "Apple",
+ "Burger",
+ "Goblet",
+ "GobletSquare",
+ "Orange",
+ "Cherry"
+ ]
+ },
+ {
+ "code": "Items",
+ "name": "项目",
+ "icons": [
+ "Printer",
+ "Calendar",
+ "CreditCard",
+ "Box",
+ "Money",
+ "Refrigerator",
+ "Cpu",
+ "Football",
+ "Brush",
+ "Suitcase",
+ "SuitcaseLine",
+ "Umbrella",
+ "AlarmClock",
+ "Medal",
+ "GoldMedal",
+ "Present",
+ "Mouse",
+ "Watch",
+ "QuartzWatch",
+ "Magnet",
+ "Help",
+ "Soccer",
+ "ToiletPaper",
+ "ReadingLamp",
+ "Paperclip",
+ "MagicStick",
+ "Basketball",
+ "Baseball",
+ "Coin",
+ "Goods",
+ "Sell",
+ "SoldOut",
+ "Key",
+ "ShoppingCart",
+ "ShoppingCartFull",
+ "ShoppingTrolley",
+ "Phone",
+ "Scissor",
+ "Handbag",
+ "ShoppingBag",
+ "Trophy",
+ "TrophyBase",
+ "Stopwatch",
+ "Timer",
+ "CollectionTag",
+ "TakeawayBox",
+ "PriceTag",
+ "Wallet",
+ "Opportunity",
+ "PhoneFilled",
+ "WalletFilled",
+ "GoodsFilled",
+ "Flag",
+ "BrushFilled",
+ "Briefcase",
+ "Stamp"
+ ]
+ },
+ {
+ "code": "Weather",
+ "name": "天气",
+ "icons": [
+ "Sunrise",
+ "Sunny",
+ "Ship",
+ "MostlyCloudy",
+ "PartlyCloudy",
+ "Sunset",
+ "Drizzling",
+ "Pouring",
+ "Cloudy",
+ "Moon",
+ "MoonNight",
+ "Lightning"
+ ]
+ },
+ {
+ "code": "Other",
+ "name": "其他",
+ "icons": [
+ "ChromeFilled",
+ "Eleme",
+ "ElemeFilled",
+ "ElementPlus",
+ "Shop",
+ "SwitchFilled",
+ "WindPower"
+ ]
+ }
+]
\ No newline at end of file
diff --git a/src/libs/icons/index.js b/src/libs/icons/index.js
new file mode 100644
index 0000000..175c6da
--- /dev/null
+++ b/src/libs/icons/index.js
@@ -0,0 +1,11 @@
+import Vue from 'vue'
+import SvgIcon from '@lib/components/icons/SvgIcon' // svg component
+
+
+// const req = require.context('./svg', false, /\.svg$/)
+const req = import.meta.globEager('./svg/*.svg')
+
+const requireAll = (requireContext) => requireContext.keys().map(requireContext)
+requireAll(req)
+
+export default SvgIcon
diff --git a/src/libs/icons/svg/404.svg b/src/libs/icons/svg/404.svg
new file mode 100644
index 0000000..6df5019
--- /dev/null
+++ b/src/libs/icons/svg/404.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/borrow.svg b/src/libs/icons/svg/borrow.svg
new file mode 100644
index 0000000..81491d4
--- /dev/null
+++ b/src/libs/icons/svg/borrow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/bug.svg b/src/libs/icons/svg/bug.svg
new file mode 100644
index 0000000..05a150d
--- /dev/null
+++ b/src/libs/icons/svg/bug.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/build.svg b/src/libs/icons/svg/build.svg
new file mode 100644
index 0000000..97c4688
--- /dev/null
+++ b/src/libs/icons/svg/build.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/button.svg b/src/libs/icons/svg/button.svg
new file mode 100644
index 0000000..904fddc
--- /dev/null
+++ b/src/libs/icons/svg/button.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/cascader.svg b/src/libs/icons/svg/cascader.svg
new file mode 100644
index 0000000..e256024
--- /dev/null
+++ b/src/libs/icons/svg/cascader.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/chart.svg b/src/libs/icons/svg/chart.svg
new file mode 100644
index 0000000..27728fb
--- /dev/null
+++ b/src/libs/icons/svg/chart.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/checkbox.svg b/src/libs/icons/svg/checkbox.svg
new file mode 100644
index 0000000..013fd3a
--- /dev/null
+++ b/src/libs/icons/svg/checkbox.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/clipboard.svg b/src/libs/icons/svg/clipboard.svg
new file mode 100644
index 0000000..90923ff
--- /dev/null
+++ b/src/libs/icons/svg/clipboard.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/code.svg b/src/libs/icons/svg/code.svg
new file mode 100644
index 0000000..5f9c5ab
--- /dev/null
+++ b/src/libs/icons/svg/code.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/color.svg b/src/libs/icons/svg/color.svg
new file mode 100644
index 0000000..44a81aa
--- /dev/null
+++ b/src/libs/icons/svg/color.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/compass.svg b/src/libs/icons/svg/compass.svg
new file mode 100644
index 0000000..701c845
--- /dev/null
+++ b/src/libs/icons/svg/compass.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/component.svg b/src/libs/icons/svg/component.svg
new file mode 100644
index 0000000..29c3458
--- /dev/null
+++ b/src/libs/icons/svg/component.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/dashboard.svg b/src/libs/icons/svg/dashboard.svg
new file mode 100644
index 0000000..5317d37
--- /dev/null
+++ b/src/libs/icons/svg/dashboard.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/date-range.svg b/src/libs/icons/svg/date-range.svg
new file mode 100644
index 0000000..fda571e
--- /dev/null
+++ b/src/libs/icons/svg/date-range.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/date.svg b/src/libs/icons/svg/date.svg
new file mode 100644
index 0000000..52dc73e
--- /dev/null
+++ b/src/libs/icons/svg/date.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/dict.svg b/src/libs/icons/svg/dict.svg
new file mode 100644
index 0000000..4849377
--- /dev/null
+++ b/src/libs/icons/svg/dict.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/documentation.svg b/src/libs/icons/svg/documentation.svg
new file mode 100644
index 0000000..7043122
--- /dev/null
+++ b/src/libs/icons/svg/documentation.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/download.svg b/src/libs/icons/svg/download.svg
new file mode 100644
index 0000000..c896951
--- /dev/null
+++ b/src/libs/icons/svg/download.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/drag.svg b/src/libs/icons/svg/drag.svg
new file mode 100644
index 0000000..4185d3c
--- /dev/null
+++ b/src/libs/icons/svg/drag.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/druid.svg b/src/libs/icons/svg/druid.svg
new file mode 100644
index 0000000..a2b4b4e
--- /dev/null
+++ b/src/libs/icons/svg/druid.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/edit.svg b/src/libs/icons/svg/edit.svg
new file mode 100644
index 0000000..d26101f
--- /dev/null
+++ b/src/libs/icons/svg/edit.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/education.svg b/src/libs/icons/svg/education.svg
new file mode 100644
index 0000000..7bfb01d
--- /dev/null
+++ b/src/libs/icons/svg/education.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/email.svg b/src/libs/icons/svg/email.svg
new file mode 100644
index 0000000..74d25e2
--- /dev/null
+++ b/src/libs/icons/svg/email.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/entrust.svg b/src/libs/icons/svg/entrust.svg
new file mode 100644
index 0000000..4f4ce41
--- /dev/null
+++ b/src/libs/icons/svg/entrust.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/example.svg b/src/libs/icons/svg/example.svg
new file mode 100644
index 0000000..46f42b5
--- /dev/null
+++ b/src/libs/icons/svg/example.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/excel.svg b/src/libs/icons/svg/excel.svg
new file mode 100644
index 0000000..74d97b8
--- /dev/null
+++ b/src/libs/icons/svg/excel.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/exit-fullscreen.svg b/src/libs/icons/svg/exit-fullscreen.svg
new file mode 100644
index 0000000..485c128
--- /dev/null
+++ b/src/libs/icons/svg/exit-fullscreen.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/eye-open.svg b/src/libs/icons/svg/eye-open.svg
new file mode 100644
index 0000000..88dcc98
--- /dev/null
+++ b/src/libs/icons/svg/eye-open.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/eye.svg b/src/libs/icons/svg/eye.svg
new file mode 100644
index 0000000..16ed2d8
--- /dev/null
+++ b/src/libs/icons/svg/eye.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/form.svg b/src/libs/icons/svg/form.svg
new file mode 100644
index 0000000..dcbaa18
--- /dev/null
+++ b/src/libs/icons/svg/form.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/fullscreen.svg b/src/libs/icons/svg/fullscreen.svg
new file mode 100644
index 0000000..0e86b6f
--- /dev/null
+++ b/src/libs/icons/svg/fullscreen.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/github.svg b/src/libs/icons/svg/github.svg
new file mode 100644
index 0000000..db0a0d4
--- /dev/null
+++ b/src/libs/icons/svg/github.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/go-out.svg b/src/libs/icons/svg/go-out.svg
new file mode 100644
index 0000000..d733ebe
--- /dev/null
+++ b/src/libs/icons/svg/go-out.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/guide.svg b/src/libs/icons/svg/guide.svg
new file mode 100644
index 0000000..b271001
--- /dev/null
+++ b/src/libs/icons/svg/guide.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/home.svg b/src/libs/icons/svg/home.svg
new file mode 100644
index 0000000..9515f19
--- /dev/null
+++ b/src/libs/icons/svg/home.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/horn.svg b/src/libs/icons/svg/horn.svg
new file mode 100644
index 0000000..f13708a
--- /dev/null
+++ b/src/libs/icons/svg/horn.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/icon.svg b/src/libs/icons/svg/icon.svg
new file mode 100644
index 0000000..82be8ee
--- /dev/null
+++ b/src/libs/icons/svg/icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/input.svg b/src/libs/icons/svg/input.svg
new file mode 100644
index 0000000..ab91381
--- /dev/null
+++ b/src/libs/icons/svg/input.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/inquiry.svg b/src/libs/icons/svg/inquiry.svg
new file mode 100644
index 0000000..43e2267
--- /dev/null
+++ b/src/libs/icons/svg/inquiry.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/international.svg b/src/libs/icons/svg/international.svg
new file mode 100644
index 0000000..e9b56ee
--- /dev/null
+++ b/src/libs/icons/svg/international.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/job.svg b/src/libs/icons/svg/job.svg
new file mode 100644
index 0000000..2a93a25
--- /dev/null
+++ b/src/libs/icons/svg/job.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/language.svg b/src/libs/icons/svg/language.svg
new file mode 100644
index 0000000..0082b57
--- /dev/null
+++ b/src/libs/icons/svg/language.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/like.svg b/src/libs/icons/svg/like.svg
new file mode 100644
index 0000000..707a30a
--- /dev/null
+++ b/src/libs/icons/svg/like.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/link.svg b/src/libs/icons/svg/link.svg
new file mode 100644
index 0000000..48197ba
--- /dev/null
+++ b/src/libs/icons/svg/link.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/list.svg b/src/libs/icons/svg/list.svg
new file mode 100644
index 0000000..20259ed
--- /dev/null
+++ b/src/libs/icons/svg/list.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/lock.svg b/src/libs/icons/svg/lock.svg
new file mode 100644
index 0000000..74fee54
--- /dev/null
+++ b/src/libs/icons/svg/lock.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/log.svg b/src/libs/icons/svg/log.svg
new file mode 100644
index 0000000..d879d33
--- /dev/null
+++ b/src/libs/icons/svg/log.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/logininfor.svg b/src/libs/icons/svg/logininfor.svg
new file mode 100644
index 0000000..267f844
--- /dev/null
+++ b/src/libs/icons/svg/logininfor.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/message.svg b/src/libs/icons/svg/message.svg
new file mode 100644
index 0000000..14ca817
--- /dev/null
+++ b/src/libs/icons/svg/message.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/money.svg b/src/libs/icons/svg/money.svg
new file mode 100644
index 0000000..c1580de
--- /dev/null
+++ b/src/libs/icons/svg/money.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/monitor.svg b/src/libs/icons/svg/monitor.svg
new file mode 100644
index 0000000..bc308cb
--- /dev/null
+++ b/src/libs/icons/svg/monitor.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/nested.svg b/src/libs/icons/svg/nested.svg
new file mode 100644
index 0000000..06713a8
--- /dev/null
+++ b/src/libs/icons/svg/nested.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/notice.svg b/src/libs/icons/svg/notice.svg
new file mode 100644
index 0000000..7969d03
--- /dev/null
+++ b/src/libs/icons/svg/notice.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/number.svg b/src/libs/icons/svg/number.svg
new file mode 100644
index 0000000..ad5ce9a
--- /dev/null
+++ b/src/libs/icons/svg/number.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/online.svg b/src/libs/icons/svg/online.svg
new file mode 100644
index 0000000..330a202
--- /dev/null
+++ b/src/libs/icons/svg/online.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/password.svg b/src/libs/icons/svg/password.svg
new file mode 100644
index 0000000..6c64def
--- /dev/null
+++ b/src/libs/icons/svg/password.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/pdf.svg b/src/libs/icons/svg/pdf.svg
new file mode 100644
index 0000000..957aa0c
--- /dev/null
+++ b/src/libs/icons/svg/pdf.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/people.svg b/src/libs/icons/svg/people.svg
new file mode 100644
index 0000000..2bd54ae
--- /dev/null
+++ b/src/libs/icons/svg/people.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/peoples.svg b/src/libs/icons/svg/peoples.svg
new file mode 100644
index 0000000..aab852e
--- /dev/null
+++ b/src/libs/icons/svg/peoples.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/phone.svg b/src/libs/icons/svg/phone.svg
new file mode 100644
index 0000000..ab8e8c4
--- /dev/null
+++ b/src/libs/icons/svg/phone.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/post.svg b/src/libs/icons/svg/post.svg
new file mode 100644
index 0000000..2922c61
--- /dev/null
+++ b/src/libs/icons/svg/post.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/put-in.svg b/src/libs/icons/svg/put-in.svg
new file mode 100644
index 0000000..60e4e58
--- /dev/null
+++ b/src/libs/icons/svg/put-in.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/qq.svg b/src/libs/icons/svg/qq.svg
new file mode 100644
index 0000000..ee13d4e
--- /dev/null
+++ b/src/libs/icons/svg/qq.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/question.svg b/src/libs/icons/svg/question.svg
new file mode 100644
index 0000000..cf75bd4
--- /dev/null
+++ b/src/libs/icons/svg/question.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/radio.svg b/src/libs/icons/svg/radio.svg
new file mode 100644
index 0000000..0cde345
--- /dev/null
+++ b/src/libs/icons/svg/radio.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/rate.svg b/src/libs/icons/svg/rate.svg
new file mode 100644
index 0000000..aa3b14d
--- /dev/null
+++ b/src/libs/icons/svg/rate.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/redis-list.svg b/src/libs/icons/svg/redis-list.svg
new file mode 100644
index 0000000..98a15b2
--- /dev/null
+++ b/src/libs/icons/svg/redis-list.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/redis.svg b/src/libs/icons/svg/redis.svg
new file mode 100644
index 0000000..2f1d62d
--- /dev/null
+++ b/src/libs/icons/svg/redis.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/report-form.svg b/src/libs/icons/svg/report-form.svg
new file mode 100644
index 0000000..206981e
--- /dev/null
+++ b/src/libs/icons/svg/report-form.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/row.svg b/src/libs/icons/svg/row.svg
new file mode 100644
index 0000000..0780992
--- /dev/null
+++ b/src/libs/icons/svg/row.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/search.svg b/src/libs/icons/svg/search.svg
new file mode 100644
index 0000000..84233dd
--- /dev/null
+++ b/src/libs/icons/svg/search.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/select.svg b/src/libs/icons/svg/select.svg
new file mode 100644
index 0000000..d628382
--- /dev/null
+++ b/src/libs/icons/svg/select.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/server.svg b/src/libs/icons/svg/server.svg
new file mode 100644
index 0000000..eb287e3
--- /dev/null
+++ b/src/libs/icons/svg/server.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/settings.svg b/src/libs/icons/svg/settings.svg
new file mode 100644
index 0000000..b93eb6b
--- /dev/null
+++ b/src/libs/icons/svg/settings.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/shopping.svg b/src/libs/icons/svg/shopping.svg
new file mode 100644
index 0000000..87513e7
--- /dev/null
+++ b/src/libs/icons/svg/shopping.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/size.svg b/src/libs/icons/svg/size.svg
new file mode 100644
index 0000000..ddb25b8
--- /dev/null
+++ b/src/libs/icons/svg/size.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/skill.svg b/src/libs/icons/svg/skill.svg
new file mode 100644
index 0000000..a3b7312
--- /dev/null
+++ b/src/libs/icons/svg/skill.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/slider.svg b/src/libs/icons/svg/slider.svg
new file mode 100644
index 0000000..fbe4f39
--- /dev/null
+++ b/src/libs/icons/svg/slider.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/star.svg b/src/libs/icons/svg/star.svg
new file mode 100644
index 0000000..6cf86e6
--- /dev/null
+++ b/src/libs/icons/svg/star.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/swagger.svg b/src/libs/icons/svg/swagger.svg
new file mode 100644
index 0000000..05d4e7b
--- /dev/null
+++ b/src/libs/icons/svg/swagger.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/switch.svg b/src/libs/icons/svg/switch.svg
new file mode 100644
index 0000000..0ba61e3
--- /dev/null
+++ b/src/libs/icons/svg/switch.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/synchronous.svg b/src/libs/icons/svg/synchronous.svg
new file mode 100644
index 0000000..f0b541b
--- /dev/null
+++ b/src/libs/icons/svg/synchronous.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/system.svg b/src/libs/icons/svg/system.svg
new file mode 100644
index 0000000..5992593
--- /dev/null
+++ b/src/libs/icons/svg/system.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/tab.svg b/src/libs/icons/svg/tab.svg
new file mode 100644
index 0000000..b4b48e4
--- /dev/null
+++ b/src/libs/icons/svg/tab.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/table.svg b/src/libs/icons/svg/table.svg
new file mode 100644
index 0000000..0e3dc9d
--- /dev/null
+++ b/src/libs/icons/svg/table.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/take-over.svg b/src/libs/icons/svg/take-over.svg
new file mode 100644
index 0000000..f7cff52
--- /dev/null
+++ b/src/libs/icons/svg/take-over.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/task.svg b/src/libs/icons/svg/task.svg
new file mode 100644
index 0000000..c7ade49
--- /dev/null
+++ b/src/libs/icons/svg/task.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/textarea.svg b/src/libs/icons/svg/textarea.svg
new file mode 100644
index 0000000..2709f29
--- /dev/null
+++ b/src/libs/icons/svg/textarea.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/theme.svg b/src/libs/icons/svg/theme.svg
new file mode 100644
index 0000000..5982a2f
--- /dev/null
+++ b/src/libs/icons/svg/theme.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/theme2.svg b/src/libs/icons/svg/theme2.svg
new file mode 100644
index 0000000..8d1c017
--- /dev/null
+++ b/src/libs/icons/svg/theme2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/time-range.svg b/src/libs/icons/svg/time-range.svg
new file mode 100644
index 0000000..13c1202
--- /dev/null
+++ b/src/libs/icons/svg/time-range.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/time.svg b/src/libs/icons/svg/time.svg
new file mode 100644
index 0000000..b376e32
--- /dev/null
+++ b/src/libs/icons/svg/time.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/todo.svg b/src/libs/icons/svg/todo.svg
new file mode 100644
index 0000000..c07e91b
--- /dev/null
+++ b/src/libs/icons/svg/todo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/tool.svg b/src/libs/icons/svg/tool.svg
new file mode 100644
index 0000000..48e0e35
--- /dev/null
+++ b/src/libs/icons/svg/tool.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/tree-table.svg b/src/libs/icons/svg/tree-table.svg
new file mode 100644
index 0000000..8aafdb8
--- /dev/null
+++ b/src/libs/icons/svg/tree-table.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/tree.svg b/src/libs/icons/svg/tree.svg
new file mode 100644
index 0000000..dd4b7dd
--- /dev/null
+++ b/src/libs/icons/svg/tree.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/update.svg b/src/libs/icons/svg/update.svg
new file mode 100644
index 0000000..d540e3a
--- /dev/null
+++ b/src/libs/icons/svg/update.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/upload.svg b/src/libs/icons/svg/upload.svg
new file mode 100644
index 0000000..bae49c0
--- /dev/null
+++ b/src/libs/icons/svg/upload.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/user.svg b/src/libs/icons/svg/user.svg
new file mode 100644
index 0000000..0ba0716
--- /dev/null
+++ b/src/libs/icons/svg/user.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/validCode.svg b/src/libs/icons/svg/validCode.svg
new file mode 100644
index 0000000..cfb1021
--- /dev/null
+++ b/src/libs/icons/svg/validCode.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/wechat.svg b/src/libs/icons/svg/wechat.svg
new file mode 100644
index 0000000..c586e55
--- /dev/null
+++ b/src/libs/icons/svg/wechat.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svg/zip.svg b/src/libs/icons/svg/zip.svg
new file mode 100644
index 0000000..f806fc4
--- /dev/null
+++ b/src/libs/icons/svg/zip.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/libs/icons/svgo.yml b/src/libs/icons/svgo.yml
new file mode 100644
index 0000000..d11906a
--- /dev/null
+++ b/src/libs/icons/svgo.yml
@@ -0,0 +1,22 @@
+# replace default config
+
+# multipass: true
+# full: true
+
+plugins:
+
+ # - name
+ #
+ # or:
+ # - name: false
+ # - name: true
+ #
+ # or:
+ # - name:
+ # param1: 1
+ # param2: 2
+
+- removeAttrs:
+ attrs:
+ - 'fill'
+ - 'fill-rule'
diff --git a/src/main.ts b/src/main.ts
new file mode 100644
index 0000000..7bed2b4
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,7 @@
+import "@/styles/tailwind/index.scss"
+import { createApp } from 'vue'
+import App from './App.vue'
+
+const app = createApp(App)
+
+app.mount('#app')
diff --git a/src/modules/admin/App.vue b/src/modules/admin/App.vue
new file mode 100644
index 0000000..49056ca
--- /dev/null
+++ b/src/modules/admin/App.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/api/login/index.ts b/src/modules/admin/api/login/index.ts
new file mode 100644
index 0000000..ec3be08
--- /dev/null
+++ b/src/modules/admin/api/login/index.ts
@@ -0,0 +1,38 @@
+import request from '@admin/utils/request'
+
+class requests {
+ static getCodeImg() {
+ return request({
+ url: '/captchaImage',
+ method: 'get'
+ })
+ }
+ static login(data) {
+ return request({
+ url: '/login',
+ method: 'post',
+ data: data
+ })
+ }
+ static getInfo(params?) {
+ return request({
+ url: `/getInfo`,
+ method: 'get',
+ params
+ })
+ }
+ static logout() {
+ return request({
+ url: '/logout',
+ method: 'post'
+ })
+ }
+ static getRouters() {
+ return request({
+ url: `/getRouters`,
+ method: 'get',
+ })
+ }
+}
+
+export default requests
diff --git a/src/modules/admin/api/monitor/job.ts b/src/modules/admin/api/monitor/job.ts
new file mode 100644
index 0000000..a228a4d
--- /dev/null
+++ b/src/modules/admin/api/monitor/job.ts
@@ -0,0 +1,101 @@
+import request from '@admin/utils/request'
+
+class requests {
+ // 查询定时任务调度列表
+ static listJob(query) {
+ return request({
+ url: '/monitor/job/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 查询定时任务调度详细
+ static getJob(jobId) {
+ return request({
+ url: '/monitor/job/' + jobId,
+ method: 'get'
+ })
+ }
+
+ // 新增定时任务调度
+ static addJob(data) {
+ return request({
+ url: '/monitor/job',
+ method: 'post',
+ data: data
+ })
+ }
+
+ // 修改定时任务调度
+ static updateJob(data) {
+ return request({
+ url: '/monitor/job',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 删除定时任务调度
+ static delJob(jobId) {
+ return request({
+ url: '/monitor/job/' + jobId,
+ method: 'delete'
+ })
+ }
+
+ // 任务状态修改
+ static changeJobStatus(jobId, status) {
+ const data = {
+ jobId,
+ status
+ }
+ return request({
+ url: '/monitor/job/changeStatus',
+ method: 'put',
+ data: data
+ })
+ }
+
+
+ // 定时任务立即执行一次
+ static runJob(jobId, jobGroup) {
+ const data = {
+ jobId,
+ jobGroup
+ }
+ return request({
+ url: '/monitor/job/run',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 查询调度日志列表
+ static listJobLog(query) {
+ return request({
+ url: '/monitor/jobLog/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 删除调度日志
+ static delJobLog(jobLogId) {
+ return request({
+ url: '/monitor/jobLog/' + jobLogId,
+ method: 'delete'
+ })
+ }
+
+ // 清空调度日志
+ static cleanJobLog() {
+ return request({
+ url: '/monitor/jobLog/clean',
+ method: 'delete'
+ })
+ }
+
+}
+
+export default requests
diff --git a/src/modules/admin/api/monitor/online.ts b/src/modules/admin/api/monitor/online.ts
new file mode 100644
index 0000000..10fc903
--- /dev/null
+++ b/src/modules/admin/api/monitor/online.ts
@@ -0,0 +1,23 @@
+import request from '@admin/utils/request'
+
+class requests {
+ // 查询在线用户列表
+ static list(query?: object) {
+ return request({
+ url: '/monitor/online/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 强退用户
+ static forceLogout(tokenId?: string | number) {
+ return request({
+ url: '/monitor/online/' + tokenId,
+ method: 'delete'
+ })
+ }
+
+}
+
+export default requests
diff --git a/src/modules/admin/api/public/index.ts b/src/modules/admin/api/public/index.ts
new file mode 100644
index 0000000..fade191
--- /dev/null
+++ b/src/modules/admin/api/public/index.ts
@@ -0,0 +1,14 @@
+import request from '@admin/utils/request'
+
+class requests {
+ /* 流程历史 */
+ static getFlowHistory(id: string | number) {
+ return request({
+ url: `/flowable/task/flowRecord?procInsId=${id}`,
+ method: 'get',
+ })
+ }
+}
+
+
+export default requests
diff --git a/src/modules/admin/api/system/dept.ts b/src/modules/admin/api/system/dept.ts
new file mode 100644
index 0000000..7ec44a3
--- /dev/null
+++ b/src/modules/admin/api/system/dept.ts
@@ -0,0 +1,56 @@
+import request from '@admin/utils/request'
+
+class requests {
+ // 查询部门列表
+ static listDept(query?: object): Promise {
+ return request({
+ url: '/system/dept/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 查询部门列表(排除节点)
+ static listDeptExcludeChild(deptId: number | string): Promise {
+ return request({
+ url: '/system/dept/list/exclude/' + deptId,
+ method: 'get'
+ })
+ }
+
+ // 查询部门详细
+ static getDept(deptId: number | string): Promise {
+ return request({
+ url: '/system/dept/detail/' + deptId,
+ method: 'get'
+ })
+ }
+
+ // 新增部门
+ static addDept(data: object): Promise {
+ return request({
+ url: '/system/dept',
+ method: 'post',
+ data: data
+ })
+ }
+
+ // 修改部门
+ static updateDept(data: object): Promise {
+ return request({
+ url: '/system/dept',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 删除部门
+ static delDept(deptId: number | string): Promise {
+ return request({
+ url: '/system/dept/' + deptId,
+ method: 'delete'
+ })
+ }
+}
+
+export default requests
diff --git a/src/modules/admin/api/system/dict.ts b/src/modules/admin/api/system/dict.ts
new file mode 100644
index 0000000..c54809b
--- /dev/null
+++ b/src/modules/admin/api/system/dict.ts
@@ -0,0 +1,116 @@
+import request from '@admin/utils/request'
+
+class requests {
+ // 查询字典类型列表
+ static listType(query) {
+ return request({
+ url: '/system/dict/type/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 查询字典类型详细
+ static getType(dictId) {
+ return request({
+ url: '/system/dict/type/' + dictId,
+ method: 'get'
+ })
+ }
+
+ // 新增字典类型
+ static addType(data) {
+ return request({
+ url: '/system/dict/type',
+ method: 'post',
+ data: data
+ })
+ }
+
+ // 修改字典类型
+ static updateType(data) {
+ return request({
+ url: '/system/dict/type',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 删除字典类型
+ static delType(dictId) {
+ return request({
+ url: '/system/dict/type/' + dictId,
+ method: 'delete'
+ })
+ }
+
+ // 刷新字典缓存
+ static refreshCache() {
+ return request({
+ url: '/system/dict/type/refreshCache',
+ method: 'delete'
+ })
+ }
+
+ // 获取字典选择框列表
+ static optionselect() {
+ return request({
+ url: '/system/dict/type/optionselect',
+ method: 'get'
+ })
+ }
+
+ /* 字典数据 */
+ // 查询字典数据列表
+ static listData(query) {
+ return request({
+ url: '/system/dict/data/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 查询字典数据详细
+ static getData(dictCode) {
+ return request({
+ url: '/system/dict/data/' + dictCode,
+ method: 'get'
+ })
+ }
+
+ // 根据字典类型查询字典数据信息
+ static getDicts(dictType) {
+ return request({
+ url: '/system/dict/data/type/' + dictType,
+ method: 'get'
+ })
+ }
+
+ // 新增字典数据
+ static addData(data) {
+ return request({
+ url: '/system/dict/data',
+ method: 'post',
+ data: data
+ })
+ }
+
+ // 修改字典数据
+ static updateData(data) {
+ return request({
+ url: '/system/dict/data',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 删除字典数据
+ static delData(dictCode) {
+ return request({
+ url: '/system/dict/data/' + dictCode,
+ method: 'delete'
+ })
+ }
+}
+
+export default requests
diff --git a/src/modules/admin/api/system/log.ts b/src/modules/admin/api/system/log.ts
new file mode 100644
index 0000000..ac1f55b
--- /dev/null
+++ b/src/modules/admin/api/system/log.ts
@@ -0,0 +1,64 @@
+import request from '@admin/utils/request'
+
+class requests {
+ // 查询操作日志列表
+ static operlist(query) {
+ return request({
+ url: '/monitor/operlog/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 删除操作日志
+ static delOperlog(operId) {
+ return request({
+ url: '/monitor/operlog/' + operId,
+ method: 'delete'
+ })
+ }
+
+ // 清空操作日志
+ static cleanOperlog() {
+ return request({
+ url: '/monitor/operlog/clean',
+ method: 'delete'
+ })
+ }
+
+ // 查询登录日志列表
+ static loginlist(query) {
+ return request({
+ url: '/monitor/logininfor/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 删除登录日志
+ static delLogininfor(infoId) {
+ return request({
+ url: '/monitor/logininfor/' + infoId,
+ method: 'delete'
+ })
+ }
+
+ // 解锁用户登录状态
+ static unlockLogininfor(userName) {
+ return request({
+ url: '/monitor/logininfor/unlock/' + userName,
+ method: 'get'
+ })
+ }
+
+ // 清空登录日志
+ static cleanLogininfor() {
+ return request({
+ url: '/monitor/logininfor/clean',
+ method: 'delete'
+ })
+ }
+
+}
+
+export default requests
diff --git a/src/modules/admin/api/system/menu.ts b/src/modules/admin/api/system/menu.ts
new file mode 100644
index 0000000..5989bd6
--- /dev/null
+++ b/src/modules/admin/api/system/menu.ts
@@ -0,0 +1,64 @@
+import request from '@admin/utils/request'
+
+class requests {
+ // 查询菜单列表
+ static listMenu(query?) {
+ return request({
+ url: '/system/menu/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 查询菜单详细
+ static getMenu(menuId) {
+ return request({
+ url: '/system/menu/' + menuId,
+ method: 'get'
+ })
+ }
+
+ // 查询菜单下拉树结构
+ static treeselect() {
+ return request({
+ url: '/system/menu/treeselect',
+ method: 'get'
+ })
+ }
+
+ // 根据角色ID查询菜单下拉树结构
+ static roleMenuTreeselect(roleId) {
+ return request({
+ url: '/system/menu/roleMenuTreeselect/' + roleId,
+ method: 'get'
+ })
+ }
+
+ // 新增菜单
+ static addMenu(data) {
+ return request({
+ url: '/system/menu',
+ method: 'post',
+ data: data
+ })
+ }
+
+ // 修改菜单
+ static updateMenu(data) {
+ return request({
+ url: '/system/menu',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 删除菜单
+ static delMenu(menuId) {
+ return request({
+ url: '/system/menu/' + menuId,
+ method: 'delete'
+ })
+ }
+}
+
+export default requests
diff --git a/src/modules/admin/api/system/post.ts b/src/modules/admin/api/system/post.ts
new file mode 100644
index 0000000..2c077ea
--- /dev/null
+++ b/src/modules/admin/api/system/post.ts
@@ -0,0 +1,48 @@
+import request from '@admin/utils/request'
+
+class requests {
+ // 查询岗位列表
+ static listPost(query: object) {
+ return request({
+ url: '/system/post/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 查询岗位详细
+ static getPost(postId: number) {
+ return request({
+ url: '/system/post/' + postId,
+ method: 'get'
+ })
+ }
+
+ // 新增岗位
+ static addPost(data: object) {
+ return request({
+ url: '/system/post',
+ method: 'post',
+ data: data
+ })
+ }
+
+ // 修改岗位
+ static updatePost(data: object) {
+ return request({
+ url: '/system/post',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 删除岗位
+ static delPost(postId: number) {
+ return request({
+ url: '/system/post/' + postId,
+ method: 'delete'
+ })
+ }
+}
+
+export default requests
diff --git a/src/modules/admin/api/system/profile.ts b/src/modules/admin/api/system/profile.ts
new file mode 100644
index 0000000..e0c6e26
--- /dev/null
+++ b/src/modules/admin/api/system/profile.ts
@@ -0,0 +1,43 @@
+import request from '@admin/utils/request'
+
+class requests {
+ // 查询用户个人信息
+ static getUserProfile() {
+ return request({
+ url: '/system/user/profile',
+ method: 'get'
+ })
+ }
+
+ // 修改用户个人信息
+ static updateUserProfile(data) {
+ return request({
+ url: '/system/user/profile',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 用户密码重置
+ static updateUserPwd(oldPassword, newPassword) {
+ const data = {
+ oldPassword,
+ newPassword
+ }
+ return request({
+ url: '/system/user/profile/updatePwd',
+ method: 'put',
+ params: data
+ })
+ }
+ // 用户头像上传
+ static uploadAvatar(data) {
+ return request({
+ url: '/system/user/profile/avatar',
+ method: 'post',
+ data: data
+ })
+ }
+}
+
+export default requests
diff --git a/src/modules/admin/api/system/role.ts b/src/modules/admin/api/system/role.ts
new file mode 100644
index 0000000..d8efc98
--- /dev/null
+++ b/src/modules/admin/api/system/role.ts
@@ -0,0 +1,123 @@
+import request from '@admin/utils/request'
+
+class requests {
+ // 查询角色列表
+ static listRole(query) {
+ return request({
+ url: '/system/role/list',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 查询角色详细
+ static getRole(roleId) {
+ return request({
+ url: '/system/role/' + roleId,
+ method: 'get'
+ })
+ }
+
+ // 新增角色
+ static addRole(data) {
+ return request({
+ url: '/system/role',
+ method: 'post',
+ data: data
+ })
+ }
+
+ // 修改角色
+ static updateRole(data) {
+ return request({
+ url: '/system/role',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 角色数据权限
+ static dataScope(data) {
+ return request({
+ url: '/system/role/dataScope',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 角色状态修改
+ static changeRoleStatus(roleId, status) {
+ const data = {
+ roleId,
+ status
+ }
+ return request({
+ url: '/system/role/changeStatus',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 删除角色
+ static delRole(roleId) {
+ return request({
+ url: '/system/role/' + roleId,
+ method: 'delete'
+ })
+ }
+
+ // 查询角色已授权用户列表
+ static allocatedUserList(query) {
+ return request({
+ url: '/system/role/authUser/allocatedList',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 查询角色未授权用户列表
+ static unallocatedUserList(query) {
+ return request({
+ url: '/system/role/authUser/unallocatedList',
+ method: 'get',
+ params: query
+ })
+ }
+
+ // 取消用户授权角色
+ static authUserCancel(data) {
+ return request({
+ url: '/system/role/authUser/cancel',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 批量取消用户授权角色
+ static authUserCancelAll(data) {
+ return request({
+ url: '/system/role/authUser/cancelAll',
+ method: 'put',
+ params: data
+ })
+ }
+
+ // 授权用户选择
+ static authUserSelectAll(data) {
+ return request({
+ url: '/system/role/authUser/selectAll',
+ method: 'put',
+ params: data
+ })
+ }
+
+ // 根据角色ID查询部门树结构
+ static deptTreeSelect(roleId) {
+ return request({
+ url: '/system/role/deptTree/' + roleId,
+ method: 'get'
+ })
+ }
+}
+
+export default requests
diff --git a/src/modules/admin/api/system/user.ts b/src/modules/admin/api/system/user.ts
new file mode 100644
index 0000000..273181e
--- /dev/null
+++ b/src/modules/admin/api/system/user.ts
@@ -0,0 +1,86 @@
+import request from '@admin/utils/request'
+import { Static } from 'vue'
+
+class requests {
+ static getUserList(params?) {
+ return request({
+ url: '/system/user/list',
+ method: 'get',
+ params
+ })
+ }
+ // 根据字典类型查询字典数据信息
+ static getDicts(type: string) {
+ return request({
+ url: '/system/dict/data/type/' + type,
+ method: 'get'
+ })
+ }
+ static getTreeData() {
+ return request({
+ url: '/system/user/deptTree',
+ method: 'get'
+ })
+ }
+ static getUserInfo(userId: string | number) {
+ return request({
+ url: '/system/user/' + userId,
+ method: 'get'
+ })
+ }
+ // 查询部门下拉树结构
+ static treeselect() {
+ return request({
+ url: '/system/dept/treeselect',
+ method: 'get'
+ })
+ }
+ // 新增用户
+ static add(data) {
+ console.log(data);
+ return request({
+ url: '/system/user',
+ method: 'post',
+ data
+ })
+ }
+
+ // 修改用户
+ static edit(data) {
+ return request({
+ url: '/system/user',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 删除用户
+ static delUser(userId) {
+ return request({
+ url: '/system/user/' + userId,
+ method: 'delete'
+ })
+ }
+
+ // 用户密码重置
+ static resetUserPwd(userId, password) {
+ const data = { userId, password }
+ return request({
+ url: '/system/user/resetPwd',
+ method: 'put',
+ data: data
+ })
+ }
+
+ // 用户状态修改
+ static changeUserStatus(userId, status) {
+ const data = { userId, status }
+ return request({
+ url: '/system/user/changeStatus',
+ method: 'put',
+ data: data
+ })
+ }
+}
+
+export default requests
diff --git a/src/modules/admin/api/tool/flowable/definition.ts b/src/modules/admin/api/tool/flowable/definition.ts
new file mode 100644
index 0000000..bca8bb0
--- /dev/null
+++ b/src/modules/admin/api/tool/flowable/definition.ts
@@ -0,0 +1,36 @@
+import request from '@admin/utils/request'
+
+class requests {
+ static getList(params) {
+ return request.request({
+ url: `/flowable/definition/list`,
+ method: "GET",
+ params
+ });
+ }
+ static flowDelete(id) {
+ return request.request({
+ url: `/flowable/definition/delete/${id}`,
+ method: "POST"
+ });
+ }
+ static flowUpdate(id) {
+ return request.request({
+ url: `/flowable/definition/update/${id}`,
+ method: "POST"
+ });
+ }
+ static flowReadImage(id) {
+ return request.request({
+ url: `/flowable/definition/readImage/${id}`,
+ method: "GET"
+ });
+ }
+ static(id) {
+ return request.request({
+ url: `/flowable/definition/readXml/${id}`,
+ method: "GET"
+ });
+ }
+}
+export default requests;
\ No newline at end of file
diff --git a/src/modules/admin/api/tool/flowable/editor.ts b/src/modules/admin/api/tool/flowable/editor.ts
new file mode 100644
index 0000000..ae7c3cd
--- /dev/null
+++ b/src/modules/admin/api/tool/flowable/editor.ts
@@ -0,0 +1,58 @@
+import request from '@admin/utils/request'
+
+class requests {
+ static getList(params) {
+ return request.request({
+ url: `/flowable/editor/list`,
+ method: "GET",
+ params
+ });
+ }
+ static getFlowXML(id) {
+ return request.request({
+ url: `/flowable/editor/detail/${id}`,
+ method: "GET"
+ });
+ }
+ static editorAdd(data) {
+ return request.request({
+ url: `/flowable/editor/add`,
+ method: "POST",
+ data
+ });
+ }
+ static editorUpdate(data) {
+ return request.request({
+ url: `/flowable/editor/update`,
+ method: "POST",
+ data
+ });
+ }
+ static editorDeploy(id) {
+ return request.request({
+ url: `/flowable/editor/deploy/${id}`,
+ method: "POST"
+ });
+ }
+ static editorDelete(id) {
+ return request.request({
+ url: `/flowable/editor/delete/${id}`,
+ method: "POST"
+ });
+ }
+ static getRoleList(params) {
+ return request.request({
+ url: `/flowable/editor/roleList`,
+ method: "GET",
+ params
+ });
+ }
+ static getUserList(params) {
+ return request.request({
+ url: `/flowable/editor/userList`,
+ method: "GET",
+ params
+ });
+ }
+}
+export default requests;
\ No newline at end of file
diff --git a/src/modules/admin/api/tool/flowable/node.ts b/src/modules/admin/api/tool/flowable/node.ts
new file mode 100644
index 0000000..3eca6fe
--- /dev/null
+++ b/src/modules/admin/api/tool/flowable/node.ts
@@ -0,0 +1,67 @@
+import request from '@admin/utils/request'
+
+class requests {
+ static getList(params) {
+ return request.request({
+ url: `/flowable/node/user/list`,
+ method: "GET",
+ params
+ });
+ }
+ static getFlowList(params) {
+ return request.request({
+ url: `/flowable/node/user/list/flow`,
+ method: "GET",
+ params
+ });
+ }
+ static getFlowNodeList(id) {
+ return request.request({
+ url: `/flowable/node/user/list/node/${id}`,
+ method: "GET"
+ });
+ }
+ static getNodeUserDetail(id) {
+ return request.request({
+ url: `/flowable/node/user/detail/${id}`,
+ method: "GET"
+ });
+ }
+ static nodeUserDelete(id) {
+ return request.request({
+ url: `/flowable/node/user/delete/${id}`,
+ method: "POST"
+ });
+ }
+ static nodeUserUpdate(data) {
+ return request.request({
+ url: `/flowable/node/user/update`,
+ method: "POST",
+ data
+ });
+ }
+ static nodeUserAdd(data) {
+ return request.request({
+ url: `/flowable/node/user/add`,
+ method: "POST",
+ data
+ });
+ }
+
+
+ static setVersion(params) {
+ return request.request({
+ url: `/flowable/node/user/setVersion`,
+ method: "POST",
+ params
+ });
+ }
+ static copyVersion(params) {
+ return request.request({
+ url: `/flowable/node/user/copyVersion`,
+ method: "POST",
+ params
+ });
+ }
+}
+export default requests;
\ No newline at end of file
diff --git a/src/modules/admin/assets/403_images/403.png b/src/modules/admin/assets/403_images/403.png
new file mode 100644
index 0000000..314caa6
Binary files /dev/null and b/src/modules/admin/assets/403_images/403.png differ
diff --git a/src/modules/admin/assets/403_images/403_cloud.png b/src/modules/admin/assets/403_images/403_cloud.png
new file mode 100644
index 0000000..c6281d0
Binary files /dev/null and b/src/modules/admin/assets/403_images/403_cloud.png differ
diff --git a/src/modules/admin/assets/404_images/404.png b/src/modules/admin/assets/404_images/404.png
new file mode 100644
index 0000000..3d8e230
Binary files /dev/null and b/src/modules/admin/assets/404_images/404.png differ
diff --git a/src/modules/admin/assets/404_images/404_bg.png b/src/modules/admin/assets/404_images/404_bg.png
new file mode 100644
index 0000000..1d34d79
Binary files /dev/null and b/src/modules/admin/assets/404_images/404_bg.png differ
diff --git a/src/modules/admin/assets/404_images/404_cloud.png b/src/modules/admin/assets/404_images/404_cloud.png
new file mode 100644
index 0000000..c6281d0
Binary files /dev/null and b/src/modules/admin/assets/404_images/404_cloud.png differ
diff --git a/src/modules/admin/assets/iconfont/iconfont.css b/src/modules/admin/assets/iconfont/iconfont.css
new file mode 100644
index 0000000..57ee5f0
--- /dev/null
+++ b/src/modules/admin/assets/iconfont/iconfont.css
@@ -0,0 +1,115 @@
+@font-face {
+ font-family: "iconfont"; /* Project id 3641732 */
+ src: url('./iconfont.woff2?t=1663216428515') format('woff2'),
+ url('./iconfont.woff?t=1663216428515') format('woff'),
+ url('./iconfont.ttf?t=1663216428515') format('truetype');
+}
+
+.iconfont {
+ font-family: "iconfont" !important;
+ font-size: 16px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-yin:before {
+ content: "\e6a0";
+}
+
+.icon-dabaoyu:before {
+ content: "\e6a7";
+}
+
+.icon-shuaxin1:before {
+ content: "\e627";
+}
+
+.icon-shuaxin:before {
+ content: "\e629";
+}
+
+.icon-duoyun-2-copy:before {
+ content: "\e68d";
+}
+
+.icon-duoyun-1:before {
+ content: "\e679";
+}
+
+.icon-daxue:before {
+ content: "\e67a";
+}
+
+.icon-dayu:before {
+ content: "\e67b";
+}
+
+.icon-feng:before {
+ content: "\e67c";
+}
+
+.icon-duoyun-3:before {
+ content: "\e67d";
+}
+
+.icon-duoyun-2:before {
+ content: "\e67e";
+}
+
+.icon-leiyujiaojia:before {
+ content: "\e67f";
+}
+
+.icon-duoyun:before {
+ content: "\e680";
+}
+
+.icon-zhongyu:before {
+ content: "\e681";
+}
+
+.icon-wu:before {
+ content: "\e682";
+}
+
+.icon-xiaoyu:before {
+ content: "\e683";
+}
+
+.icon-xiaoxue:before {
+ content: "\e684";
+}
+
+.icon-shandian:before {
+ content: "\e685";
+}
+
+.icon-xue:before {
+ content: "\e686";
+}
+
+.icon-zhongxue:before {
+ content: "\e687";
+}
+
+.icon-yangchen:before {
+ content: "\e688";
+}
+
+.icon-yueliang:before {
+ content: "\e689";
+}
+
+.icon-yujiaxue:before {
+ content: "\e68a";
+}
+
+.icon-qing:before {
+ content: "\e68b";
+}
+
+.icon-mai:before {
+ content: "\e68c";
+}
+
diff --git a/src/modules/admin/assets/iconfont/iconfont.js b/src/modules/admin/assets/iconfont/iconfont.js
new file mode 100644
index 0000000..f94a118
--- /dev/null
+++ b/src/modules/admin/assets/iconfont/iconfont.js
@@ -0,0 +1 @@
+window._iconfont_svg_string_3641732=' ',function(l){var c=(c=document.getElementsByTagName("script"))[c.length-1],s=c.getAttribute("data-injectcss"),c=c.getAttribute("data-disable-injectsvg");if(!c){var a,t,i,h,o,e=function(c,s){s.parentNode.insertBefore(c,s)};if(s&&!l.__iconfont__svg__cssinject__){l.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}a=function(){var c,s=document.createElement("div");s.innerHTML=l._iconfont_svg_string_3641732,(s=s.getElementsByTagName("svg")[0])&&(s.setAttribute("aria-hidden","true"),s.style.position="absolute",s.style.width=0,s.style.height=0,s.style.overflow="hidden",s=s,(c=document.body).firstChild?e(s,c.firstChild):c.appendChild(s))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(a,0):(t=function(){document.removeEventListener("DOMContentLoaded",t,!1),a()},document.addEventListener("DOMContentLoaded",t,!1)):document.attachEvent&&(i=a,h=l.document,o=!1,p(),h.onreadystatechange=function(){"complete"==h.readyState&&(h.onreadystatechange=null,d())})}function d(){o||(o=!0,i())}function p(){try{h.documentElement.doScroll("left")}catch(c){return void setTimeout(p,50)}d()}}(window);
\ No newline at end of file
diff --git a/src/modules/admin/assets/iconfont/iconfont.json b/src/modules/admin/assets/iconfont/iconfont.json
new file mode 100644
index 0000000..55b9a00
--- /dev/null
+++ b/src/modules/admin/assets/iconfont/iconfont.json
@@ -0,0 +1,184 @@
+{
+ "id": "3641732",
+ "name": "weather",
+ "font_family": "iconfont",
+ "css_prefix_text": "icon-",
+ "description": "",
+ "glyphs": [
+ {
+ "icon_id": "28557556",
+ "name": "阴",
+ "font_class": "yin",
+ "unicode": "e6a0",
+ "unicode_decimal": 59040
+ },
+ {
+ "icon_id": "28557770",
+ "name": "大暴雨",
+ "font_class": "dabaoyu",
+ "unicode": "e6a7",
+ "unicode_decimal": 59047
+ },
+ {
+ "icon_id": "7724796",
+ "name": "刷新",
+ "font_class": "shuaxin1",
+ "unicode": "e627",
+ "unicode_decimal": 58919
+ },
+ {
+ "icon_id": "6999224",
+ "name": "刷新",
+ "font_class": "shuaxin",
+ "unicode": "e629",
+ "unicode_decimal": 58921
+ },
+ {
+ "icon_id": "31772217",
+ "name": "多云-2-copy",
+ "font_class": "duoyun-2-copy",
+ "unicode": "e68d",
+ "unicode_decimal": 59021
+ },
+ {
+ "icon_id": "29265274",
+ "name": "多云-1",
+ "font_class": "duoyun-1",
+ "unicode": "e679",
+ "unicode_decimal": 59001
+ },
+ {
+ "icon_id": "29265275",
+ "name": "大雪",
+ "font_class": "daxue",
+ "unicode": "e67a",
+ "unicode_decimal": 59002
+ },
+ {
+ "icon_id": "29265276",
+ "name": "大雨",
+ "font_class": "dayu",
+ "unicode": "e67b",
+ "unicode_decimal": 59003
+ },
+ {
+ "icon_id": "29265277",
+ "name": "风",
+ "font_class": "feng",
+ "unicode": "e67c",
+ "unicode_decimal": 59004
+ },
+ {
+ "icon_id": "29265278",
+ "name": "多云-3",
+ "font_class": "duoyun-3",
+ "unicode": "e67d",
+ "unicode_decimal": 59005
+ },
+ {
+ "icon_id": "29265279",
+ "name": "多云-2",
+ "font_class": "duoyun-2",
+ "unicode": "e67e",
+ "unicode_decimal": 59006
+ },
+ {
+ "icon_id": "29265280",
+ "name": "雷雨交加",
+ "font_class": "leiyujiaojia",
+ "unicode": "e67f",
+ "unicode_decimal": 59007
+ },
+ {
+ "icon_id": "29265281",
+ "name": "多云",
+ "font_class": "duoyun",
+ "unicode": "e680",
+ "unicode_decimal": 59008
+ },
+ {
+ "icon_id": "29265282",
+ "name": "中雨",
+ "font_class": "zhongyu",
+ "unicode": "e681",
+ "unicode_decimal": 59009
+ },
+ {
+ "icon_id": "29265283",
+ "name": "雾",
+ "font_class": "wu",
+ "unicode": "e682",
+ "unicode_decimal": 59010
+ },
+ {
+ "icon_id": "29265284",
+ "name": "小雨",
+ "font_class": "xiaoyu",
+ "unicode": "e683",
+ "unicode_decimal": 59011
+ },
+ {
+ "icon_id": "29265285",
+ "name": "小雪",
+ "font_class": "xiaoxue",
+ "unicode": "e684",
+ "unicode_decimal": 59012
+ },
+ {
+ "icon_id": "29265286",
+ "name": "闪电",
+ "font_class": "shandian",
+ "unicode": "e685",
+ "unicode_decimal": 59013
+ },
+ {
+ "icon_id": "29265287",
+ "name": "雪",
+ "font_class": "xue",
+ "unicode": "e686",
+ "unicode_decimal": 59014
+ },
+ {
+ "icon_id": "29265288",
+ "name": "中雪",
+ "font_class": "zhongxue",
+ "unicode": "e687",
+ "unicode_decimal": 59015
+ },
+ {
+ "icon_id": "29265289",
+ "name": "扬尘",
+ "font_class": "yangchen",
+ "unicode": "e688",
+ "unicode_decimal": 59016
+ },
+ {
+ "icon_id": "29265290",
+ "name": "月亮",
+ "font_class": "yueliang",
+ "unicode": "e689",
+ "unicode_decimal": 59017
+ },
+ {
+ "icon_id": "29265291",
+ "name": "雨夹雪",
+ "font_class": "yujiaxue",
+ "unicode": "e68a",
+ "unicode_decimal": 59018
+ },
+ {
+ "icon_id": "29265292",
+ "name": "晴",
+ "font_class": "qing",
+ "unicode": "e68b",
+ "unicode_decimal": 59019
+ },
+ {
+ "icon_id": "29265293",
+ "name": "霾",
+ "font_class": "mai",
+ "unicode": "e68c",
+ "unicode_decimal": 59020
+ }
+ ]
+}
diff --git a/src/modules/admin/assets/iconfont/iconfont.ttf b/src/modules/admin/assets/iconfont/iconfont.ttf
new file mode 100644
index 0000000..6c6aaf8
Binary files /dev/null and b/src/modules/admin/assets/iconfont/iconfont.ttf differ
diff --git a/src/modules/admin/assets/iconfont/iconfont.woff b/src/modules/admin/assets/iconfont/iconfont.woff
new file mode 100644
index 0000000..e0ca58d
Binary files /dev/null and b/src/modules/admin/assets/iconfont/iconfont.woff differ
diff --git a/src/modules/admin/assets/iconfont/iconfont.woff2 b/src/modules/admin/assets/iconfont/iconfont.woff2
new file mode 100644
index 0000000..4ed68d8
Binary files /dev/null and b/src/modules/admin/assets/iconfont/iconfont.woff2 differ
diff --git a/src/modules/admin/assets/image/avatar.png b/src/modules/admin/assets/image/avatar.png
new file mode 100644
index 0000000..30a870a
Binary files /dev/null and b/src/modules/admin/assets/image/avatar.png differ
diff --git a/src/modules/admin/assets/image/log.png b/src/modules/admin/assets/image/log.png
new file mode 100644
index 0000000..1f20ee0
Binary files /dev/null and b/src/modules/admin/assets/image/log.png differ
diff --git a/src/modules/admin/assets/image/login/side-logo.png b/src/modules/admin/assets/image/login/side-logo.png
new file mode 100644
index 0000000..4b19fa6
Binary files /dev/null and b/src/modules/admin/assets/image/login/side-logo.png differ
diff --git a/src/modules/admin/assets/image/public/d_loading.gif b/src/modules/admin/assets/image/public/d_loading.gif
new file mode 100644
index 0000000..b77f546
Binary files /dev/null and b/src/modules/admin/assets/image/public/d_loading.gif differ
diff --git a/src/modules/admin/assets/image/public/d_noData.png b/src/modules/admin/assets/image/public/d_noData.png
new file mode 100644
index 0000000..34568cd
Binary files /dev/null and b/src/modules/admin/assets/image/public/d_noData.png differ
diff --git a/src/modules/admin/assets/image/public/loading.gif b/src/modules/admin/assets/image/public/loading.gif
new file mode 100644
index 0000000..ffa121e
Binary files /dev/null and b/src/modules/admin/assets/image/public/loading.gif differ
diff --git "a/src/modules/admin/assets/image/public/\346\225\254\350\257\267\346\234\237\345\276\205.png" "b/src/modules/admin/assets/image/public/\346\225\254\350\257\267\346\234\237\345\276\205.png"
new file mode 100644
index 0000000..3270d25
Binary files /dev/null and "b/src/modules/admin/assets/image/public/\346\225\254\350\257\267\346\234\237\345\276\205.png" differ
diff --git "a/src/modules/admin/assets/svg/\346\225\254\350\257\267\346\234\237\345\276\205.svg" "b/src/modules/admin/assets/svg/\346\225\254\350\257\267\346\234\237\345\276\205.svg"
new file mode 100644
index 0000000..8642708
--- /dev/null
+++ "b/src/modules/admin/assets/svg/\346\225\254\350\257\267\346\234\237\345\276\205.svg"
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Global/common/IconSelect/iconList.vue b/src/modules/admin/components/Global/common/IconSelect/iconList.vue
new file mode 100644
index 0000000..6bc5b5a
--- /dev/null
+++ b/src/modules/admin/components/Global/common/IconSelect/iconList.vue
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Global/common/IconSelect/index.vue b/src/modules/admin/components/Global/common/IconSelect/index.vue
new file mode 100644
index 0000000..78e9ab6
--- /dev/null
+++ b/src/modules/admin/components/Global/common/IconSelect/index.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Global/common/datePicker/dDatePicker.vue b/src/modules/admin/components/Global/common/datePicker/dDatePicker.vue
new file mode 100644
index 0000000..8adb78c
--- /dev/null
+++ b/src/modules/admin/components/Global/common/datePicker/dDatePicker.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Global/common/table/dTable.vue b/src/modules/admin/components/Global/common/table/dTable.vue
new file mode 100644
index 0000000..3c8ff94
--- /dev/null
+++ b/src/modules/admin/components/Global/common/table/dTable.vue
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
暂无数据
+
+
+
+
+
+
+
+
+ {{ (searchInfo[pageKey]-1)*searchInfo[sizeKey] + scope.$index + 1 }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Global/common/upload/dUpload.vue b/src/modules/admin/components/Global/common/upload/dUpload.vue
new file mode 100644
index 0000000..2845a42
--- /dev/null
+++ b/src/modules/admin/components/Global/common/upload/dUpload.vue
@@ -0,0 +1,210 @@
+
+
+
+
+ 点击上传
+
+
+ 无附件
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Global/content/WangEdior/index.vue b/src/modules/admin/components/Global/content/WangEdior/index.vue
new file mode 100644
index 0000000..27dac69
--- /dev/null
+++ b/src/modules/admin/components/Global/content/WangEdior/index.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Global/content/approve/dApprove.vue b/src/modules/admin/components/Global/content/approve/dApprove.vue
new file mode 100644
index 0000000..6df3938
--- /dev/null
+++ b/src/modules/admin/components/Global/content/approve/dApprove.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+ 通过
+ 驳回
+
+
+
+
+
+
+
+ {{name}}
+
+
+
+
+
diff --git a/src/modules/admin/components/Global/content/flowHistory/index.vue b/src/modules/admin/components/Global/content/flowHistory/index.vue
new file mode 100644
index 0000000..ceccab0
--- /dev/null
+++ b/src/modules/admin/components/Global/content/flowHistory/index.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
流程历史
+
+
+
+
+
+
+
+
+
流程图
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Global/content/selectUser/dSelectUser.vue b/src/modules/admin/components/Global/content/selectUser/dSelectUser.vue
new file mode 100644
index 0000000..c2c990e
--- /dev/null
+++ b/src/modules/admin/components/Global/content/selectUser/dSelectUser.vue
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Global/content/selectUser/selectUser.vue b/src/modules/admin/components/Global/content/selectUser/selectUser.vue
new file mode 100644
index 0000000..f150202
--- /dev/null
+++ b/src/modules/admin/components/Global/content/selectUser/selectUser.vue
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 姓名:
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ getSelectedStatus(row) ? '已选择' : '未选择' }}
+
+
+
+
+
+
+
+
+
+ 可选多个成员
+ 选择单个成员
+ 可选{{limit}}名成员
+
+
确认
+
清空
+
选择全部
+
+
+
+ {{ item.name }}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Global/index.ts b/src/modules/admin/components/Global/index.ts
new file mode 100644
index 0000000..4acddad
--- /dev/null
+++ b/src/modules/admin/components/Global/index.ts
@@ -0,0 +1,18 @@
+import { App } from 'vue'
+import dtable from './common/table/dTable.vue'
+import dDatePicker from './common/datePicker/dDatePicker.vue'
+import dIconSelect from './common/IconSelect/index.vue'
+import dUpload from './common/upload/dUpload.vue'
+import dSelectUser from './content/selectUser/dSelectUser.vue'
+import flowHistory from './content/flowHistory/index.vue'
+import dApprove from './content/approve/dApprove.vue'
+
+export default (app: App ) => {
+ app.component('dTable', dtable)
+ app.component('dDatePicker', dDatePicker)
+ app.component('dIconSelect', dIconSelect)
+ app.component('dSelectUser', dSelectUser)
+ app.component('flowHistory', flowHistory)
+ app.component('dUpload', dUpload)
+ app.component('dApprove', dApprove)
+}
\ No newline at end of file
diff --git a/src/modules/admin/components/Layout/PageWrapLayout/index.scss b/src/modules/admin/components/Layout/PageWrapLayout/index.scss
new file mode 100644
index 0000000..95810a3
--- /dev/null
+++ b/src/modules/admin/components/Layout/PageWrapLayout/index.scss
@@ -0,0 +1,18 @@
+.m-container-layout {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ padding: 10px 12px;
+ box-sizing: border-box;
+ .m-container-layout-inner {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+ background: white;
+ padding: 20px;
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+ }
+}
diff --git a/src/modules/admin/components/Layout/PageWrapLayout/index.vue b/src/modules/admin/components/Layout/PageWrapLayout/index.vue
new file mode 100644
index 0000000..eb8f256
--- /dev/null
+++ b/src/modules/admin/components/Layout/PageWrapLayout/index.vue
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Layout/SwitchDark/index.vue b/src/modules/admin/components/Layout/SwitchDark/index.vue
new file mode 100644
index 0000000..cc20c1a
--- /dev/null
+++ b/src/modules/admin/components/Layout/SwitchDark/index.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
diff --git a/src/modules/admin/components/Layout/Theme/index.vue b/src/modules/admin/components/Layout/Theme/index.vue
new file mode 100644
index 0000000..669e62a
--- /dev/null
+++ b/src/modules/admin/components/Layout/Theme/index.vue
@@ -0,0 +1,219 @@
+
+
+
+
+
+ 导航栏布局
+ changeSwitch('mode',val)"
+ >
+
+
+
+
+
+
+ 主题颜色
+
+
+
+ 暗黑模式
+
+
+
+ 灰色模式
+ changeGrayWeak('gray',val)" />
+
+
+ 色弱模式
+ changeGrayWeak('weak',val)" />
+
+
+ 标签栏
+ changeSwitch('showTag',val)" />
+
+
+ 侧边栏 Logo
+ changeSwitch('showLogo',val)" />
+
+
+ 保持一个子菜单的展开
+ changeSwitch('uniqueOpened',val)" />
+
+
+ 固定header
+ changeSwitch('fixedHeader',val)" />
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Crontab/day.vue b/src/modules/admin/components/Ruoyi/Crontab/day.vue
new file mode 100644
index 0000000..956be3a
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Crontab/day.vue
@@ -0,0 +1,176 @@
+
+
+
+
+ 日,允许的通配符[, - * ? / L W]
+
+
+
+
+
+ 不指定
+
+
+
+
+
+ 周期从
+ -
+ 日
+
+
+
+
+
+ 从
+ 号开始,每
+ 日执行一次
+
+
+
+
+
+ 每月
+ 号最近的那个工作日
+
+
+
+
+
+ 本月最后一天
+
+
+
+
+
+ 指定
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Crontab/hour.vue b/src/modules/admin/components/Ruoyi/Crontab/hour.vue
new file mode 100644
index 0000000..7b03646
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Crontab/hour.vue
@@ -0,0 +1,128 @@
+
+
+
+
+ 小时,允许的通配符[, - * /]
+
+
+
+
+
+ 周期从
+ -
+ 时
+
+
+
+
+
+ 从
+ 时开始,每
+ 小时执行一次
+
+
+
+
+
+ 指定
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Crontab/index.vue b/src/modules/admin/components/Ruoyi/Crontab/index.vue
new file mode 100644
index 0000000..0f9638f
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Crontab/index.vue
@@ -0,0 +1,292 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 确定
+ 重置
+ 取消
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Crontab/min.vue b/src/modules/admin/components/Ruoyi/Crontab/min.vue
new file mode 100644
index 0000000..0f1c20e
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Crontab/min.vue
@@ -0,0 +1,128 @@
+
+
+
+
+ 分钟,允许的通配符[, - * /]
+
+
+
+
+
+ 周期从
+ -
+ 分钟
+
+
+
+
+
+ 从
+ 分钟开始, 每
+ 分钟执行一次
+
+
+
+
+
+ 指定
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Crontab/month.vue b/src/modules/admin/components/Ruoyi/Crontab/month.vue
new file mode 100644
index 0000000..093ae57
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Crontab/month.vue
@@ -0,0 +1,142 @@
+
+
+
+
+ 月,允许的通配符[, - * /]
+
+
+
+
+
+ 周期从
+ -
+ 月
+
+
+
+
+
+ 从
+ 月开始,每
+ 月月执行一次
+
+
+
+
+
+ 指定
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Crontab/result.vue b/src/modules/admin/components/Ruoyi/Crontab/result.vue
new file mode 100644
index 0000000..6235049
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Crontab/result.vue
@@ -0,0 +1,541 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Crontab/second.vue b/src/modules/admin/components/Ruoyi/Crontab/second.vue
new file mode 100644
index 0000000..0436fbf
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Crontab/second.vue
@@ -0,0 +1,130 @@
+
+
+
+
+ 秒,允许的通配符[, - * /]
+
+
+
+
+
+ 周期从
+ -
+ 秒
+
+
+
+
+
+ 从
+ 秒开始,每
+ 秒执行一次
+
+
+
+
+
+ 指定
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Crontab/week.vue b/src/modules/admin/components/Ruoyi/Crontab/week.vue
new file mode 100644
index 0000000..17f327e
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Crontab/week.vue
@@ -0,0 +1,200 @@
+
+
+
+
+ 周,允许的通配符[, - * ? / L #]
+
+
+
+
+
+ 不指定
+
+
+
+
+
+ 周期从
+
+ {{item.value}}
+
+ -
+
+ {{item.value}}
+
+
+
+
+
+
+ 第
+ 周的
+
+
+
+
+
+
+
+
+ 本月最后一个
+
+
+
+
+
+
+
+
+ 指定
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Crontab/year.vue b/src/modules/admin/components/Ruoyi/Crontab/year.vue
new file mode 100644
index 0000000..3119d67
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Crontab/year.vue
@@ -0,0 +1,150 @@
+
+
+
+
+ 不填,允许的通配符[, - * /]
+
+
+
+
+
+ 每年
+
+
+
+
+
+ 周期从
+ -
+
+
+
+
+
+
+ 从
+ 年开始,每
+ 年执行一次
+
+
+
+
+
+
+ 指定
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/DictTag.vue b/src/modules/admin/components/Ruoyi/DictTag.vue
new file mode 100644
index 0000000..d6b1dc3
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/DictTag.vue
@@ -0,0 +1,83 @@
+
+
+
+
+ {{ item.label + " " }}
+ {{ item.label + " " }}
+
+
+
+ {{ unmatchArray.join(',') || '' }}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Process/BpmData.js b/src/modules/admin/components/Ruoyi/Process/BpmData.js
new file mode 100644
index 0000000..672ca44
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/BpmData.js
@@ -0,0 +1,68 @@
+/**
+ * 存储流程设计相关参数
+ */
+export default class BpmData {
+ constructor() {
+ this.controls = [] // 设计器控件
+ this.init()
+ }
+
+ init() {
+ this.controls = [
+ {
+ action: 'create.start-event',
+ title: '开始'
+ },
+ {
+ action: 'create.intermediate-event',
+ title: '中间'
+ },
+ {
+ action: 'create.end-event',
+ title: '结束'
+ },
+ {
+ action: 'create.exclusive-gateway',
+ title: '网关'
+ },
+ {
+ action: 'create.task',
+ title: '任务'
+ },
+ {
+ action: 'create.user-task',
+ title: '用户任务'
+ },
+ {
+ action: 'create.user-sign-task',
+ title: '会签任务'
+ },
+ {
+ action: 'create.subprocess-expanded',
+ title: '子流程'
+ },
+ {
+ action: 'create.data-object',
+ title: '数据对象'
+ },
+ {
+ action: 'create.data-store',
+ title: '数据存储'
+ },
+ {
+ action: 'create.participant-expanded',
+ title: '扩展流程'
+ },
+ {
+ action: 'create.group',
+ title: '分组'
+ }
+ ]
+ }
+
+ // 获取控件配置信息
+ getControl(action) {
+ const result = this.controls.filter(item => item.action === action)
+ return result[0] || {}
+ }
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/PropertyPanel.vue b/src/modules/admin/components/Ruoyi/Process/PropertyPanel.vue
new file mode 100644
index 0000000..d5002d1
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/PropertyPanel.vue
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/common/customTranslate.js b/src/modules/admin/components/Ruoyi/Process/common/customTranslate.js
new file mode 100644
index 0000000..fa05f9d
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/common/customTranslate.js
@@ -0,0 +1,20 @@
+import translations from '../lang/zh'
+
+export default function customTranslate(template, replacements) {
+ replacements = replacements || {}
+
+ // Translate
+ template = translations[template] || template
+
+ // Replace
+ return template.replace(/{([^}]+)}/g, function(_, key) {
+ var str = replacements[key]
+ if (
+ translations[replacements[key]] !== null &&
+ translations[replacements[key]] !== 'undefined'
+ ) {
+ str = translations[replacements[key]]
+ }
+ return str || '{' + key + '}'
+ })
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/common/mixinExecutionListener.js b/src/modules/admin/components/Ruoyi/Process/common/mixinExecutionListener.js
new file mode 100644
index 0000000..23295b0
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/common/mixinExecutionListener.js
@@ -0,0 +1,24 @@
+
+import executionListenerDialog from '../components/nodePanel/property/executionListener'
+export default {
+ components: {
+ executionListenerDialog
+ },
+ data() {
+ return {
+ executionListenerLength: 0,
+ dialogName: null
+ }
+ },
+ methods: {
+ computedExecutionListenerLength() {
+ this.executionListenerLength = this.element.businessObject.extensionElements?.values?.length ?? 0
+ },
+ finishExecutionListener() {
+ if (this.dialogName === 'executionListenerDialog') {
+ this.computedExecutionListenerLength()
+ }
+ this.dialogName = ''
+ }
+ }
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/common/mixinPanel.js b/src/modules/admin/components/Ruoyi/Process/common/mixinPanel.js
new file mode 100644
index 0000000..d8c389d
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/common/mixinPanel.js
@@ -0,0 +1,76 @@
+// import xcrud from 'xcrud'
+// import golbalConfig from 'xcrud/package/common/config'
+
+import { toRaw } from 'vue';
+import xcrud from '../package/index.js'
+import golbalConfig from '../package/common/config.js'
+import showConfig from '../flowable/showConfig'
+golbalConfig.set({
+ input: {
+ // size: 'mini'
+ },
+ select: {
+ // size: 'mini'
+ },
+ colorPicker: {
+ showAlpha: true
+ },
+ xform: {
+ form: {
+ labelWidth: 'auto'
+ // size: 'mini'
+ }
+ }
+})
+export default {
+ components: { xForm: xcrud.xForm },
+ props: {
+ modeler: {
+ type: Object,
+ required: true
+ },
+ element: {
+ type: Object,
+ required: true
+ },
+ categorys: {
+ type: Array,
+ default: () => []
+ }
+ },
+ watch: {
+ 'formData.id': function(val) {
+ this.updateProperties({ id: val })
+ },
+ 'formData.name': function(val) {
+ this.updateProperties({ name: val })
+ },
+ 'formData.documentation': function(val) {
+ if (!val) {
+ this.updateProperties({ documentation: [] })
+ return
+ }
+ const documentationElement = this.modeler.get('moddle').create('bpmn:Documentation', { text: val })
+ this.updateProperties({ documentation: [documentationElement] })
+ }
+ },
+ methods: {
+ updateProperties(properties) {
+ const modeling = this.modeler.get('modeling')
+ const element_x = toRaw(this.element)
+ modeling.updateProperties(element_x, properties)
+
+ }
+ },
+ computed: {
+ elementType() {
+ const bizObj = this.element.businessObject
+ return bizObj.eventDefinitions
+ ? bizObj.eventDefinitions[0].$type
+ : bizObj.$type
+ },
+ showConfig() {
+ return showConfig[this.elementType] || {}
+ }
+ }
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/common/mixinXcrud.js b/src/modules/admin/components/Ruoyi/Process/common/mixinXcrud.js
new file mode 100644
index 0000000..72abe35
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/common/mixinXcrud.js
@@ -0,0 +1,30 @@
+// import xcrud from 'xcrud'
+// import golbalConfig from 'xcrud/package/common/config'
+
+
+
+import xcrud from '../package/index.js'
+import golbalConfig from '../package/common/config.js'
+console.log(xcrud);
+golbalConfig.set({
+ input: {
+ // size: 'mini'
+ },
+ select: {
+ // size: 'mini'
+ },
+ colorPicker: {
+ showAlpha: true
+ },
+ xform: {
+ form: {
+ labelWidth: 'auto'
+ // size: 'mini'
+ }
+ }
+})
+
+export default {
+ components: { xForm: xcrud.xForm }
+
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/common/parseElement.js b/src/modules/admin/components/Ruoyi/Process/common/parseElement.js
new file mode 100644
index 0000000..63cf336
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/common/parseElement.js
@@ -0,0 +1,53 @@
+export function commonParse(element) {
+ const result = {
+ ...element.businessObject,
+ ...element.businessObject.$attrs
+ }
+ return formatJsonKeyValue(result)
+}
+
+export function formatJsonKeyValue(result) {
+ // 移除flowable前缀,格式化数组
+ for (const key in result) {
+ if (key.indexOf('flowable:') === 0) {
+ const newKey = key.replace('flowable:', '')
+ result[newKey] = result[key]
+ delete result[key]
+ }
+ }
+ result = documentationParse(result)
+ return result
+}
+
+export function documentationParse(obj) {
+ if ('documentation' in obj) {
+ let str = ''
+ obj.documentation.forEach(item => {
+ str += item.text
+ })
+ obj.documentation = str
+ }
+ return obj
+}
+
+export function conditionExpressionParse(obj) {
+ if ('conditionExpression' in obj) {
+ obj.conditionExpression = obj.conditionExpression.body
+ }
+ return obj
+}
+
+export function userTaskParse(obj) {
+ for (const key in obj) {
+ if (key === 'candidateUsers') {
+ obj.userType = 'candidateUsers'
+ obj[key] = obj[key]?.split(',') || []
+ } else if (key === 'candidateGroups') {
+ obj.userType = 'candidateGroups'
+ obj[key] = obj[key]?.split(',') || []
+ } else if (key === 'assignee') {
+ obj.userType = 'assignee'
+ }
+ }
+ return obj
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/components/custom/customContextPad.vue b/src/modules/admin/components/Ruoyi/Process/components/custom/customContextPad.vue
new file mode 100644
index 0000000..89c2f68
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/custom/customContextPad.vue
@@ -0,0 +1,24 @@
+export default class CustomContextPad {
+ constructor(config, contextPad, create, elementFactory, injector, translate) {
+ this.create = create;
+ this.elementFactory = elementFactory;
+ this.translate = translate;
+
+ if (config.autoPlace !== false) {
+ this.autoPlace = injector.get('autoPlace', false);
+ }
+
+ contextPad.registerProvider(this); // 定义这是一个contextPad
+ }
+
+ getContextPadEntries(element) {}
+}
+
+CustomContextPad.$inject = [
+ 'config',
+ 'contextPad',
+ 'create',
+ 'elementFactory',
+ 'injector',
+ 'translate'
+];
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/gateway.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/gateway.vue
new file mode 100644
index 0000000..db18153
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/gateway.vue
@@ -0,0 +1,81 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/process.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/process.vue
new file mode 100644
index 0000000..6946f1e
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/process.vue
@@ -0,0 +1,113 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/executionListener.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/executionListener.vue
new file mode 100644
index 0000000..1a15b8a
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/executionListener.vue
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+ 配置
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/listenerParam.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/listenerParam.vue
new file mode 100644
index 0000000..dd8ace1
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/listenerParam.vue
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/multiInstance.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/multiInstance.vue
new file mode 100644
index 0000000..357b716
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/multiInstance.vue
@@ -0,0 +1,117 @@
+
+
+
+
+
+ 按照BPMN2.0规范的要求,用于为每个实例创建执行的父执行,会提供下列变量:
+ nrOfInstances:实例总数。
+ nrOfActiveInstances:当前活动的(即未完成的),实例数量。对于顺序多实例,这个值总为1。
+ nrOfCompletedInstances:已完成的实例数量。
+ loopCounter:给定实例在for-each循环中的index。
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/signal.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/signal.vue
new file mode 100644
index 0000000..2c29d73
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/signal.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/taskListener.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/taskListener.vue
new file mode 100644
index 0000000..0f72a89
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/property/taskListener.vue
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+ 配置
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/sequenceFlow.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/sequenceFlow.vue
new file mode 100644
index 0000000..178cd7d
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/sequenceFlow.vue
@@ -0,0 +1,92 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/startEnd.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/startEnd.vue
new file mode 100644
index 0000000..ccbd676
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/startEnd.vue
@@ -0,0 +1,99 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/components/nodePanel/task.vue b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/task.vue
new file mode 100644
index 0000000..dae7e30
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/components/nodePanel/task.vue
@@ -0,0 +1,426 @@
+
+
+
+
+
+ 编辑
+
+
+
+
+ 编辑
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/flowable/flowable.json b/src/modules/admin/components/Ruoyi/Process/flowable/flowable.json
new file mode 100644
index 0000000..bffad65
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/flowable/flowable.json
@@ -0,0 +1,1194 @@
+{
+ "name": "Flowable",
+ "uri": "http://flowable.org/bpmn",
+ "prefix": "flowable",
+ "xml": {
+ "tagAlias": "lowerCase"
+ },
+ "associations": [],
+ "types": [
+ {
+ "name": "InOutBinding",
+ "superClass": ["Element"],
+ "isAbstract": true,
+ "properties": [
+ {
+ "name": "source",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "sourceExpression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "target",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "businessKey",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "local",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ },
+ {
+ "name": "variables",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "In",
+ "superClass": ["InOutBinding"],
+ "meta": {
+ "allowedIn": ["bpmn:CallActivity"]
+ }
+ },
+ {
+ "name": "Out",
+ "superClass": ["InOutBinding"],
+ "meta": {
+ "allowedIn": ["bpmn:CallActivity"]
+ }
+ },
+ {
+ "name": "AsyncCapable",
+ "isAbstract": true,
+ "extends": ["bpmn:Activity", "bpmn:Gateway", "bpmn:Event"],
+ "properties": [
+ {
+ "name": "async",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ },
+ {
+ "name": "asyncBefore",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ },
+ {
+ "name": "asyncAfter",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ },
+ {
+ "name": "exclusive",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": true
+ }
+ ]
+ },
+ {
+ "name": "flowable:in",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "source",
+ "type": "string",
+ "isAttr": true
+ },
+ {
+ "name": "target",
+ "type": "string",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "flowable:out",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "source",
+ "type": "string",
+ "isAttr": true
+ },
+ {
+ "name": "target",
+ "type": "string",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "BoundaryEvent",
+ "superClass": ["CatchEvent"],
+ "properties": [
+ {
+ "name": "cancelActivity",
+ "default": true,
+ "isAttr": true,
+ "type": "Boolean"
+ },
+ {
+ "name": "attachedToRef",
+ "type": "Activity",
+ "isAttr": true,
+ "isReference": true
+ }
+ ]
+ },
+ {
+ "name": "JobPriorized",
+ "isAbstract": true,
+ "extends": ["bpmn:Process", "flowable:AsyncCapable"],
+ "properties": [
+ {
+ "name": "jobPriority",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "SignalEventDefinition",
+ "isAbstract": true,
+ "extends": ["bpmn:SignalEventDefinition"],
+ "properties": [
+ {
+ "name": "async",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": false
+ }
+ ]
+ },
+ {
+ "name": "ErrorEventDefinition",
+ "isAbstract": true,
+ "extends": ["bpmn:ErrorEventDefinition"],
+ "properties": [
+ {
+ "name": "errorCodeVariable",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "errorMessageVariable",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Error",
+ "isAbstract": true,
+ "extends": ["bpmn:Error"],
+ "properties": [
+ {
+ "name": "flowable:errorMessage",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "PotentialStarter",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "resourceAssignmentExpression",
+ "type": "bpmn:ResourceAssignmentExpression"
+ }
+ ]
+ },
+ {
+ "name": "UserTask",
+ "isAbstract": true,
+ "extends": ["bpmn:UserTask"],
+ "properties": [
+ {
+ "name": "timerEventDefinition",
+ "type": "Expression"
+ },
+ {
+ "name": "multiInstanceLoopCharacteristics",
+ "type": "MultiInstanceLoopCharacteristics"
+ }
+ ]
+ },
+ {
+ "name": "StartEvent",
+ "isAbstract": true,
+ "extends": ["bpmn:StartEvent"],
+ "properties": [
+ {
+ "name": "timerEventDefinition",
+ "type": "Expression"
+ }
+ ]
+ },
+ {
+ "name": "FormSupported",
+ "isAbstract": true,
+ "extends": ["bpmn:StartEvent", "bpmn:UserTask"],
+ "properties": [
+ {
+ "name": "formHandlerClass",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "formKey",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "TemplateSupported",
+ "isAbstract": true,
+ "extends": ["bpmn:Process", "bpmn:FlowElement"],
+ "properties": [
+ {
+ "name": "modelerTemplate",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Initiator",
+ "isAbstract": true,
+ "extends": ["bpmn:StartEvent"],
+ "properties": [
+ {
+ "name": "initiator",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ScriptTask",
+ "isAbstract": true,
+ "extends": ["bpmn:ScriptTask"],
+ "properties": [
+ {
+ "name": "resultVariable",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "resource",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Process",
+ "isAbstract": true,
+ "extends": ["bpmn:Process"],
+ "properties": [
+ {
+ "name": "candidateStarterGroups",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "candidateStarterUsers",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "versionTag",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "historyTimeToLive",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "isStartableInTasklist",
+ "isAttr": true,
+ "type": "Boolean",
+ "default": true
+ }
+ ]
+ },
+ {
+ "name": "EscalationEventDefinition",
+ "isAbstract": true,
+ "extends": ["bpmn:EscalationEventDefinition"],
+ "properties": [
+ {
+ "name": "escalationCodeVariable",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "FormalExpression",
+ "isAbstract": true,
+ "extends": ["bpmn:FormalExpression"],
+ "properties": [
+ {
+ "name": "resource",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Assignable",
+ "extends": ["bpmn:UserTask"],
+ "properties": [
+ {
+ "name": "candidateGroups",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "dueDate",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "followUpDate",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "priority",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "CallActivity",
+ "extends": ["bpmn:CallActivity"],
+ "properties": [
+ {
+ "name": "calledElementBinding",
+ "isAttr": true,
+ "type": "String",
+ "default": "latest"
+ },
+ {
+ "name": "calledElementVersion",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "calledElementVersionTag",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "calledElementTenantId",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "caseRef",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "caseBinding",
+ "isAttr": true,
+ "type": "String",
+ "default": "latest"
+ },
+ {
+ "name": "caseVersion",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "caseTenantId",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "variableMappingClass",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "variableMappingDelegateExpression",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ServiceTaskLike",
+ "extends": [
+ "bpmn:ServiceTask",
+ "bpmn:BusinessRuleTask",
+ "bpmn:SendTask",
+ "bpmn:MessageEventDefinition"
+ ],
+ "properties": [
+ {
+ "name": "expression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "class",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "delegateExpression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "resultVariable",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ExclusiveGateway",
+ "isAbstract": true,
+ "extends": ["bpmn:ExclusiveGateway"],
+ "properties": [
+ {
+ "name": "serviceClass",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "DmnCapable",
+ "extends": ["bpmn:BusinessRuleTask"],
+ "properties": [
+ {
+ "name": "decisionRef",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "decisionRefBinding",
+ "isAttr": true,
+ "type": "String",
+ "default": "latest"
+ },
+ {
+ "name": "decisionRefVersion",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "mapDecisionResult",
+ "isAttr": true,
+ "type": "String",
+ "default": "resultList"
+ },
+ {
+ "name": "decisionRefTenantId",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ExternalCapable",
+ "extends": ["flowable:ServiceTaskLike"],
+ "properties": [
+ {
+ "name": "type",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "topic",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "TaskPriorized",
+ "extends": ["bpmn:Process", "flowable:ExternalCapable"],
+ "properties": [
+ {
+ "name": "taskPriority",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Properties",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["*"]
+ },
+ "properties": [
+ {
+ "name": "values",
+ "type": "Property",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "Property",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "id",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "name",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "value",
+ "type": "String",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "Connector",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["flowable:ServiceTaskLike"]
+ },
+ "properties": [
+ {
+ "name": "inputOutput",
+ "type": "InputOutput"
+ },
+ {
+ "name": "connectorId",
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "InputOutput",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["bpmn:FlowNode", "flowable:Connector"]
+ },
+ "properties": [
+ {
+ "name": "inputOutput",
+ "type": "InputOutput"
+ },
+ {
+ "name": "connectorId",
+ "type": "String"
+ },
+ {
+ "name": "inputParameters",
+ "isMany": true,
+ "type": "InputParameter"
+ },
+ {
+ "name": "outputParameters",
+ "isMany": true,
+ "type": "OutputParameter"
+ }
+ ]
+ },
+ {
+ "name": "InputOutputParameter",
+ "properties": [
+ {
+ "name": "name",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "value",
+ "isBody": true,
+ "type": "String"
+ },
+ {
+ "name": "definition",
+ "type": "InputOutputParameterDefinition"
+ }
+ ]
+ },
+ {
+ "name": "InputOutputParameterDefinition",
+ "isAbstract": true
+ },
+ {
+ "name": "List",
+ "superClass": ["InputOutputParameterDefinition"],
+ "properties": [
+ {
+ "name": "items",
+ "isMany": true,
+ "type": "InputOutputParameterDefinition"
+ }
+ ]
+ },
+ {
+ "name": "Map",
+ "superClass": ["InputOutputParameterDefinition"],
+ "properties": [
+ {
+ "name": "entries",
+ "isMany": true,
+ "type": "Entry"
+ }
+ ]
+ },
+ {
+ "name": "Entry",
+ "properties": [
+ {
+ "name": "key",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "value",
+ "isBody": true,
+ "type": "String"
+ },
+ {
+ "name": "definition",
+ "type": "InputOutputParameterDefinition"
+ }
+ ]
+ },
+ {
+ "name": "Value",
+ "superClass": ["InputOutputParameterDefinition"],
+ "properties": [
+ {
+ "name": "id",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "name",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "value",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Script",
+ "superClass": ["InputOutputParameterDefinition"],
+ "properties": [
+ {
+ "name": "scriptFormat",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "resource",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "value",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "Field",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": [
+ "flowable:ServiceTaskLike",
+ "flowable:ExecutionListener",
+ "flowable:TaskListener"
+ ]
+ },
+ "properties": [
+ {
+ "name": "name",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "expression",
+ "isAttr": true,
+ "type": "expression"
+ },
+ {
+ "name": "string",
+ "type": "string"
+ },
+ {
+ "name": "stringValue",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "string",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": [
+ "flowable:Field"
+ ]
+ },
+ "properties": [
+ {
+ "name": "body",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "expression",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": [
+ "flowable:Field"
+ ]
+ },
+ "properties": [
+ {
+ "name": "body",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "InputParameter",
+ "superClass": ["InputOutputParameter"]
+ },
+ {
+ "name": "OutputParameter",
+ "superClass": ["InputOutputParameter"]
+ },
+ {
+ "name": "Collectable",
+ "isAbstract": true,
+ "extends": ["bpmn:MultiInstanceLoopCharacteristics"],
+ "superClass": ["flowable:AsyncCapable"],
+ "properties": [
+ {
+ "name": "collection",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "elementVariable",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "SequenceFlow",
+ "superClass": ["FlowElement"],
+ "properties": [
+ {
+ "name": "isImmediate",
+ "isAttr": true,
+ "type": "Boolean"
+ },
+ {
+ "name": "conditionExpression",
+ "type": "Expression"
+ },
+ {
+ "name": "sourceRef",
+ "type": "FlowNode",
+ "isAttr": true,
+ "isReference": true
+ },
+ {
+ "name": "targetRef",
+ "type": "FlowNode",
+ "isAttr": true,
+ "isReference": true
+ }
+ ]
+ },
+ {
+ "name": "MultiInstanceLoopCharacteristics",
+ "superClass": ["LoopCharacteristics"],
+ "properties": [
+ {
+ "name": "isSequential",
+ "default": false,
+ "isAttr": true,
+ "type": "Boolean"
+ },
+ {
+ "name": "behavior",
+ "type": "MultiInstanceBehavior",
+ "default": "All",
+ "isAttr": true
+ },
+ {
+ "name": "loopCardinality",
+ "type": "Expression",
+ "xml": {
+ "serialize": "xsi:type"
+ }
+ },
+ {
+ "name": "loopDataInputRef",
+ "type": "ItemAwareElement",
+ "isReference": true
+ },
+ {
+ "name": "loopDataOutputRef",
+ "type": "ItemAwareElement",
+ "isReference": true
+ },
+ {
+ "name": "inputDataItem",
+ "type": "DataInput",
+ "xml": {
+ "serialize": "property"
+ }
+ },
+ {
+ "name": "outputDataItem",
+ "type": "DataOutput",
+ "xml": {
+ "serialize": "property"
+ }
+ },
+ {
+ "name": "complexBehaviorDefinition",
+ "type": "ComplexBehaviorDefinition",
+ "isMany": true
+ },
+ {
+ "name": "completionCondition",
+ "type": "Expression",
+ "xml": {
+ "serialize": "xsi:type"
+ }
+ },
+ {
+ "name": "oneBehaviorEventRef",
+ "type": "EventDefinition",
+ "isAttr": true,
+ "isReference": true
+ },
+ {
+ "name": "noneBehaviorEventRef",
+ "type": "EventDefinition",
+ "isAttr": true,
+ "isReference": true
+ }
+ ]
+ },
+ {
+ "name": "FailedJobRetryTimeCycle",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["flowable:AsyncCapable", "bpmn:MultiInstanceLoopCharacteristics"]
+ },
+ "properties": [
+ {
+ "name": "body",
+ "isBody": true,
+ "type": "String"
+ }
+ ]
+ },
+ {
+ "name": "ExecutionListener",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": [
+ "bpmn:Task",
+ "bpmn:ServiceTask",
+ "bpmn:UserTask",
+ "bpmn:BusinessRuleTask",
+ "bpmn:ScriptTask",
+ "bpmn:ReceiveTask",
+ "bpmn:ManualTask",
+ "bpmn:ExclusiveGateway",
+ "bpmn:SequenceFlow",
+ "bpmn:ParallelGateway",
+ "bpmn:InclusiveGateway",
+ "bpmn:EventBasedGateway",
+ "bpmn:StartEvent",
+ "bpmn:IntermediateCatchEvent",
+ "bpmn:IntermediateThrowEvent",
+ "bpmn:EndEvent",
+ "bpmn:BoundaryEvent",
+ "bpmn:CallActivity",
+ "bpmn:SubProcess",
+ "bpmn:Process"
+ ]
+ },
+ "properties": [
+ {
+ "name": "expression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "class",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "delegateExpression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "event",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "script",
+ "type": "Script"
+ },
+ {
+ "name": "fields",
+ "type": "Field",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "TaskListener",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["bpmn:UserTask"]
+ },
+ "properties": [
+ {
+ "name": "expression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "class",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "delegateExpression",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "event",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "script",
+ "type": "Script"
+ },
+ {
+ "name": "fields",
+ "type": "Field",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "FormProperty",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["bpmn:StartEvent", "bpmn:UserTask"]
+ },
+ "properties": [
+ {
+ "name": "id",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "name",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "type",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "required",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "readable",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "writable",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "variable",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "expression",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "datePattern",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "default",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "values",
+ "type": "Value",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "FormData",
+ "superClass": ["Element"],
+ "meta": {
+ "allowedIn": ["bpmn:StartEvent", "bpmn:UserTask"]
+ },
+ "properties": [
+ {
+ "name": "fields",
+ "type": "FormField",
+ "isMany": true
+ },
+ {
+ "name": "businessKey",
+ "type": "String",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "FormField",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "id",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "label",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "type",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "datePattern",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "defaultValue",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "properties",
+ "type": "Properties"
+ },
+ {
+ "name": "validation",
+ "type": "Validation"
+ },
+ {
+ "name": "values",
+ "type": "Value",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "Validation",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "constraints",
+ "type": "Constraint",
+ "isMany": true
+ }
+ ]
+ },
+ {
+ "name": "Constraint",
+ "superClass": ["Element"],
+ "properties": [
+ {
+ "name": "name",
+ "type": "String",
+ "isAttr": true
+ },
+ {
+ "name": "config",
+ "type": "String",
+ "isAttr": true
+ }
+ ]
+ },
+ {
+ "name": "ConditionalEventDefinition",
+ "isAbstract": true,
+ "extends": ["bpmn:ConditionalEventDefinition"],
+ "properties": [
+ {
+ "name": "variableName",
+ "isAttr": true,
+ "type": "String"
+ },
+ {
+ "name": "variableEvent",
+ "isAttr": true,
+ "type": "String"
+ }
+ ]
+ }
+ ],
+ "emumerations": []
+ }
\ No newline at end of file
diff --git a/src/modules/admin/components/Ruoyi/Process/flowable/init.js b/src/modules/admin/components/Ruoyi/Process/flowable/init.js
new file mode 100644
index 0000000..ec9e282
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/flowable/init.js
@@ -0,0 +1,24 @@
+
+function randomStr() {
+ return Math.random().toString(36).slice(-8)
+}
+
+export default function() {
+ return `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/flowable/showConfig.js b/src/modules/admin/components/Ruoyi/Process/flowable/showConfig.js
new file mode 100644
index 0000000..69ba83e
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/flowable/showConfig.js
@@ -0,0 +1,55 @@
+export default {
+ 'bpmn:EndEvent': {},
+ 'bpmn:StartEvent': {
+ initiator: true,
+ formKey: true
+ },
+ 'bpmn:UserTask': {
+ userType: true,
+ dataType: true,
+ assignee: true,
+ candidateUsers: true,
+ candidateGroups: true,
+ // assigneeFixed: true,
+ // candidateUsersFixed: true,
+ // candidateGroupsFixed: true,
+ async: true,
+ priority: true,
+ formKey: true,
+ skipExpression: true,
+ dueDate: true,
+ taskListener: true
+ },
+ 'bpmn:ServiceTask': {
+ async: true,
+ skipExpression: true,
+ isForCompensation: true,
+ triggerable: true,
+ class: true
+ },
+ 'bpmn:ScriptTask': {
+ async: true,
+ isForCompensation: true,
+ autoStoreVariables: true
+ },
+ 'bpmn:ManualTask': {
+ async: true,
+ isForCompensation: true
+ },
+ 'bpmn:ReceiveTask': {
+ async: true,
+ isForCompensation: true
+ },
+ 'bpmn:SendTask': {
+ async: true,
+ isForCompensation: true
+ },
+ 'bpmn:BusinessRuleTask': {
+ async: true,
+ isForCompensation: true,
+ ruleVariablesInput: true,
+ rules: true,
+ resultVariable: true,
+ exclude: true
+ }
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/index.js b/src/modules/admin/components/Ruoyi/Process/index.js
new file mode 100644
index 0000000..f78489d
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/index.js
@@ -0,0 +1,5 @@
+import workflowBpmnModeler from './index.vue'
+
+workflowBpmnModeler.install = Vue => Vue.component(workflowBpmnModeler.name, workflowBpmnModeler) // 给组件配置install方法
+
+export default workflowBpmnModeler
diff --git a/src/modules/admin/components/Ruoyi/Process/index.vue b/src/modules/admin/components/Ruoyi/Process/index.vue
new file mode 100644
index 0000000..38c42de
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/index.vue
@@ -0,0 +1,467 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查看xml
+ 下载xml
+ 下载svg
+ {{saveTip}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/lang/zh.js b/src/modules/admin/components/Ruoyi/Process/lang/zh.js
new file mode 100644
index 0000000..003c0cc
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/lang/zh.js
@@ -0,0 +1,227 @@
+export default {
+ // Labels
+ 'Activate the global connect tool': '激活全局连接工具',
+ 'Append {type}': '添加 {type}',
+ 'Add Lane above': '在上面添加道',
+ 'Divide into two Lanes': '分割成两个道',
+ 'Divide into three Lanes': '分割成三个道',
+ 'Add Lane below': '在下面添加道',
+ 'Append compensation activity': '追加补偿活动',
+ 'Change type': '修改类型',
+ 'Connect using Association': '使用关联连接',
+ 'Connect using Sequence/MessageFlow or Association': '使用顺序/消息流或者关联连接',
+ 'Connect using DataInputAssociation': '使用数据输入关联连接',
+ 'Remove': '移除',
+ 'Activate the hand tool': '激活抓手工具',
+ 'Activate the lasso tool': '激活套索工具',
+ 'Activate the create/remove space tool': '激活创建/删除空间工具',
+ 'Create expanded SubProcess': '创建扩展子过程',
+ 'Create IntermediateThrowEvent/BoundaryEvent': '创建中间抛出事件/边界事件',
+ 'Create Pool/Participant': '创建池/参与者',
+ 'Parallel Multi Instance': '并行多重事件',
+ 'Sequential Multi Instance': '时序多重事件',
+ 'DataObjectReference': '数据对象参考',
+ 'DataStoreReference': '数据存储参考',
+ 'Loop': '循环',
+ 'Ad-hoc': '即席',
+ 'Create {type}': '创建 {type}',
+ 'Task': '任务',
+ 'Send Task': '发送任务',
+ 'Receive Task': '接收任务',
+ 'User Task': '用户任务',
+ 'Manual Task': '手工任务',
+ 'Business Rule Task': '业务规则任务',
+ 'Service Task': '服务任务',
+ 'Script Task': '脚本任务',
+ 'Call Activity': '调用活动',
+ 'Sub Process (collapsed)': '子流程(折叠的)',
+ 'Sub Process (expanded)': '子流程(展开的)',
+ 'Start Event': '开始事件',
+ 'StartEvent': '开始事件',
+ 'Intermediate Throw Event': '中间事件',
+ 'End Event': '结束事件',
+ 'EndEvent': '结束事件',
+ 'Create Gateway': '创建网关',
+ 'Create Intermediate/Boundary Event': '创建中间/边界事件',
+ 'Message Start Event': '消息开始事件',
+ 'Timer Start Event': '定时开始事件',
+ 'Conditional Start Event': '条件开始事件',
+ 'Signal Start Event': '信号开始事件',
+ 'Error Start Event': '错误开始事件',
+ 'Escalation Start Event': '升级开始事件',
+ 'Compensation Start Event': '补偿开始事件',
+ 'Message Start Event (non-interrupting)': '消息开始事件(非中断)',
+ 'Timer Start Event (non-interrupting)': '定时开始事件(非中断)',
+ 'Conditional Start Event (non-interrupting)': '条件开始事件(非中断)',
+ 'Signal Start Event (non-interrupting)': '信号开始事件(非中断)',
+ 'Escalation Start Event (non-interrupting)': '升级开始事件(非中断)',
+ 'Message Intermediate Catch Event': '消息中间捕获事件',
+ 'Message Intermediate Throw Event': '消息中间抛出事件',
+ 'Timer Intermediate Catch Event': '定时中间捕获事件',
+ 'Escalation Intermediate Throw Event': '升级中间抛出事件',
+ 'Conditional Intermediate Catch Event': '条件中间捕获事件',
+ 'Link Intermediate Catch Event': '链接中间捕获事件',
+ 'Link Intermediate Throw Event': '链接中间抛出事件',
+ 'Compensation Intermediate Throw Event': '补偿中间抛出事件',
+ 'Signal Intermediate Catch Event': '信号中间捕获事件',
+ 'Signal Intermediate Throw Event': '信号中间抛出事件',
+ 'Message End Event': '消息结束事件',
+ 'Escalation End Event': '定时结束事件',
+ 'Error End Event': '错误结束事件',
+ 'Cancel End Event': '取消结束事件',
+ 'Compensation End Event': '补偿结束事件',
+ 'Signal End Event': '信号结束事件',
+ 'Terminate End Event': '终止结束事件',
+ 'Message Boundary Event': '消息边界事件',
+ 'Message Boundary Event (non-interrupting)': '消息边界事件(非中断)',
+ 'Timer Boundary Event': '定时边界事件',
+ 'Timer Boundary Event (non-interrupting)': '定时边界事件(非中断)',
+ 'Escalation Boundary Event': '升级边界事件',
+ 'Escalation Boundary Event (non-interrupting)': '升级边界事件(非中断)',
+ 'Conditional Boundary Event': '条件边界事件',
+ 'Conditional Boundary Event (non-interrupting)': '条件边界事件(非中断)',
+ 'Error Boundary Event': '错误边界事件',
+ 'Cancel Boundary Event': '取消边界事件',
+ 'Signal Boundary Event': '信号边界事件',
+ 'Signal Boundary Event (non-interrupting)': '信号边界事件(非中断)',
+ 'Compensation Boundary Event': '补偿边界事件',
+ 'Exclusive Gateway': '互斥网关',
+ 'Parallel Gateway': '并行网关',
+ 'Inclusive Gateway': '相容网关',
+ 'Complex Gateway': '复杂网关',
+ 'Event based Gateway': '事件网关',
+ 'Transaction': '转运',
+ 'Sub Process': '子流程',
+ 'Event Sub Process': '事件子流程',
+ 'Collapsed Pool': '折叠池',
+ 'Expanded Pool': '展开池',
+ // Errors
+ 'no parent for {element} in {parent}': '在{parent}里,{element}没有父类',
+ 'no shape type specified': '没有指定的形状类型',
+ 'flow elements must be children of pools/participants': '流元素必须是池/参与者的子类',
+ 'out of bounds release': 'out of bounds release',
+ 'more than {count} child lanes': '子道大于{count} ',
+ 'element required': '元素不能为空',
+ 'diagram not part of bpmn:Definitions': '流程图不符合bpmn规范',
+ 'no diagram to display': '没有可展示的流程图',
+ 'no process or collaboration to display': '没有可展示的流程/协作',
+ 'element {element} referenced by {referenced}#{property} not yet drawn': '由{referenced}#{property}引用的{element}元素仍未绘制',
+ 'already rendered {element}': '{element} 已被渲染',
+ 'failed to import {element}': '导入{element}失败',
+ // 属性面板的参数
+ 'Id': '标识',
+ 'Name': '名称',
+ 'General': '常规',
+ 'Details': '详情',
+ 'Message Name': '消息名称',
+ 'Message': '消息',
+ 'Initiator': '创建者',
+ 'Asynchronous Continuations': '持续异步',
+ 'Asynchronous Before': '异步前',
+ 'Asynchronous After': '异步后',
+ 'Job Configuration': '工作配置',
+ 'Exclusive': '排除',
+ 'Job Priority': '工作优先级',
+ 'Retry Time Cycle': '重试时间周期',
+ 'Documentation': '文档',
+ 'Element Documentation': '元素文档',
+ 'History Configuration': '历史配置',
+ 'History Time To Live': '历史的生存时间',
+ 'Forms': '表单',
+ 'Form Key': '表单key',
+ 'Form Fields': '表单字段',
+ 'Business Key': '业务key',
+ 'Form Field': '表单字段',
+ 'ID': '编号',
+ 'Type': '类型',
+ 'Label': '名称',
+ 'Default Value': '默认值',
+ 'Validation': '校验',
+ 'Add Constraint': '添加约束',
+ 'Config': '配置',
+ 'Properties': '属性',
+ 'Add Property': '添加属性',
+ 'Value': '值',
+ 'Listeners': '监听器',
+ 'Execution Listener': '执行监听',
+ 'Event Type': '事件类型',
+ 'Listener Type': '监听器类型',
+ 'Java Class': 'Java类',
+ 'Expression': '表达式',
+ 'Must provide a value': '必须提供一个值',
+ 'Delegate Expression': '代理表达式',
+ 'Script': '脚本',
+ 'Script Format': '脚本格式',
+ 'Script Type': '脚本类型',
+ 'Inline Script': '内联脚本',
+ 'External Script': '外部脚本',
+ 'Resource': '资源',
+ 'Field Injection': '字段注入',
+ 'Extensions': '扩展',
+ 'Input/Output': '输入/输出',
+ 'Input Parameters': '输入参数',
+ 'Output Parameters': '输出参数',
+ 'Parameters': '参数',
+ 'Output Parameter': '输出参数',
+ 'Timer Definition Type': '定时器定义类型',
+ 'Timer Definition': '定时器定义',
+ 'Date': '日期',
+ 'Duration': '持续',
+ 'Cycle': '循环',
+ 'Signal': '信号',
+ 'Signal Name': '信号名称',
+ 'Escalation': '升级',
+ 'Error': '错误',
+ 'Link Name': '链接名称',
+ 'Condition': '条件名称',
+ 'Variable Name': '变量名称',
+ 'Variable Event': '变量事件',
+ 'Specify more than one variable change event as a comma separated list.': '多个变量事件以逗号隔开',
+ 'Wait for Completion': '等待完成',
+ 'Activity Ref': '活动参考',
+ 'Version Tag': '版本标签',
+ 'Executable': '可执行文件',
+ 'External Task Configuration': '扩展任务配置',
+ 'Task Priority': '任务优先级',
+ 'External': '外部',
+ 'Connector': '连接器',
+ 'Must configure Connector': '必须配置连接器',
+ 'Connector Id': '连接器编号',
+ 'Implementation': '实现方式',
+ 'Field Injections': '字段注入',
+ 'Fields': '字段',
+ 'Result Variable': '结果变量',
+ 'Topic': '主题',
+ 'Configure Connector': '配置连接器',
+ 'Input Parameter': '输入参数',
+ 'Assignee': '代理人',
+ 'Candidate Users': '候选用户',
+ 'Candidate Groups': '候选组',
+ 'Due Date': '到期时间',
+ 'Follow Up Date': '跟踪日期',
+ 'Priority': '优先级',
+ 'The follow up date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)': '跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00',
+ 'The due date as an EL expression (e.g. ${someDate} or an ISO date (e.g. 2015-06-26T09:54:00)': '跟踪日期必须符合EL表达式,如: ${someDate} ,或者一个ISO标准日期,如:2015-06-26T09:54:00',
+ 'Variables': '变量'
+}
+
+export const NodeName = {
+ 'bpmn:Process': '流程',
+ 'bpmn:StartEvent': '开始事件',
+ 'bpmn:IntermediateThrowEvent': '中间事件',
+ 'bpmn:Task': '任务',
+ 'bpmn:SendTask': '发送任务',
+ 'bpmn:ReceiveTask': '接收任务',
+ 'bpmn:UserTask': '用户任务',
+ 'bpmn:ManualTask': '手工任务',
+ 'bpmn:BusinessRuleTask': '业务规则任务',
+ 'bpmn:ServiceTask': '服务任务',
+ 'bpmn:ScriptTask': '脚本任务',
+ 'bpmn:EndEvent': '结束事件',
+ 'bpmn:SequenceFlow': '流程线',
+ 'bpmn:ExclusiveGateway': '互斥网关',
+ 'bpmn:ParallelGateway': '并行网关',
+ 'bpmn:InclusiveGateway': '相容网关',
+ 'bpmn:ComplexGateway': '复杂网关',
+ 'bpmn:EventBasedGateway': '事件网关'
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/package/common/config.js b/src/modules/admin/components/Ruoyi/Process/package/common/config.js
new file mode 100644
index 0000000..881c90b
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/common/config.js
@@ -0,0 +1,495 @@
+import merge from 'lodash.merge'
+const golbalConfig = {
+ input: {
+ disabled: false,
+ type: 'text',
+ valueKey: 'value',
+ debounce: 300,
+ placement: 'bottom-start',
+ triggerOnFocus: true,
+ selectWhenUnmatched: false,
+ maxlength: null,
+ minlength: null,
+ showWordLimit: false,
+ placeholder: null,
+ clearable: false,
+ size: 'medium',
+ rows: 3,
+ autosize: false,
+ autocomplete: 'off',
+ resize: 'none',
+ validateEvent: true,
+ hideLoading: false,
+ popperAppendToBody: true,
+ highlightFirstItem: false
+ },
+ autocomplete: {
+ disabled: false,
+ placeholder: null,
+ valueKey: 'value',
+ debounce: 300,
+ placement: 'bottom-start',
+ fetchSuggestions: null,
+ popperClass: null,
+ triggerOnFocus: true,
+ name: null,
+ selectWhenUnmatched: false,
+ label: null,
+ prefixIcon: null,
+ suffixIcon: null,
+ hideLoading: false,
+ popperAppendToBody: true,
+ highlightFirstItem: false,
+ maxlength: null,
+ minlength: null,
+ clearable: false,
+ size: 'medium',
+ rows: 3,
+ autosize: false,
+ autocomplete: 'off',
+ resize: 'none',
+ validateEvent: true
+ },
+ select: {
+ disabled: false,
+ multiple: false,
+ valueKey: 'value',
+ size: 'medium',
+ clearable: false,
+ collapseTags: false,
+ multipleLimit: 0,
+ autocomplete: 'off',
+ placeholder: '请选择',
+ filterable: false,
+ allowCreate: false,
+ remote: false,
+ loading: false,
+ loadingText: '加载中',
+ noMatchText: '无匹配数据',
+ noDataText: '无数据',
+ reserveKeyword: false,
+ defaultFirstOption: false,
+ popperAppendToBody: true,
+ automaticDropdown: false
+ },
+ datePicker: {
+ disabled: false,
+ readonly: false,
+ editable: true,
+ clearable: true,
+ size: '',
+ placeholder: '请选择日期',
+ startPlaceholder: '开始时间',
+ endPlaceholder: '结束时间',
+ type: 'date',
+ format: '',
+ align: 'left',
+ pickerOptions: {},
+ rangeSeparator: ':',
+ valueFormat: '',
+ unlinkPanels: false,
+ prefixIcon: 'el-icon-date',
+ clearIcon: 'el-icon-circle-close',
+ validateEvent: true
+ },
+ checkbox: {
+ disabled: false,
+ size: 'medium',
+ min: undefined,
+ max: undefined,
+ textColor: '#ffffff',
+ fill: '#409EFF',
+ border: false
+ },
+ radio: {
+ disabled: false,
+ border: false,
+ size: 'medium',
+ textColor: '#ffffff',
+ fill: '#409EFF'
+ },
+ cascader: {
+ disabled: false,
+ size: 'medium',
+ placeholder: '请选择',
+ clearable: false,
+ showAllLevels: true,
+ collapseTags: false,
+ separator: ' / ',
+ debounce: 300
+ },
+ switch: {
+ disabled: false,
+ width: 40,
+ activeValue: true,
+ inactiveValue: false,
+ activeColor: '#409EFF',
+ inactiveColor: '#C0CCDA',
+ validateEvent: true
+ },
+ inputNumber: {
+ disabled: false,
+ min: '-Infinity',
+ max: 'Infinity',
+ step: 1,
+ stepStrictly: false,
+ precision: null,
+ size: 'medium',
+ controls: true,
+ controlsPosition: null,
+ placeholder: null
+ },
+ slider: {
+ disabled: false,
+ min: 0,
+ max: 100,
+ step: 1,
+ showInput: false,
+ showInputControls: true,
+ inputSize: 'small',
+ showStops: false,
+ showTooltip: true,
+ range: false,
+ vertical: false,
+ height: null,
+ label: null,
+ debounce: 300,
+ marks: null
+ },
+ timePicker: {
+ disabled: false,
+ editable: true,
+ clearable: true,
+ size: 'medium',
+ placeholder: '',
+ align: 'left',
+ startPlaceholder: '',
+ endPlaceholder: '',
+ isRange: false,
+ arrowControl: false,
+ pickerOptions: {},
+ rangeSeparator: ':',
+ valueFormat: '',
+ prefixIcon: 'el-icon-time',
+ clearIcon: 'el-icon-circle-close',
+
+ selectableRange: null,
+ format: 'HH:mm:ss'
+ },
+ timeSelect: {
+ disabled: false,
+ editable: true,
+ clearable: true,
+ size: 'medium',
+ placeholder: '',
+ align: 'left',
+ startPlaceholder: '',
+ endPlaceholder: '',
+ isRange: false,
+ arrowControl: false,
+ pickerOptions: {},
+ rangeSeparator: ':',
+ valueFormat: '',
+ prefixIcon: 'el-icon-time',
+ clearIcon: 'el-icon-circle-close',
+
+ start: '09:00',
+ end: '18:00',
+ step: '00:30',
+ minTime: '00:00',
+ maxTime: null
+ },
+ rate: {
+ disabled: false,
+ max: 5,
+ texts: ['极差', '失望', '一般', '满意', '惊喜'],
+ colors: ['#F7BA2A', '#F7BA2A', '#F7BA2A'],
+ allowHalf: false,
+ lowThreshold: 2,
+ highThreshold: 4,
+ voidColor: '#C6D1DE',
+ iconClasses: ['el-icon-star-on', 'el-icon-star-on', 'el-icon-star-on'],
+ showText: false,
+ showScore: false,
+ textColor: '#1F2D3D',
+ scoreTemplate: '{value}',
+ disabledVoidColor: '#EFF2F7',
+ voidIconClass: 'el-icon-star-off',
+ disabledVoidIconClass: 'el-icon-star-on'
+ },
+ colorPicker: {
+ disabled: false,
+ size: 'medium',
+ predefine: null,
+ showAlpha: false,
+ colorFormat: 'hex'
+ },
+ transfer: {
+ disabled: false,
+ filterable: false,
+ filterPlaceholder: '请输入搜索内容',
+ targetOrder: 'original',
+ titles: ['列表 1', '列表 2'],
+ buttonTexts: [],
+ format: { noChecked: '${checked}/${total}', hasChecked: '${checked}/${total}' },
+ props: null
+ },
+ xtable: {
+ table: {
+ height: null,
+ maxHeight: null,
+ stripe: false,
+ border: false,
+ size: 'medium',
+ fit: true,
+ showHeader: true,
+ highlightCurrentRow: false,
+ rowClassName: null,
+ rowStyle: null,
+ cellClassName: null,
+ cellStyle: null,
+ headerRowClassName: null,
+ headerRowStyle: null,
+ headerCellClassName: null,
+ headerCellStyle: null,
+ emptyText: '暂无数据',
+ defaultExpandAll: false,
+ defaultSort: { order: 'ascending' },
+ tooltipEffect: 'dark',
+ showSummary: false,
+ sumText: '合计',
+ selectOnIndeterminate: true,
+ indent: 16,
+ treeProps: { hasChildren: 'hasChildren', children: 'children' }
+ },
+ column: {
+ width: null,
+ minWidth: null,
+ fixed: false,
+ sortable: false,
+ sortOrders: ['ascending', 'descending', null],
+ resizable: true,
+ showOverflowTooltip: false,
+ align: 'center',
+ headerAlign: 'center',
+ className: null,
+ labelClassName: null,
+ reserveSelection: false,
+ filterPlacement: null,
+ filterMultiple: true
+ },
+ search: {
+ form: {
+ inline: true,
+ labelPosition: 'right',
+ labelWidth: 'auto',
+ labelSuffix: undefined,
+ hideRequiredAsterisk: false,
+ showMessage: true,
+ inlineMessage: false,
+ statusIcon: false,
+ validateOnRuleChange: true,
+ size: 'medium',
+ disabled: false,
+ itemStyle: 'width: 200px;'
+ },
+ btn: {
+ size: 'medium',
+ type: 'primary',
+ plain: false,
+ round: false,
+ circle: false,
+ loading: false,
+ disabled: false,
+ icon: null,
+ autofocus: false,
+ nativeType: 'button',
+ searchBtn: {
+ // circle: false,
+ // round: false,
+ // plain: false,
+ // type: 'primary',
+ show: true,
+ text: '搜索',
+ icon: 'el-icon-search'
+ },
+ resetBtn: {
+ // circle: false,
+ // round: false,
+ // plain: false,
+ // type: 'primary',
+ show: true,
+ text: '重置',
+ icon: 'el-icon-refresh-right'
+ }
+ }
+ },
+ operate: {
+ column: {
+ label: '操作'
+ // width: null,
+ // minWidth: null,
+ // fixed: false
+ // renderHeader: null,
+ // resizable: null,
+ // align: null,
+ // headerAlign: null,
+ // className: null,
+ // labelClassName: null
+ },
+ btn: {
+ size: 'medium',
+ type: 'primary',
+ plain: false,
+ round: false,
+ circle: false,
+ loading: false,
+ disabled: false,
+ icon: null,
+ autofocus: false,
+ nativeType: 'button'
+ },
+ dropdown: {
+ className: '',
+ text: '更多',
+ placement: 'bottom-end',
+ trigger: 'hover',
+ hideOnClick: true,
+ showTimeout: 250,
+ hideTimeout: 150,
+ tabindex: 0,
+ divided: false
+ }
+ }
+ },
+ xform: {
+ form: {
+ inline: false,
+ labelPosition: 'right',
+ labelWidth: '120px',
+ labelSuffix: undefined,
+ hideRequiredAsterisk: false,
+ showMessage: true,
+ inlineMessage: false,
+ statusIcon: false,
+ validateOnRuleChange: true,
+ size: 'medium',
+ disabled: false,
+ itemStyle: 'max-width: 300px; width: 100%;',
+ tooltip: {
+ effect: 'dark',
+ placement: 'top-start',
+ iconName: 'el-icon-info',
+ iconStyle: 'color: #409EFF'
+ },
+ tabs: {
+ type: 'border-card',
+ closable: false,
+ addable: false,
+ editable: false,
+ tabPosition: 'top',
+ stretch: false,
+ table: {
+ height: null,
+ maxHeight: null,
+ stripe: false,
+ border: true,
+ size: 'medium',
+ fit: true,
+ showHeader: true,
+ highlightCurrentRow: false,
+ rowClassName: null,
+ rowStyle: null,
+ cellClassName: null,
+ cellStyle: null,
+ headerRowClassName: null,
+ headerRowStyle: null,
+ headerCellClassName: null,
+ headerCellStyle: null,
+ emptyText: '暂无数据',
+ defaultExpandAll: false,
+ defaultSort: { order: 'ascending' },
+ tooltipEffect: 'dark',
+ showSummary: false,
+ sumText: '合计',
+ selectOnIndeterminate: true,
+ indent: 16,
+ treeProps: { hasChildren: 'hasChildren', children: 'children' },
+ column: {
+ width: null,
+ minWidth: null,
+ showOverflowTooltip: false,
+ align: 'center',
+ headerAlign: 'center',
+ className: null,
+ // input的宽度100%
+ style: 'width: 100%'
+ },
+ addConfig: {
+ show: true,
+ type: 'primary',
+ icon: '',
+ text: '新增',
+ size: 'mini',
+ circle: false,
+ style: 'margin-bottom:14px;',
+ className: '',
+ click: (fun, arr) => {
+ if (fun) {
+ fun(arr)
+ return
+ }
+ arr.splice(arr.length, 0, {})
+ }
+ },
+ operate: {
+ show: true,
+ label: '操作',
+ width: '60px',
+ headerAlign: 'center',
+ align: 'center',
+ btn: [
+ {
+ type: 'danger',
+ icon: 'el-icon-close',
+ text: '',
+ size: 'mini',
+ circle: true,
+ style: '',
+ className: '',
+ click: (arr, index, fun) => {
+ if (fun) {
+ fun(arr, index)
+ return
+ }
+ arr.splice(index, 1)
+ }
+ }
+ ]
+ }
+ }
+ }
+ },
+ operate: {
+ btn: {
+ size: 'medium',
+ type: 'primary',
+ plain: false,
+ round: false,
+ circle: false,
+ loading: false,
+ disabled: false,
+ icon: null,
+ autofocus: false,
+ nativeType: 'button'
+ }
+ }
+ }
+}
+
+export default {
+ get: () => golbalConfig,
+ set: item => {
+ merge(golbalConfig, item)
+ }
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/package/common/filterDic.js b/src/modules/admin/components/Ruoyi/Process/package/common/filterDic.js
new file mode 100644
index 0000000..85faf0c
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/common/filterDic.js
@@ -0,0 +1,15 @@
+export function filterDic(dic, value) {
+ let labelName = 'label'
+ let valueName = 'value'
+ if (dic.data || dic.label || dic.value) {
+ if (dic.label) labelName = dic.label
+ if (dic.value) valueName = dic.value
+ dic = dic.data
+ }
+ if (dic) {
+ for (let i = 0; i < dic.length; i++) {
+ if (dic[i][valueName] === value) return dic[i][labelName]
+ }
+ }
+ return ''
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/package/common/util.js b/src/modules/admin/components/Ruoyi/Process/package/common/util.js
new file mode 100644
index 0000000..2ce20fd
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/common/util.js
@@ -0,0 +1,42 @@
+// 获取动态组件类型
+export function getComponentType(configItem) {
+ const xType = configItem.xType
+ const type = configItem.type
+
+ if (xType === 'slot') {
+ return 'slot'
+ } else if (xType === 'cascader') {
+ return 'xCascader'
+ } else if (xType === 'checkbox') {
+ return 'xCheckbox'
+ } else if (xType === 'colorPicker') {
+ return 'xColorPicker'
+ } else if (xType === 'datePicker') {
+ return 'xDatePicker'
+ } else if (xType === 'input') {
+ return 'xInput'
+ } else if (xType === 'autocomplete') {
+ return 'xAutocomplete'
+ } else if (xType === 'inputNumber') {
+ return 'xInputNumber'
+ } else if (xType === 'radio') {
+ return 'xRadio'
+ } else if (xType === 'rate') {
+ return 'xRate'
+ } else if (xType === 'select') {
+ if (type === 'tree') {
+ return 'xTree'
+ }
+ return 'xSelect'
+ } else if (xType === 'slider') {
+ return 'xSlider'
+ } else if (xType === 'switch') {
+ return 'xSwitch'
+ } else if (xType === 'timePicker') {
+ return 'xTimePicker'
+ } else if (xType === 'timeSelect') {
+ return 'xTimeSelect'
+ } else if (xType === 'transfer') {
+ return 'xTransfer'
+ }
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/package/common/xMixin.js b/src/modules/admin/components/Ruoyi/Process/package/common/xMixin.js
new file mode 100644
index 0000000..3a04292
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/common/xMixin.js
@@ -0,0 +1,114 @@
+import golbalConfig from './config'
+
+export default function() {
+ return {
+ model: {
+ prop: 'modelValue',
+ event: 'input'
+ },
+ props: {
+ config: {
+ type: Object,
+ default: {},
+ required: true
+ },
+ modelValue: {
+ default: undefined
+ }
+ },
+ data() {
+ return {
+ formData: this.modelValue,
+ golbalConfig: golbalConfig.get()
+ }
+ },
+ methods: {
+ /**
+ * 计算出布尔值,并且可以配置默认值
+ */
+ computeBoolen(value, defaultValue) {
+ if (this.isBoolen(value)) return value
+ if (this.isEmpty(value)) {
+ if (defaultValue) {
+ return defaultValue
+ } else {
+ return false
+ }
+ }
+ return true
+ },
+ /**
+ * 如果给属性配置默认值
+ */
+ // computeData(value, defaultValue) {
+ // if (value !== null || value !== undefined) {
+ // return value
+ // }
+ // return defaultValue
+ // },
+ /**
+ * 计算出布尔值,并且可以配置默认值
+ */
+ computeFunction(fun, ...data) {
+ if (fun) {
+ fun(...data)
+ } else {
+ return false
+ }
+ },
+ /**
+ * 判断是否是 空指针,如果是,默认返回 {}
+ */
+ // isDisabled(hasNullPoint, )) {
+ // if(this.isBoolen(value)) return value;
+ // if(this.isEmpty(value)) return false;
+ // if(value == "disabled") return true;
+ // return false;
+ // },
+ /**
+ * 判断是否是 空
+ */
+
+ isEmpty(value) {
+ if (
+ value === 'null' ||
+ value == null ||
+ value === 'undefined' ||
+ value === undefined ||
+ value === ''
+ ) {
+ return true
+ } else {
+ return false
+ }
+ },
+ /**
+ * 判断是否是 boolean
+ */
+ isBoolen(value) {
+ return typeof value === 'boolean'
+ },
+ /**
+ * 判断是否是 对象
+ */
+ isObject(value) {
+ return typeof value === 'object'
+ }
+ },
+ watch: {
+ formData: {
+ handler(val) {
+ this.$emit('input', val)
+ this.$emit('change', val)
+ },
+ deep: true
+ },
+ modelValue: {
+ handler(val) {
+ this.formData = val
+ },
+ deep: true
+ }
+ }
+ }
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/package/index.js b/src/modules/admin/components/Ruoyi/Process/package/index.js
new file mode 100644
index 0000000..389334e
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/index.js
@@ -0,0 +1,20 @@
+import xForm from './xForm/'
+import xTable from './xTable/'
+import golbalConfig from './common/config'
+const components = [
+ xForm,
+ xTable
+]
+
+function install(Vue, opts = {}) {
+ golbalConfig.set(opts)
+ components.map(component => {
+ Vue.component(component.name, component)
+ })
+}
+
+export default {
+ install,
+ xForm,
+ xTable
+}
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/components/xColumn.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/components/xColumn.vue
new file mode 100644
index 0000000..c9e0dee
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/components/xColumn.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ columnConfig.label }}
+
+
+
+
+
+
+
+
+
+ {{ filterTableData(scope.row[columnConfig.name]) }}
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/index.js b/src/modules/admin/components/Ruoyi/Process/package/xForm/index.js
new file mode 100644
index 0000000..41a8528
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/index.js
@@ -0,0 +1,7 @@
+import xForm from './src/xForm'
+
+xForm.install = function(Vue) {
+ Vue.component(xForm.name, xForm)
+}
+
+export default xForm
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xAutocomplete.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xAutocomplete.vue
new file mode 100644
index 0000000..ad062fe
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xAutocomplete.vue
@@ -0,0 +1,74 @@
+
+ computeFunction(computedConfig.blur, e)"
+ @focus="e => computeFunction(computedConfig.focus, e)"
+ @change="e => computeFunction(computedConfig.change, e)"
+ @input="e => computeFunction(computedConfig.input, e)"
+ @clear="e => computeFunction(computedConfig.clear, e)"
+ @select="e => computeFunction(computedConfig.select, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xCascader.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xCascader.vue
new file mode 100644
index 0000000..ead91a8
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xCascader.vue
@@ -0,0 +1,47 @@
+
+ computeFunction(computedConfig.change, e)"
+ @expand-change="e => computeFunction(computedConfig.expandChange, e)"
+ @blur="e => computeFunction(computedConfig.blur, e)"
+ @focus="e => computeFunction(computedConfig.focus, e)"
+ @visible-change="e => computeFunction(computedConfig.visibleChange, e)"
+ @remove-tag="e => computeFunction(computedConfig.removeTag, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xCheckbox.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xCheckbox.vue
new file mode 100644
index 0000000..823b00e
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xCheckbox.vue
@@ -0,0 +1,56 @@
+
+ computeFunction(computedConfig.change, data)"
+ >
+ {{ item[labelName] }}
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xColorPicker.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xColorPicker.vue
new file mode 100644
index 0000000..6e80aac
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xColorPicker.vue
@@ -0,0 +1,35 @@
+
+ computeFunction(computedConfig.change, e)"
+ @active-change="e => computeFunction(computedConfig.activeChange, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xDatePicker.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xDatePicker.vue
new file mode 100644
index 0000000..0f22355
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xDatePicker.vue
@@ -0,0 +1,52 @@
+
+ computeFunction(computedConfig.change, e)"
+ @blur="e => computeFunction(computedConfig.blur, e)"
+ @focus="e => computeFunction(computedConfig.focus, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xForm.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xForm.vue
new file mode 100644
index 0000000..7a48a39
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xForm.vue
@@ -0,0 +1,367 @@
+
+
+ computeFunction(computedConfig.validate, a, b, c)"
+ >
+
+
+
+
+
+ computeFunction(computedConfig.tabs.tabClick, a)"
+ @tab-remove="(a) => computeFunction(computedConfig.tabs.tabRemove, a)"
+ @tab-add="() => computeFunction(computedConfig.tabs.tabAdd)"
+ @edit="(a, b) => computeFunction(computedConfig.tabs.edit, a, b)"
+ >
+
+
+
+ {{ tabConfig.addConfig.text }}
+
+ computeFunction(tabConfig.select, a, b) "
+ @select-all="(a) => computeFunction(tabConfig.selectAll, a) "
+ @selection-change="(a) => computeFunction(tabConfig.selectionChange, a)"
+ @cell-mouse-enter="(a, b, c, d) => computeFunction(tabConfig.cellMouseEnter, a, b, c, d) "
+ @cell-mouse-leave="(a, b, c, d) => computeFunction(tabConfig.cellMouseLeave, a, b, c, d) "
+ @cell-click="(a, b, c, d) => computeFunction(tabConfig.cellClick, a, b, c, d) "
+ @cell-dblclick="(a, b, c, d) => computeFunction(tabConfig.cellDblclick, a, b, c, d) "
+ @row-click="(a, b, c) => computeFunction(tabConfig.rowClick, a, b, c) "
+ @row-contextmenu="(a, b, c) => computeFunction(tabConfig.rowContextmenu, a, b, c) "
+ @row-dblclick="(a, b, c) => computeFunction(tabConfig.rowDblclick, a, b, c) "
+ @header-click="(a, b) => computeFunction(tabConfig.headerClick, a, b) "
+ @header-contextmenu="(a, b) => computeFunction(tabConfig.headerContextmenu, a, b) "
+ @sort-change="(a) => computeFunction(tabConfig.sortChange, a) "
+ @filter-change="(a) => computeFunction(tabConfig.filterChange, a) "
+ @current-change="(a, b) => computeFunction(tabConfig.currentChange, a, b) "
+ @header-dragend="(a, b, c, d) => computeFunction(tabConfig.headerDragend, a, b, c, d) "
+ @expand-change="(a, b) => computeFunction(tabConfig.expandChange, a, b) "
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ btn.text }}
+
+
+
+
+
+
+
+
+
+
+
+ {{ configItem.label }}
+
+
+
+
+ :
+
+
+
+
+
+
+
+
+
+
+ {{ operateItem.text }}
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xInput.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xInput.vue
new file mode 100644
index 0000000..8bf281f
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xInput.vue
@@ -0,0 +1,64 @@
+
+ computeFunction(computedConfig.blur, e)"
+ @focus="e => computeFunction(computedConfig.focus, e)"
+ @change="e => computeFunction(computedConfig.change, e)"
+ @input="e => computeFunction(computedConfig.input, e)"
+ @clear="e => computeFunction(computedConfig.clear, e)"
+ />
+ {{ formData }}
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xInputNumber.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xInputNumber.vue
new file mode 100644
index 0000000..7433851
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xInputNumber.vue
@@ -0,0 +1,43 @@
+
+ computeFunction(computedConfig.change, currentValue, oldValue)"
+ @blur="e => computeFunction(computedConfig.blur, e)"
+ @focus="e => computeFunction(computedConfig.focus, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xRadio.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xRadio.vue
new file mode 100644
index 0000000..0240cb4
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xRadio.vue
@@ -0,0 +1,39 @@
+
+ computeFunction(computedConfig.change, data)"
+ >
+ {{ item.label }}
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xRate.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xRate.vue
new file mode 100644
index 0000000..314c830
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xRate.vue
@@ -0,0 +1,44 @@
+
+ computeFunction(computedConfig.change, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xSelect.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xSelect.vue
new file mode 100644
index 0000000..6ab261e
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xSelect.vue
@@ -0,0 +1,75 @@
+
+ computeFunction(computedConfig.change, data)"
+ @visible-change="data => computeFunction(computedConfig.visibleChange, data)"
+ @remove-tag="data => computeFunction(computedConfig.removeTag, data)"
+ @clear="data => computeFunction(computedConfig.clear, data)"
+ @blur="data => computeFunction(computedConfig.blur, data)"
+ @focus="data => computeFunction(computedConfig.focus, data)"
+ >
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xSlider.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xSlider.vue
new file mode 100644
index 0000000..9836b7d
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xSlider.vue
@@ -0,0 +1,46 @@
+
+ computeFunction(computedConfig.change, e)"
+ @input="e => computeFunction(computedConfig.input, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xSwitch.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xSwitch.vue
new file mode 100644
index 0000000..4f35065
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xSwitch.vue
@@ -0,0 +1,40 @@
+
+ computeFunction(computedConfig.change, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTimePicker.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTimePicker.vue
new file mode 100644
index 0000000..996340f
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTimePicker.vue
@@ -0,0 +1,52 @@
+
+ computeFunction(computedConfig.change, e)"
+ @blur="e => computeFunction(computedConfig.blur, e)"
+ @focus="e => computeFunction(computedConfig.focus, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTimeSelect.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTimeSelect.vue
new file mode 100644
index 0000000..fbfa451
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTimeSelect.vue
@@ -0,0 +1,55 @@
+
+ computeFunction(computedConfig.change, e)"
+ @blur="e => computeFunction(computedConfig.blur, e)"
+ @focus="e => computeFunction(computedConfig.focus, e)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTransfer.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTransfer.vue
new file mode 100644
index 0000000..f17ea0e
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTransfer.vue
@@ -0,0 +1,43 @@
+
+ computeFunction(computedConfig.change, a, b, c)"
+ @left-check-change="(a, b) => computeFunction(computedConfig.blur, a, b)"
+ @right-check-change="(a, b) => computeFunction(computedConfig.blur, a, b)"
+ />
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTree.vue b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTree.vue
new file mode 100644
index 0000000..4072dfe
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xForm/src/xTree.vue
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+ {{ data[getTreeProps.label] }}
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xTable/index.js b/src/modules/admin/components/Ruoyi/Process/package/xTable/index.js
new file mode 100644
index 0000000..b90df36
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xTable/index.js
@@ -0,0 +1,7 @@
+import xTable from './src/xTable'
+
+xTable.install = function(Vue) {
+ Vue.component(xTable.name, xTable)
+}
+
+export default xTable
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xTable/src/xColumn.vue b/src/modules/admin/components/Ruoyi/Process/package/xTable/src/xColumn.vue
new file mode 100644
index 0000000..f829164
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xTable/src/xColumn.vue
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/Process/package/xTable/src/xTable.vue b/src/modules/admin/components/Ruoyi/Process/package/xTable/src/xTable.vue
new file mode 100644
index 0000000..8a88a30
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/Process/package/xTable/src/xTable.vue
@@ -0,0 +1,330 @@
+
+
+
+
+ computeFunction(computedConfig.select, a, b) "
+ @select-all="(a) => computeFunction(computedConfig.selectAll, a) "
+ @selection-change="(a) => computeFunction(computedConfig.selectionChange, a)"
+ @cell-mouse-enter="(a, b, c, d) => computeFunction(computedConfig.cellMouseEnter, a, b, c, d) "
+ @cell-mouse-leave="(a, b, c, d) => computeFunction(computedConfig.cellMouseLeave, a, b, c, d) "
+ @cell-click="(a, b, c, d) => computeFunction(computedConfig.cellClick, a, b, c, d) "
+ @cell-dblclick="(a, b, c, d) => computeFunction(computedConfig.cellDblclick, a, b, c, d) "
+ @row-click="(a, b, c) => computeFunction(computedConfig.rowClick, a, b, c) "
+ @row-contextmenu="(a, b, c) => computeFunction(computedConfig.rowContextmenu, a, b, c) "
+ @row-dblclick="(a, b, c) => computeFunction(computedConfig.rowDblclick, a, b, c) "
+ @header-click="(a, b) => computeFunction(computedConfig.headerClick, a, b) "
+ @header-contextmenu="(a, b) => computeFunction(computedConfig.headerContextmenu, a, b) "
+ @sort-change="(a) => computeFunction(computedConfig.sortChange, a) "
+ @filter-change="(a) => computeFunction(computedConfig.filterChange, a) "
+ @current-change="(a, b) => computeFunction(computedConfig.currentChange, a, b) "
+ @header-dragend="(a, b, c, d) => computeFunction(computedConfig.headerDragend, a, b, c, d) "
+ @expand-change="(a, b) => computeFunction(computedConfig.expandChange, a, b) "
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ operateItem.text }}
+
+
+
+
+ handleDropdownCommand(index, scope.row)"
+ >
+
+ {{ operateConfig.dropdown.config.text }}
+
+
+
+
+
+ {{ dropdownBtnItem.text }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/components/Ruoyi/iFrame/index.vue b/src/modules/admin/components/Ruoyi/iFrame/index.vue
new file mode 100644
index 0000000..173b197
--- /dev/null
+++ b/src/modules/admin/components/Ruoyi/iFrame/index.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
diff --git a/src/modules/admin/config/index.ts b/src/modules/admin/config/index.ts
new file mode 100644
index 0000000..ecd63a8
--- /dev/null
+++ b/src/modules/admin/config/index.ts
@@ -0,0 +1,2 @@
+// * 默认主题颜色
+export const PRIMARY_COLOR: string = "#409eff";
diff --git a/src/modules/admin/hooks/theme/useInitTheme.ts b/src/modules/admin/hooks/theme/useInitTheme.ts
new file mode 100644
index 0000000..0c4b0bb
--- /dev/null
+++ b/src/modules/admin/hooks/theme/useInitTheme.ts
@@ -0,0 +1,7 @@
+import { useThemeChange } from "@admin/hooks/theme/useThemeChange";
+
+export function useInitTheme() {
+ const { switchDark, changePrimary } = useThemeChange();
+ switchDark()
+ changePrimary()
+}
\ No newline at end of file
diff --git a/src/modules/admin/hooks/theme/useThemeChange.ts b/src/modules/admin/hooks/theme/useThemeChange.ts
new file mode 100644
index 0000000..8351d53
--- /dev/null
+++ b/src/modules/admin/hooks/theme/useThemeChange.ts
@@ -0,0 +1,33 @@
+import { ref } from "vue";
+import { ElMessage } from "element-plus";
+import { PRIMARY_COLOR } from "@admin/config/index";
+import { useSettingStore } from "@admin/store/modules/setting"
+
+
+
+export function useThemeChange() {
+ const SettingStore = useSettingStore()
+ const primary = ref(SettingStore.themeConfig.primary)
+
+ // 进行配置
+ const changeSwitch = (key: string, val: any) => {
+ SettingStore.setThemeConfig({key, val})
+ }
+ /** 日间、夜间主题切换 */
+ function switchDark () {
+ const body = document.documentElement as HTMLElement;
+ if (SettingStore.themeConfig.isDark) body.setAttribute("class", "dark");
+ else body.setAttribute("class", "");
+ }
+ /* 修改主题颜色 */
+ function changePrimary (val?: string){
+ const primary_color = val || primary.value || PRIMARY_COLOR;
+ document.documentElement.style.setProperty("--el-color-primary", primary_color);
+ changeSwitch('primary',primary_color)
+ }
+ return {
+ primary,
+ switchDark,
+ changePrimary
+ }
+}
\ No newline at end of file
diff --git a/src/modules/admin/hooks/useFullscreen.ts b/src/modules/admin/hooks/useFullscreen.ts
new file mode 100644
index 0000000..73fd158
--- /dev/null
+++ b/src/modules/admin/hooks/useFullscreen.ts
@@ -0,0 +1,136 @@
+/**
+ * @description 方法用来切换元素 进入全屏
+ * @vueuse/core 提供了 useFullscreen 方法,因此项目中采用 useFullscreen,实现效果功能是一样得,目的是为了减少代码量
+ * 它原理原理实现如下:
+ */
+
+import { ElMessage } from "element-plus";
+import { onMounted } from "vue";
+
+declare global {
+ interface Document {
+ mozFullScreenEnabled: boolean;
+ mozFullScreenElement: Element | null;
+ webkitFullscreenEnabled: boolean;
+ webkitFullscreenElement: Element | null;
+ msFullscreenEnabled: boolean;
+ msFullscreenElement: Element | null;
+ }
+}
+
+export const useFullscreen = () => {
+ /**
+ * @description: 是否支持全屏+判断浏览器前缀
+ */
+ const isFullscreen = () => {
+ let prefixName = ""; // 浏览器前缀
+ let fullscreenEnabled = false;
+
+ // 判断浏览器前缀
+ if (document.fullscreenEnabled) {
+ fullscreenEnabled = document.fullscreenEnabled;
+ // webkit
+ } else if (document.webkitFullscreenEnabled) {
+ fullscreenEnabled = document.webkitFullscreenEnabled;
+ prefixName = "webkit";
+ // moz
+ } else if (document.mozFullScreenEnabled) {
+ fullscreenEnabled = document.mozFullScreenEnabled;
+ prefixName = "moz";
+ // ms
+ } else if (document.msFullscreenEnabled) {
+ fullscreenEnabled = document.msFullscreenEnabled;
+ prefixName = "ms";
+ }
+
+ return {
+ fullscreenEnabled,
+ prefixName
+ }
+ }
+
+
+ /**
+ * @description: 检测有没有元素处于全屏状态
+ * @return 布尔值
+ */
+ const isElementFullScreen = () => {
+ const fullscreenElement =
+ document.fullscreenElement ||
+ document.msFullscreenElement ||
+ document.mozFullScreenElement ||
+ document.webkitFullscreenElement;
+ if (fullscreenElement === null) {
+ return false; // 当前没有元素在全屏状态
+ } else {
+ return true; // 有元素在全屏状态
+ }
+ }
+
+ /**
+ * @description: 将传进来的元素全屏
+ * @param {String} domName 要全屏的dom名称
+ */
+ const Fullscreen = (target) => {
+ const targetRef = target || (document == null ? void 0 : document.querySelector("html"));
+ const { prefixName } = isFullscreen()
+ const methodName =
+ prefixName === ""
+ ? "requestFullscreen"
+ : `${prefixName}RequestFullScreen`;
+ targetRef[methodName]();
+ }
+
+ // 退出全屏
+ const exitFullscreen = () => {
+ const { prefixName } = isFullscreen()
+ const methodName =
+ prefixName === ""
+ ? "exitFullscreen"
+ : `${prefixName}ExitFullscreen`;
+ document[methodName]();
+ }
+
+ /**
+ * @description: 浏览器无法进入全屏时触发,可能是技术原因,也可能是用户拒绝:比如全屏请求不是在事件处理函数中调用,会在这里拦截到错误
+ * @param {Function} enterErrorFn 回调
+ */
+ const screenError = () => {
+ const { prefixName } = isFullscreen()
+ const methodName = `on${prefixName}fullscreenerror`;
+ document[methodName] = e => {
+ ElMessage.error('进入全屏失败')
+ };
+ }
+
+ /**
+ * @description: 监听进入/离开全屏
+ * @param {Function} enter 进入全屏的回调
+ * @param {Function} quit 离开全屏的回调
+ */
+ const screenChange = (enter, quit) => {
+ const { fullscreenEnabled, prefixName } = isFullscreen()
+ if (!fullscreenEnabled) return;
+ const methodName = `on${prefixName}fullscreenchange`;
+ document[methodName] = e => {
+ if (isElementFullScreen()) {
+ enter && enter(e); // 进入全屏回调
+ } else {
+ quit && quit(e); // 离开全屏的回调
+ }
+ };
+ }
+
+ onMounted(() => {
+ screenError()
+ })
+
+
+ return {
+ isFullscreen,
+ isElementFullScreen,
+ Fullscreen,
+ exitFullscreen,
+ screenChange
+ }
+}
diff --git a/src/modules/admin/hooks/useResizeElement.ts b/src/modules/admin/hooks/useResizeElement.ts
new file mode 100644
index 0000000..5d7b119
--- /dev/null
+++ b/src/modules/admin/hooks/useResizeElement.ts
@@ -0,0 +1,39 @@
+import ResizeObserver from "resize-observer-polyfill";
+import { onBeforeUnmount } from "vue";
+import requestAnimationFrameThrottle from "@admin/utils/requestAnimationFrameThrottle"
+export const useResizeElement = (chart, chartsRef)=>{
+ let observer = null ;
+ let widthW = 0;
+ let heightW = 0;
+ const handleResize = (entries )=>{
+ const { contentRect } = entries[0];
+ let {width,height} = contentRect
+ width = Math.floor(width);
+ height = Math.floor(height);
+ if(widthW!==width|| heightW !== height){
+ widthW = width
+ heightW = height
+ chart && chart.resize()
+ }
+ }
+ const addObserver = ()=>{
+ observer = new ResizeObserver(requestAnimationFrameThrottle(handleResize))
+ observer.observe(chartsRef)
+ }
+
+ const removeObserver = ()=>{
+ if (observer) {
+ observer.disconnect();
+ observer = null;
+ }
+ chart&&chart.dispose()
+ }
+
+ onBeforeUnmount(()=>{
+ removeObserver()
+ })
+
+ return{
+ addObserver
+ }
+}
diff --git a/src/modules/admin/hooks/useResizeHandler.ts b/src/modules/admin/hooks/useResizeHandler.ts
new file mode 100644
index 0000000..fa2fbe9
--- /dev/null
+++ b/src/modules/admin/hooks/useResizeHandler.ts
@@ -0,0 +1,70 @@
+import { useSettingStore } from "@admin/store/modules/setting"
+import { computed, onMounted, onUnmounted, watch } from "vue";
+import { useRoute } from "vue-router";
+
+const { body } = document
+
+const WIDTH = 768 // refer to Bootstrap's responsive design
+const MAX_WIDTH = 1200
+
+export const useResizeHandler = () => {
+ const SettingStore = useSettingStore()
+ const route = useRoute()
+ const device = computed(() => {
+ return SettingStore.device
+ })
+ function $_isMobile() {
+ const rect = body.getBoundingClientRect()
+ return rect.width - 1 < WIDTH
+ }
+
+ function collapse() {
+ const rect = body.getBoundingClientRect()
+ if (rect.width - 1 > MAX_WIDTH) {
+ return true
+ } else {
+ return false
+ }
+
+ }
+
+ function $_resizeHandler() {
+ if (!document.hidden) { // bool型,表示页面是否处于隐藏状态。页面隐藏包括页面在后台标签页或者浏览器最小化
+ const isMobile = $_isMobile()
+ const isCollapse = collapse()
+ SettingStore.toggleDevice(isMobile ? 'mobile' : 'desktop')
+
+
+ if (isMobile) {
+ SettingStore.closeSideBar({ withoutAnimation: true })
+ }
+
+ if (!isMobile) {
+ SettingStore.setCollapse(isCollapse)
+ }
+
+
+ }
+ }
+ onMounted(() => {
+ const isMobile = $_isMobile()
+ if (isMobile) {
+ SettingStore.toggleDevice('mobile')
+ SettingStore.closeSideBar({ withoutAnimation: true })
+ }
+ window.addEventListener('resize', $_resizeHandler)
+
+ watch(route, () => {
+ if (device.value === 'mobile' && SettingStore.isCollapse) {
+ SettingStore.closeSideBar({ withoutAnimation: false })
+ }
+ })
+ })
+
+ onUnmounted(() => {
+ window.removeEventListener('resize', $_resizeHandler)
+ })
+
+
+ return { device }
+}
diff --git a/src/modules/admin/hooks/useWrapComponents.ts b/src/modules/admin/hooks/useWrapComponents.ts
new file mode 100644
index 0000000..f25b800
--- /dev/null
+++ b/src/modules/admin/hooks/useWrapComponents.ts
@@ -0,0 +1,23 @@
+// 自定义name的壳的集合
+import { h } from "vue";
+
+const wrapperMap = new Map()
+
+export const useWrapComponents = (Component, route) => {
+ let wrapper
+ if (Component) {
+ const wrapperName = route.name
+ if (wrapperMap.has(wrapperName)) {
+ wrapper = wrapperMap.get(wrapperName)
+ } else {
+ wrapper = {
+ name: wrapperName,
+ render() {
+ return h("div", { className: "app-main-inner" }, Component)
+ },
+ }
+ wrapperMap.set(wrapperName, wrapper)
+ }
+ return h(wrapper)
+ }
+}
diff --git a/src/modules/admin/hooks/web/useScript.ts b/src/modules/admin/hooks/web/useScript.ts
new file mode 100644
index 0000000..9707116
--- /dev/null
+++ b/src/modules/admin/hooks/web/useScript.ts
@@ -0,0 +1,46 @@
+import { onMounted, onUnmounted, ref } from 'vue';
+
+interface ScriptOptions {
+ src: string;
+}
+
+export function useScript(opts: ScriptOptions) {
+ const isLoading = ref(false);
+ const error = ref(false);
+ const success = ref(false);
+ let script: HTMLScriptElement;
+
+ const promise = new Promise((resolve, reject) => {
+ onMounted(() => {
+ script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.onload = function () {
+ isLoading.value = false;
+ success.value = true;
+ error.value = false;
+ resolve('');
+ };
+
+ script.onerror = function (err) {
+ isLoading.value = false;
+ success.value = false;
+ error.value = true;
+ reject(err);
+ };
+
+ script.src = opts.src;
+ document.head.appendChild(script);
+ });
+ });
+
+ onUnmounted(() => {
+ script && script.remove();
+ });
+
+ return {
+ isLoading,
+ error,
+ success,
+ toPromise: () => promise,
+ };
+}
diff --git a/src/modules/admin/index.html b/src/modules/admin/index.html
new file mode 100644
index 0000000..2f9d14c
--- /dev/null
+++ b/src/modules/admin/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/LayoutColumns/index.vue b/src/modules/admin/layout/LayoutColumns/index.vue
new file mode 100644
index 0000000..f148f46
--- /dev/null
+++ b/src/modules/admin/layout/LayoutColumns/index.vue
@@ -0,0 +1,223 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ isCollapse ? "D" : SYS_NAME }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/LayoutHorizontal/HeaderHorizontal/index.scss b/src/modules/admin/layout/LayoutHorizontal/HeaderHorizontal/index.scss
new file mode 100644
index 0000000..88a2f78
--- /dev/null
+++ b/src/modules/admin/layout/LayoutHorizontal/HeaderHorizontal/index.scss
@@ -0,0 +1,37 @@
+.m-layout-header {
+ width: 100%;
+ transition: width 0.28s;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
+ .header-inner {
+ height: 50px;
+ width: 100%;
+ border-bottom: 1px solid #eee;
+ display: flex;
+ background-color:$menuBg;
+ align-items: center;
+ padding: 0 10px 0 0;
+ box-sizing: border-box;
+ justify-content: space-between;
+ }
+}
+.fixed-header{
+ position: fixed;
+ top: 0;
+ right: 0;
+ z-index: 9;
+}
+
+.menu-horizontal{
+ flex: 1;
+ overflow: hidden;
+ height: 100%;
+ margin-right:20px;
+ :deep(.el-menu-item){
+ height: 100%;
+ }
+}
+
+
+
diff --git a/src/modules/admin/layout/LayoutHorizontal/HeaderHorizontal/index.vue b/src/modules/admin/layout/LayoutHorizontal/HeaderHorizontal/index.vue
new file mode 100644
index 0000000..574c15e
--- /dev/null
+++ b/src/modules/admin/layout/LayoutHorizontal/HeaderHorizontal/index.vue
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/LayoutHorizontal/index.vue b/src/modules/admin/layout/LayoutHorizontal/index.vue
new file mode 100644
index 0000000..cd3f6ed
--- /dev/null
+++ b/src/modules/admin/layout/LayoutHorizontal/index.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/LayoutVertical/HeaderVertical/index.scss b/src/modules/admin/layout/LayoutVertical/HeaderVertical/index.scss
new file mode 100644
index 0000000..c439d3f
--- /dev/null
+++ b/src/modules/admin/layout/LayoutVertical/HeaderVertical/index.scss
@@ -0,0 +1,70 @@
+.mobile {
+ .m-layout-header {
+ left: 0 !important;
+ width: 100%!important;
+ }
+}
+.show-tag{
+ height: 90px;
+}
+
+
+.zb-no-fixed-header{
+ width: 100%!important;;
+}
+
+.m-layout-header {
+ width: 100%;
+ background: white;
+ transition: width 0.28s;
+ flex-shrink: 0;
+ box-sizing: border-box;
+ box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
+
+ .header-inner {
+ height: 50px;
+ width: 100%;
+ border-bottom: 1px solid #eee;
+ display: flex;
+ align-items: center;
+ padding: 0 10px 0 0;
+ box-sizing: border-box;
+ justify-content: space-between;
+ }
+}
+.fixed-header{
+ position: fixed;
+ top: 0;
+ right: 0;
+ z-index: 9;
+}
+.header-collapse{
+ width: calc(100% - 60px);
+}
+.no-collapse{
+ width: calc(100% - 210px);
+}
+
+
+
+.el-dropdown {
+ display: flex;
+ height: 100%;
+ align-items: center;
+}
+
+.transverseMenu{
+ display: flex;
+ .el-menu{
+ overflow: hidden;
+ }
+ :deep(.el-menu-item){
+ height: 100% !important;
+ }
+ .tool-bar-right{
+ display: flex;
+ justify-content: flex-end;
+ min-width:300px ;
+ flex-shrink: 0;
+ }
+}
diff --git a/src/modules/admin/layout/LayoutVertical/HeaderVertical/index.vue b/src/modules/admin/layout/LayoutVertical/HeaderVertical/index.vue
new file mode 100644
index 0000000..6496731
--- /dev/null
+++ b/src/modules/admin/layout/LayoutVertical/HeaderVertical/index.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/LayoutVertical/index.vue b/src/modules/admin/layout/LayoutVertical/index.vue
new file mode 100644
index 0000000..e3c6a67
--- /dev/null
+++ b/src/modules/admin/layout/LayoutVertical/index.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Footer/index.vue b/src/modules/admin/layout/components/Footer/index.vue
new file mode 100644
index 0000000..e82a9de
--- /dev/null
+++ b/src/modules/admin/layout/components/Footer/index.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/ToolLeft.vue b/src/modules/admin/layout/components/Header/ToolLeft.vue
new file mode 100644
index 0000000..239d5f3
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/ToolLeft.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/ToolRight.vue b/src/modules/admin/layout/components/Header/ToolRight.vue
new file mode 100644
index 0000000..b304f8a
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/ToolRight.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/Avatar.vue b/src/modules/admin/layout/components/Header/components/Avatar.vue
new file mode 100644
index 0000000..2381a56
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/Avatar.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+ {{ userInfo.nickName }}
+
+
+
+
+
+ 个人中心
+
+
+
+
+ 退出登录
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/CollapseIcon.vue b/src/modules/admin/layout/components/Header/components/CollapseIcon.vue
new file mode 100644
index 0000000..1f513bd
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/CollapseIcon.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/Hamburger.vue b/src/modules/admin/layout/components/Header/components/Hamburger.vue
new file mode 100644
index 0000000..46c0da7
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/Hamburger.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
+ 首页
+
+
+
+ {{ item.meta.title }}
+ {{ item.meta.title }}
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/HeaderSearch.vue b/src/modules/admin/layout/components/Header/components/HeaderSearch.vue
new file mode 100644
index 0000000..6718a64
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/HeaderSearch.vue
@@ -0,0 +1,171 @@
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/Height.vue b/src/modules/admin/layout/components/Header/components/Height.vue
new file mode 100644
index 0000000..0bed005
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/Height.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/Link.vue b/src/modules/admin/layout/components/Header/components/Link.vue
new file mode 100644
index 0000000..a8e2fae
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/Link.vue
@@ -0,0 +1,12 @@
+
+
+
+ 项目管理系统
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/layout/components/Header/components/PersonalDialog.vue b/src/modules/admin/layout/components/Header/components/PersonalDialog.vue
new file mode 100644
index 0000000..efa4a60
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/PersonalDialog.vue
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/Remind.vue b/src/modules/admin/layout/components/Header/components/Remind.vue
new file mode 100644
index 0000000..cc36d62
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/Remind.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 通知1
+
+
+ 通知2
+
+
+ 通知3
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/ScreenFull.vue b/src/modules/admin/layout/components/Header/components/ScreenFull.vue
new file mode 100644
index 0000000..f1b8356
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/ScreenFull.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/Setting.vue b/src/modules/admin/layout/components/Header/components/Setting.vue
new file mode 100644
index 0000000..c6fa9aa
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/Setting.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Header/components/globalComSize.vue b/src/modules/admin/layout/components/Header/components/globalComSize.vue
new file mode 100644
index 0000000..2596fc8
--- /dev/null
+++ b/src/modules/admin/layout/components/Header/components/globalComSize.vue
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ {{ assemblySizeListCh[item] }}
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Main/index.vue b/src/modules/admin/layout/components/Main/index.vue
new file mode 100644
index 0000000..d4ce51b
--- /dev/null
+++ b/src/modules/admin/layout/components/Main/index.vue
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Mobile/index.vue b/src/modules/admin/layout/components/Mobile/index.vue
new file mode 100644
index 0000000..3618988
--- /dev/null
+++ b/src/modules/admin/layout/components/Mobile/index.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Sidebar/components/Logo.vue b/src/modules/admin/layout/components/Sidebar/components/Logo.vue
new file mode 100644
index 0000000..ae258f1
--- /dev/null
+++ b/src/modules/admin/layout/components/Sidebar/components/Logo.vue
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/Sidebar/index.vue b/src/modules/admin/layout/components/Sidebar/index.vue
new file mode 100644
index 0000000..3ce0a06
--- /dev/null
+++ b/src/modules/admin/layout/components/Sidebar/index.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/SubMenu/MenuItem.vue b/src/modules/admin/layout/components/SubMenu/MenuItem.vue
new file mode 100644
index 0000000..b00332d
--- /dev/null
+++ b/src/modules/admin/layout/components/SubMenu/MenuItem.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+ {{ subItem?.meta?.title }}
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/SubMenu/SubMenu.vue b/src/modules/admin/layout/components/SubMenu/SubMenu.vue
new file mode 100644
index 0000000..fb652d8
--- /dev/null
+++ b/src/modules/admin/layout/components/SubMenu/SubMenu.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ subItem?.meta?.title }}
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/TagsView/components/MoreButton.vue b/src/modules/admin/layout/components/TagsView/components/MoreButton.vue
new file mode 100644
index 0000000..070afeb
--- /dev/null
+++ b/src/modules/admin/layout/components/TagsView/components/MoreButton.vue
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
+ 刷新当页
+ 关闭当前
+ 关闭其他
+ 关闭所有
+
+
+
+
+
+
diff --git a/src/modules/admin/layout/components/TagsView/index.vue b/src/modules/admin/layout/components/TagsView/index.vue
new file mode 100644
index 0000000..33c61c0
--- /dev/null
+++ b/src/modules/admin/layout/components/TagsView/index.vue
@@ -0,0 +1,167 @@
+
+
+
+
+
diff --git a/src/modules/admin/layout/index.vue b/src/modules/admin/layout/index.vue
new file mode 100644
index 0000000..0b3c63f
--- /dev/null
+++ b/src/modules/admin/layout/index.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/main.ts b/src/modules/admin/main.ts
new file mode 100644
index 0000000..a4c8626
--- /dev/null
+++ b/src/modules/admin/main.ts
@@ -0,0 +1,38 @@
+import "@/styles/tailwind/index.scss"
+import { createApp } from 'vue'
+import App from './App.vue'
+import router from './routers'
+import pinia from "./store";
+
+import {registerElIcons} from "@admin/utils/element/ElIcons"
+// 引入全局组件布局
+import PageWrapLayout from '@admin/components/Layout/PageWrapLayout/index.vue'
+// 权限路由
+import './permission'
+// svg-icons注册导入
+import 'virtual:svg-icons-register'
+import SvgIcon from '@lib/components/icons/SvgIcon/index.vue'// svg component
+// UI框架 element-plus
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+// 引入暗黑模式 element-plus 2.2 内置暗黑模式
+import 'element-plus/theme-chalk/dark/css-vars.css'
+// 自定义暗黑模式
+import "@/styles/element-dark.scss";
+import "@/styles/public/index.scss";
+// 引入阿里图标库
+import "@admin/assets/iconfont/iconfont.css";
+import "@admin/assets/iconfont/iconfont.js";
+
+import global from '@admin/components/Global'
+const app = createApp(App)
+app.use(pinia)
+registerElIcons(app)
+
+app.component('svg-icon',SvgIcon)
+app.component('PageWrapLayout',PageWrapLayout)
+
+app.use(router)
+app.use(ElementPlus)
+global(app)
+app.mount('#app')
diff --git a/src/modules/admin/permission.ts b/src/modules/admin/permission.ts
new file mode 100644
index 0000000..3919cbb
--- /dev/null
+++ b/src/modules/admin/permission.ts
@@ -0,0 +1,67 @@
+import router from '@admin/routers/index'
+import NProgress from 'nprogress'
+import 'nprogress/nprogress.css'
+import { useUserStore } from "@admin/store/modules/user"
+import { usePermissionStore } from "@admin/store/modules/permission"
+import await_to from 'await-to-js'
+
+NProgress.configure({ showSpinner: false }) // NProgress Configuration
+
+const whiteList = ['/login', '/auth-redirect'] // 设置白名单
+
+router.beforeEach(async (to, from, next) => {
+ // 开启进度条
+ NProgress.start()
+ // 设置标题
+ if (typeof (to.meta.title) === 'string') {
+ document.title = to.meta.title || import.meta.env.VITE_SYS_NAME
+ }
+
+ const UserStore = useUserStore();
+ // 确定用户是否已登录过,存在Token
+ const hasToken = UserStore.token
+ if (hasToken) {
+ if (to.path === '/login') {
+ // 如果已登录,请重定向到主页
+ next({ path: '/' })
+ } else {
+ try {
+ if (UserStore.roles.length !== 0) {
+ next()
+ return
+ }
+ const [err] = await await_to(UserStore.getInfo())
+ if(err) {
+ UserStore.logout().then(() => { next({ path: '/' }) })
+ return
+ }
+ const PermissionStore = usePermissionStore()
+ if (!PermissionStore.routes.length) {
+ const accessRoutes = await PermissionStore.generateRoutes(UserStore.roles)
+ accessRoutes.forEach(item => {
+ // 动态添加访问路由表
+ router.addRoute(item)
+ })
+ next({ ...to, replace: true })
+ } else {
+ next()
+ }
+ } catch (error) {
+ console.error(error)
+ next(`/login?redirect=${to.path}`)
+ }
+ }
+ } else {
+ if (whiteList.indexOf(to.path) !== -1) {
+ next()
+ } else {
+ next(`/login?redirect=${to.path}`)
+ }
+ }
+})
+
+router.afterEach(() => {
+ NProgress.done();
+});
+
+
diff --git a/src/modules/admin/routers/index.ts b/src/modules/admin/routers/index.ts
new file mode 100644
index 0000000..b6b2f72
--- /dev/null
+++ b/src/modules/admin/routers/index.ts
@@ -0,0 +1,130 @@
+import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
+import Layout from "@admin/layout/index.vue";
+import { useUserStore } from "@admin/store/modules/user";
+// 扩展继承属性
+interface extendRoute {
+ hidden?: boolean
+}
+
+import systemRouter from './modules/system'
+
+// 异步组件
+export const asyncRoutes = [
+ ...systemRouter,
+]
+
+/**
+ * path ==> 路由路径
+ * name ==> 路由名称
+ * component ==> 路由组件
+ * redirect ==> 路由重定向
+ * alwaysShow ==> 如果设置为true,将始终显示根菜单,无论其子路由长度如何
+ * hidden ==> 如果“hidden:true”不会显示在侧边栏中(默认值为false)
+ * keepAlive ==> 设为true 缓存
+ * meta ==> 路由元信息
+ * meta.title ==> 路由标题
+ * meta.icon ==> 菜单icon
+ * meta.affix ==> 如果设置为true将会出现在 标签栏中
+ * meta.breadcrumb ==> 如果设置为false,该项将隐藏在breadcrumb中(默认值为true)
+ */
+
+export const constantRoutes: Array = [
+ {
+ path: "/404",
+ name: "404",
+ component: () => import("@admin/views/system/error/404.vue"),
+ hidden: true,
+ },
+ {
+ path: "/403",
+ name: "403",
+ component: () => import("@admin/views/system/error/403.vue"),
+ hidden: true,
+ },
+ {
+ path: '/login',
+ name: 'Login',
+ component: () => import('@admin/views/login/index.vue'),
+ hidden: true,
+ meta: { title: '登录', }
+ },
+ {
+ path: '/',
+ name: 'layout',
+ component: Layout,
+ redirect: '/home',
+ meta: { title: '首页', icon: 'House', },
+ children: [
+ {
+ path: '/home',
+ component: () => import('@admin/views/home/index.vue'),
+ name: 'home',
+ meta: { title: '首页', icon: 'House', affix: true, role: ['other'] }
+ },
+ ]
+ },
+ {
+ path: '/',
+ component: Layout,
+ hidden: true,
+ children: [
+ {
+ path: '/profile',
+ component: () => import('@admin/views/system/profile/index.vue'),
+ name: 'profile',
+ meta: { title: '个人中心' }
+ },
+ ]
+ },
+ {
+ path: '/common',
+ component: Layout,
+ hidden: true,
+ children: [
+ {
+ path: "/common/404",
+ name: "layout_404",
+ component: () => import("@admin/views/system/error/404.vue"),
+ meta: { title: '404' }
+ },
+ {
+ path: "/common/403",
+ name: "layout_403",
+ component: () => import("@admin/views/system/error/403.vue"),
+ meta: { title: '403' }
+ },
+ ]
+ },
+ {
+ path: '/flowable',
+ component: Layout,
+ hidden: true,
+ children: [
+ {
+ path: '/flowable/editor/edit',
+ component: () => import('@admin/views/tool/flowable/editor/edit/index.vue'),
+ name: 'flowable_editor',
+ meta: { title: '在线编辑', activeMenu: '/flowable/editor/edit' },
+ },
+ ]
+ },
+]
+
+export const notFoundRouter = [
+ {
+ path: '/:pathMatch(.*)',
+ name: "notFound",
+ redirect: () => {
+ const userStore = useUserStore()
+ return { path: userStore.token ? '/common/404' : '/404' }
+ },
+ }
+]
+
+
+const router = createRouter({
+ history: createWebHistory('/admin'),
+ routes: constantRoutes
+})
+
+export default router
diff --git a/src/modules/admin/routers/modules/system.ts b/src/modules/admin/routers/modules/system.ts
new file mode 100644
index 0000000..658b65b
--- /dev/null
+++ b/src/modules/admin/routers/modules/system.ts
@@ -0,0 +1,35 @@
+import Layout from '@admin/layout/index.vue'
+
+const systemRouter = [
+ {
+ path: '/system',
+ component: Layout,
+ meta: { title: '系统管理', icon: 'Setting', },
+ children: [
+ {
+ path: '/system/dict/data/:dictId(\\d+)',
+ component: () => import('@admin/views/system/dict/dictData/index.vue'),
+ name: 'dictData',
+ hidden: true,
+ permissions: ['system:dict:list'],
+ meta: { title: '字典数据', activeMenu: '/system/dict' },
+ },
+ ]
+ },
+ {
+ path: '/monitor',
+ component: Layout,
+ meta: { title: '系统监控', icon: 'Setting', },
+ children: [
+ {
+ path: '/monitor/job/log/:jobId(\\d+)',
+ component: () => import('@admin/views/monitor/job/log/index.vue'),
+ permissions: ['monitor:job:list'],
+ name: 'JobLog',
+ meta: { title: '调度日志', activeMenu: '/monitor/job' }
+ },
+ ]
+ },
+]
+
+export default systemRouter
diff --git a/src/modules/admin/store/index.ts b/src/modules/admin/store/index.ts
new file mode 100644
index 0000000..4c7caec
--- /dev/null
+++ b/src/modules/admin/store/index.ts
@@ -0,0 +1,23 @@
+import { fa } from 'element-plus/es/locale';
+import { defineStore, createPinia } from 'pinia'
+// 引入持久化插件
+import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
+
+export const Store = defineStore({
+ id: 'globalState',
+ state: () => ({
+ isLoading: false,
+ }),
+ getters: {},
+ actions: {},
+ persist: {
+ key: "globalState",
+ storage: window.sessionStorage,
+ },
+})
+
+
+const pinia = createPinia();
+//pinia使用
+pinia.use(piniaPluginPersistedstate);
+export default pinia
diff --git a/src/modules/admin/store/modules/dict.ts b/src/modules/admin/store/modules/dict.ts
new file mode 100644
index 0000000..3be27b4
--- /dev/null
+++ b/src/modules/admin/store/modules/dict.ts
@@ -0,0 +1,58 @@
+import { defineStore } from 'pinia'
+const useDictStore = defineStore(
+ 'dict',
+ {
+ state: () => ({
+ dict: new Array()
+ }),
+ actions: {
+ // 获取字典
+ getDict(_key) {
+ if (_key == null && _key == "") {
+ return null;
+ }
+ try {
+ for (let i = 0; i < this.dict.length; i++) {
+ if (this.dict[i].key == _key) {
+ return this.dict[i].value;
+ }
+ }
+ } catch (e) {
+ return null;
+ }
+ },
+ // 设置字典
+ setDict(_key, value) {
+ if (_key !== null && _key !== "") {
+ this.dict.push({
+ key: _key,
+ value: value
+ });
+ }
+ },
+ // 删除字典
+ removeDict(_key) {
+ var bln = false;
+ try {
+ for (let i = 0; i < this.dict.length; i++) {
+ if (this.dict[i].key == _key) {
+ this.dict.splice(i, 1);
+ return true;
+ }
+ }
+ } catch (e) {
+ bln = false;
+ }
+ return bln;
+ },
+ // 清空字典
+ cleanDict() {
+ this.dict = new Array();
+ },
+ // 初始字典
+ initDict() {
+ }
+ }
+ })
+
+export default useDictStore
diff --git a/src/modules/admin/store/modules/permission.ts b/src/modules/admin/store/modules/permission.ts
new file mode 100644
index 0000000..0474569
--- /dev/null
+++ b/src/modules/admin/store/modules/permission.ts
@@ -0,0 +1,147 @@
+import { defineStore } from 'pinia'
+import Layout from '@admin/layout/index.vue'
+import { asyncRoutes, constantRoutes, notFoundRouter } from '@admin/routers/index'
+// import { hasPermission, filterAsyncRoutes } from "@admin/utils/routers"
+import auth from '@admin/utils/common/auth'
+import { filterKeepAlive } from "@admin/utils/routers";
+import to from 'await-to-js'
+import request from '@admin/api/login'
+import { join } from 'path-browserify'
+const viewModules = import.meta.glob('@admin/views/**/*.vue')
+
+export const usePermissionStore = defineStore({
+ // id: 必须的,在所有 Store 中唯一
+ id: 'permissionState',
+ // state: 返回对象的函数
+ state: () => ({
+ // 菜单路由
+ routes: [],
+ // 动态路由
+ addRoutes: [],
+ // 缓存路由
+ cacheRoutes: {},
+ }),
+ getters: {
+ permission_routes: state => {
+ return state.routes
+ },
+ keepAliveRoutes: state => {
+ return filterKeepAlive(asyncRoutes)
+ }
+ },
+ // 可以同步 也可以异步
+ actions: {
+ // 生成路由
+ generateRoutes(roles): Promise {
+
+ return new Promise(async (resolve) => {
+ const [err, { data }] = await to(request.getRouters())
+ if(err) return
+ const fnc = function(arr, parentName?) {
+ arr.forEach(item => {
+ item.path = join(parentName || '', item.path || '')
+ item.name = item.path?.slice(1)?.replaceAll('/','_')
+ if(item.children?.length > 0 ) {
+ fnc(item.children, item.path)
+ }
+ })
+ }
+ fnc(data)
+
+ const siderdata = JSON.parse(JSON.stringify(data))
+ const routerdata = JSON.parse(JSON.stringify(data))
+ // 生成菜单路由
+ const sidebarRoutes = filterAsyncRouter(siderdata, roles)
+ // 重新为路由命名,对应组件名
+ this.routes = [...constantRoutes, ...sidebarRoutes]
+ // 生成权限路由(异步路由和动态路由)
+ let accessedRoutes = [ ...filterAsyncRouter(routerdata, false, true), ...filterDynamicRoutes(asyncRoutes), ...notFoundRouter ].filter(item => !item.meta?.link)
+ resolve(accessedRoutes)
+ })
+ },
+ // 清除路由
+ clearRoutes() {
+ this.routes = []
+ this.addRoutes = []
+ this.cacheRoutes = []
+ },
+ getCacheRoutes() {
+ this.cacheRoutes = filterKeepAlive(asyncRoutes)
+ return this.cacheRoutes
+ }
+ },
+
+})
+
+// / 遍历后台传来的路由字符串,转换为组件对象
+function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
+ return asyncRouterMap.filter(route => {
+ if (type && route.children) {
+ route.children = filterChildren(route.children)
+ }
+ if (route.component) {
+ if (route.component === 'Layout') {
+ route.component = Layout
+ } else {
+ route.component = dynamicImport(route.component)
+ }
+ }
+ if (route.children != null && route.children && route.children.length) {
+ route.children = filterAsyncRouter(route.children, route, type)
+ } else {
+ delete route['children']
+ delete route['redirect']
+ }
+ return true
+ })
+}
+
+function filterChildren(childrenMap, lastRouter: any = false) {
+ var children = []
+ childrenMap.forEach((el, index) => {
+ if (el.children && el.children.length) {
+ if (el.component === 'ParentView') {
+ el.children.forEach(c => {
+ c.path = el.path + '/' + c.path
+ if (c.children && c.children.length) {
+ children = children.concat(filterChildren(c.children, c))
+ return
+ }
+ children.push(c)
+ })
+ return
+ }
+ }
+ if (lastRouter) {
+ el.path = lastRouter.path + '/' + el.path
+ }
+ children = children.concat(el)
+ })
+ return children
+}
+
+function dynamicImport( component: string ) {
+ const matchKey = `/src/modules/admin/views/${component}.vue`
+ return viewModules[matchKey]
+}
+
+
+// 动态路由遍历,验证是否具备权限
+export function filterDynamicRoutes(routes: any[]) {
+ // 递归校验routes权限
+ function checkRoute(list: any[]) {
+ const res = []
+ list.forEach(route => {
+ if(route.children?.length) {
+ route.children = checkRoute(route.children)
+ }
+ if(route.permissions = "admin" || route.children?.length || auth.hasPermiOr(route.permissions) || auth.hasRoleOr(route.roles) ) {
+ res.push(route)
+ }
+ })
+ return res
+ }
+ return checkRoute(routes)
+}
+
+
diff --git a/src/modules/admin/store/modules/setting.ts b/src/modules/admin/store/modules/setting.ts
new file mode 100644
index 0000000..055deb5
--- /dev/null
+++ b/src/modules/admin/store/modules/setting.ts
@@ -0,0 +1,81 @@
+import { defineStore } from 'pinia'
+import { PRIMARY_COLOR } from "@admin/config";
+
+const defaultThemeConfig = {
+ // 显示设置
+ showSetting: false,
+ // 菜单展示模式 默认 vertical horizontal / vertical /columns
+ mode: 'vertical',
+ // tagsView 是否展示 默认展示
+ showTag: true,
+ // 页脚
+ footer: true,
+ // 深色模式 切换暗黑模式
+ isDark: false,
+ // 显示侧边栏Logo
+ showLogo: true,
+ // 主题颜色
+ primary: PRIMARY_COLOR,
+ // element组件大小
+ globalComSize: 'default',
+ // 是否只保持一个子菜单的展开
+ uniqueOpened: true,
+ // 固定header
+ fixedHeader: true,
+ // 灰色模式
+ gray: false,
+ // 色弱模式
+ weak: false
+}
+export const useSettingStore = defineStore({
+ // id: 必须的,在所有 Store 中唯一
+ id: 'settingState',
+ // state: 返回对象的函数
+ state: () => ({
+ // menu 是否收缩
+ isCollapse: true,
+ //
+ withoutAnimation: false,
+ device: 'desktop',
+ // 刷新当前页
+ isReload: true,
+ // 主题设置
+ themeConfig: defaultThemeConfig,
+ }),
+ getters: {
+ isMobile: (state) => state.device === 'mobile',
+ },
+ // 可以同步 也可以异步
+ actions: {
+ // 设置主题
+ setThemeConfig({ key, val }) {
+ this.themeConfig[key] = val
+ },
+ // 切换 Collapse
+ setCollapse(value) {
+ this.isCollapse = value
+ this.withoutAnimation = false
+ },
+ // 关闭侧边栏
+ closeSideBar({ withoutAnimation }) {
+ this.isCollapse = false
+ this.withoutAnimation = withoutAnimation
+ },
+ toggleDevice(device) {
+ this.device = device
+ },
+ // 刷新
+ setReload() {
+ this.isReload = false
+ setTimeout(() => {
+ this.isReload = true
+ }, 50)
+ }
+ },
+ persist: {
+ // 本地存储的名称
+ key: "settingState",
+ //保存的位置
+ storage: window.localStorage,//localstorage
+ },
+})
diff --git a/src/modules/admin/store/modules/tagsView.ts b/src/modules/admin/store/modules/tagsView.ts
new file mode 100644
index 0000000..f98eefa
--- /dev/null
+++ b/src/modules/admin/store/modules/tagsView.ts
@@ -0,0 +1,113 @@
+import { defineStore } from 'pinia'
+import router from "@admin/routers/index";
+
+export const useTagsViewStore = defineStore({
+ // id: 必须的,在所有 Store 中唯一
+ id: 'tagsViewState',
+ // state: 返回对象的函数
+ state: () => ({
+ activeTabsValue: '/home',
+ visitedViews: [],
+ cachedViews: [],
+
+ }),
+ getters: {},
+ // 可以同步 也可以异步
+ actions: {
+ setTabsMenuValue(val) {
+ this.activeTabsValue = val
+ },
+ addView(view) {
+ this.addVisitedView(view)
+ },
+ removeView(routes) {
+ return new Promise((resolve, reject) => {
+ this.visitedViews = this.visitedViews.filter(item => !routes.includes(item.path))
+ resolve(null)
+ })
+ },
+ addVisitedView(view) {
+ this.setTabsMenuValue(view.path);
+ if (this.visitedViews.some(v => v.path === view.path)) return
+
+ this.visitedViews.push(
+ Object.assign({}, view, {
+ title: view.meta.title || 'no-name'
+ })
+ )
+ if (view.meta.keepAlive) {
+ this.cachedViews.push(view.name)
+ }
+
+ },
+ delView(activeTabPath) {
+ return new Promise(resolve => {
+ this.delVisitedView(activeTabPath)
+ this.delCachedView(activeTabPath)
+ resolve({
+ visitedViews: [...this.visitedViews],
+ cachedViews: [...this.cachedViews]
+ })
+ })
+
+ },
+ toLastView(activeTabPath) {
+ let index = this.visitedViews.findIndex(item => item.path === activeTabPath)
+ const nextTab = this.visitedViews[index + 1] || this.visitedViews[index - 1];
+ if (!nextTab) return;
+ router.push(nextTab.path);
+ this.addVisitedView(nextTab)
+ },
+ delVisitedView(path) {
+ return new Promise(resolve => {
+ this.visitedViews = this.visitedViews.filter(v => {
+ return (v.path !== path || v.meta.affix)
+ })
+ this.cachedViews = this.cachedViews.filter(v => {
+ return (v.path !== path || v.meta.affix)
+ })
+ resolve([...this.visitedViews])
+ })
+
+ },
+ delCachedView(view) {
+ return new Promise(resolve => {
+ const index = this.cachedViews.indexOf(view.name)
+ index > -1 && this.cachedViews.splice(index, 1)
+ resolve([...this.cachedViews])
+ })
+
+ },
+ clearVisitedView() {
+ this.delAllViews()
+ },
+ delAllViews() {
+ return new Promise((resolve) => {
+ this.visitedViews = this.visitedViews.filter(v => v.meta.affix)
+ this.cachedViews = this.visitedViews.filter(v => v.meta.affix)
+ resolve([...this.visitedViews])
+ })
+ },
+ delOtherViews(path) {
+ this.visitedViews = this.visitedViews.filter(item => {
+ return item.path === path || item.meta.affix;
+ });
+ this.cachedViews = this.visitedViews.filter(item => {
+ return item.path === path || item.meta.affix;
+ });
+ },
+ goHome() {
+ this.activeTabsValue = '/home';
+ router.push({ path: '/home' });
+ },
+ updateVisitedView(view) {
+ for (let v of this.visitedViews) {
+ if (v.path === view.path) {
+ v = Object.assign(v, view)
+ break
+ }
+ }
+ }
+ },
+
+})
diff --git a/src/modules/admin/store/modules/user.ts b/src/modules/admin/store/modules/user.ts
new file mode 100644
index 0000000..f1bc6ed
--- /dev/null
+++ b/src/modules/admin/store/modules/user.ts
@@ -0,0 +1,80 @@
+import { defineStore } from 'pinia'
+import type { loginForm } from '@/types/login'
+import request from '@admin/api/login'
+import { getToken, setToken, removeToken } from '@admin/utils/auth'
+
+interface UserInfo {
+ userId: string | number,
+ nickName: string,
+ userName: string,
+ deptId: string | number,
+ avatar: string,
+ sex: string,
+ email: string,
+ phonenumber: string,
+ admin: boolean,
+}
+
+export const useUserStore = defineStore({
+ id: 'userState',
+ state: () => ({
+ token: getToken(),
+ userInfo: {} as UserInfo | null,
+ roles: [],
+ permissions: [],
+ }),
+ getters: {
+ avatar: (state): string => `${import.meta.env.VITE_BASE_API}${state.userInfo.avatar}`
+ },
+ actions: {
+ // 登录
+ login(userInfo: loginForm) {
+ return new Promise(async (resolve, reject) => {
+ request.login(userInfo).then(res => {
+ setToken(res.token)
+ this.token = res.token
+ resolve(res)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+ // 获取用户信息
+ getInfo() {
+ const _this = this
+ return new Promise((resolve, reject) => {
+ request.getInfo().then(res => {
+ _this.userInfo = res.user
+ _this.roles = res.roles
+ _this.permissions = res.permissions
+ resolve(res)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+ // 退出
+ logout() {
+ const _this = this
+ return new Promise((resolve, reject) => {
+ request.logout().then(res => {
+ _this.token = null
+ _this.roles = []
+ _this.permissions = []
+ _this.userInfo = {}
+ removeToken()
+ resolve(res)
+ }).catch(error => {
+ reject(error)
+ })
+ })
+ },
+ },
+ // 进行持久化存储
+ // persist: {
+ // // 本地存储的名称
+ // key: "userState",
+ // //保存的位置
+ // storage: window.localStorage,//localstorage
+ // },
+})
diff --git a/src/modules/admin/types/login.ts b/src/modules/admin/types/login.ts
new file mode 100644
index 0000000..bdc72b1
--- /dev/null
+++ b/src/modules/admin/types/login.ts
@@ -0,0 +1,7 @@
+export interface loginForm {
+ username: string
+ password: string
+ code: string
+ uuid: string
+ rememberMe: boolean
+}
\ No newline at end of file
diff --git a/src/modules/admin/utils/auth.ts b/src/modules/admin/utils/auth.ts
new file mode 100644
index 0000000..3caee40
--- /dev/null
+++ b/src/modules/admin/utils/auth.ts
@@ -0,0 +1,15 @@
+import Cookies from 'js-cookie'
+
+const TokenKey = 'Admin-Token'
+
+export function getToken() {
+ return Cookies.get(TokenKey)
+}
+
+export function setToken(token) {
+ return Cookies.set(TokenKey, token)
+}
+
+export function removeToken() {
+ return Cookies.remove(TokenKey)
+}
\ No newline at end of file
diff --git a/src/modules/admin/utils/common/auth.ts b/src/modules/admin/utils/common/auth.ts
new file mode 100644
index 0000000..27b4e6d
--- /dev/null
+++ b/src/modules/admin/utils/common/auth.ts
@@ -0,0 +1,60 @@
+import { useUserStore } from '@admin/store/modules/user'
+
+function authPermission(permission) {
+ const all_permission = "*:*:*";
+ const permissions = useUserStore().permissions
+ if (permission && permission.length > 0) {
+ return permissions.some(v => {
+ return all_permission === v || v === permission
+ })
+ } else {
+ return false
+ }
+}
+
+function authRole(role) {
+ const super_admin = "admin";
+ const roles = useUserStore().roles
+ if (role && role.length > 0) {
+ return roles.some(v => {
+ return super_admin === v || v === role
+ })
+ } else {
+ return false
+ }
+}
+
+export default {
+ // 验证用户是否具备某权限
+ hasPermi(permission) {
+ return authPermission(permission);
+ },
+ // 验证用户是否含有指定权限,只需包含其中一个
+ hasPermiOr(permissions) {
+ return permissions?.some(item => {
+ return authPermission(item)
+ })
+ },
+ // 验证用户是否含有指定权限,必须全部拥有
+ hasPermiAnd(permissions) {
+ return permissions.every(item => {
+ return authPermission(item)
+ })
+ },
+ // 验证用户是否具备某角色
+ hasRole(role) {
+ return authRole(role);
+ },
+ // 验证用户是否含有指定角色,只需包含其中一个
+ hasRoleOr(roles) {
+ return roles?.some(item => {
+ return authRole(item)
+ })
+ },
+ // 验证用户是否含有指定角色,必须全部拥有
+ hasRoleAnd(roles) {
+ return roles.every(item => {
+ return authRole(item)
+ })
+ }
+}
diff --git a/src/modules/admin/utils/common/content.ts b/src/modules/admin/utils/common/content.ts
new file mode 100644
index 0000000..b3cdb0b
--- /dev/null
+++ b/src/modules/admin/utils/common/content.ts
@@ -0,0 +1,50 @@
+/**
+ * 构造树型结构数据
+ * @param {*} data 数据源
+ * @param {*} id id字段 默认 'id'
+ * @param {*} parentId 父节点字段 默认 'parentId'
+ * @param {*} children 孩子节点字段 默认 'children'
+ */
+export function handleTree(data: any[], id: string, parentId?: string |number, children?: string) {
+ let config = {
+ id: id || 'id',
+ parentId: parentId || 'parentId',
+ childrenList: children || 'children'
+ };
+
+ var childrenListMap = {};
+ var nodeIds = {};
+ var tree = [];
+
+ for (let d of data) {
+ let parentId = d[config.parentId];
+ if (childrenListMap[parentId] == null) {
+ childrenListMap[parentId] = [];
+ }
+ nodeIds[d[config.id]] = d;
+ childrenListMap[parentId].push(d);
+ }
+
+ for (let d of data) {
+ let parentId = d[config.parentId];
+ if (nodeIds[parentId] == null) {
+ tree.push(d);
+ }
+ }
+
+ for (let t of tree) {
+ adaptToChildrenList(t);
+ }
+
+ function adaptToChildrenList(o) {
+ if (childrenListMap[o[config.id]] !== null) {
+ o[config.childrenList] = childrenListMap[o[config.id]];
+ }
+ if (o[config.childrenList]) {
+ for (let c of o[config.childrenList]) {
+ adaptToChildrenList(c);
+ }
+ }
+ }
+ return tree;
+}
\ No newline at end of file
diff --git a/src/modules/admin/utils/common/dict.ts b/src/modules/admin/utils/common/dict.ts
new file mode 100644
index 0000000..e034d65
--- /dev/null
+++ b/src/modules/admin/utils/common/dict.ts
@@ -0,0 +1,29 @@
+import useDictStore from '@admin/store/modules/dict'
+import request from '@admin/api/system/user'
+import { ref, toRefs } from 'vue'
+/**
+ * 获取字典数据
+ */
+export function useDict(...args: string[]) {
+ const res = ref({});
+ return (() => {
+ args.forEach(type => {
+ res.value[type] = [];
+ const dicts = useDictStore().getDict(type);
+ if (dicts) {
+ res.value[type] = dicts;
+ } else {
+ request.getDicts(type).then(resp => {
+ res.value[type] = resp.data.data?.map(p => ({
+ label: p.dictLabel,
+ value: p.dictValue === 'undefined' ? undefined : p.dictValue,
+ elTagType: p.listClass,
+ elTagClass: p.cssClass
+ }))
+ useDictStore().setDict(type, res.value[type]);
+ })
+ }
+ })
+ return toRefs(res.value);
+ })()
+}
\ No newline at end of file
diff --git a/src/modules/admin/utils/common/download.ts b/src/modules/admin/utils/common/download.ts
new file mode 100644
index 0000000..488f912
--- /dev/null
+++ b/src/modules/admin/utils/common/download.ts
@@ -0,0 +1,33 @@
+import service from '@admin/utils/request'
+import { ElLoading, ElMessage } from 'element-plus'
+import { blobValidate, tansParams } from '@admin/utils/index'
+import errorCode from '@admin/utils/request/errorCode'
+import FileSaver from 'file-saver';
+
+let downloadLoadingInstance;
+// 通用下载方法
+function download(url, params, filename, config?) {
+ downloadLoadingInstance = ElLoading.service({ text: "正在下载数据,请稍候", background: "rgba(0, 0, 0, 0.7)", })
+ return service.post(url, params, {
+ transformRequest: [(params) => { return tansParams(params) }],
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ responseType: 'blob',
+ ...config
+ }).then(async (data: any) => {
+ const isBlob = blobValidate(data);
+ if (isBlob) {
+ const blob = new Blob([data])
+ FileSaver.saveAs(blob, filename)
+ } else {
+ const resText = await data.text();
+ const rspObj = JSON.parse(resText);
+ const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+ ElMessage.error(errMsg);
+ }
+ downloadLoadingInstance.close();
+ }).catch((r) => {
+ ElMessage.error('下载文件出现错误,请联系管理员!')
+ downloadLoadingInstance.close();
+ })
+}
+export default download
\ No newline at end of file
diff --git a/src/modules/admin/utils/common/index.ts b/src/modules/admin/utils/common/index.ts
new file mode 100644
index 0000000..8952f25
--- /dev/null
+++ b/src/modules/admin/utils/common/index.ts
@@ -0,0 +1,108 @@
+
+
+import NProgress from 'nprogress'
+import { setUrlQuery } from '@admin/utils'
+import { getToken } from '@admin/utils/auth'
+import router from '@admin/routers/index'
+import request from '@admin/utils/request'
+import { useTagsViewStore } from '@admin/store/modules/tagsView'
+const baseURL = import.meta.env.VITE_BASE_API
+
+// 处理上传附件的下载方法
+export function downloadFile(val: any, name?: string, download?: Boolean) {
+ const id = val?.id || val
+ const fileName = val?.name || name
+ if(!id) return
+ const url = `${baseURL}/system/file/download/${id}`
+ console.log(url);
+ const type = fileName?.split('.')?.pop()
+ const previewType = ['jpg', 'jpeg', 'png', 'PNG']
+ // if(!download && previewType.includes(type)) {
+ // const url = setUrlQuery(`/download/${id}`, { fileName })
+ // window.open(url)
+ // return
+ // }
+ const xhr = new XMLHttpRequest();
+ xhr.open("get", url, true);
+ xhr.responseType = "blob";
+ xhr.setRequestHeader("Authorization", 'Bearer ' + getToken()); // token键值对
+ xhr.onload = function() {
+ if (this.status == 200) {
+ console.log(this.response);
+ var blob = this.response;
+ var a = document.createElement("a")
+ var url = window.URL.createObjectURL(blob)
+ a.href = url
+ a.download = fileName || "未命名"
+ }
+ a.click()
+ window.URL.revokeObjectURL(url)
+ }
+ xhr.send();
+}
+
+// 导出excel
+export function handleExport(url: string, params: object, type?: string) {
+ console.log(url);
+ const option: any = {
+ url,
+ method: type || "GET",
+ }
+ if(!type || type === 'GET') {
+ option.params = params
+ }else {
+ option.data = params
+ }
+ NProgress.start()
+ request.request(option).then(res => {
+
+ // download(res.msg)
+ downloadFile
+ NProgress.done()
+ }).catch(() => {
+ NProgress.done()
+ })
+}
+
+// 通用下载方法
+export function download(fileName: string) {
+ const url = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
+ const xhr = new XMLHttpRequest();
+ xhr.open("get", url, true);
+ xhr.responseType = "blob";
+ xhr.setRequestHeader("Authorization", 'Bearer ' + getToken()); // token键值对
+ xhr.onload = function() {
+ if (this.status == 200) {
+ console.log(this.response);
+ var blob = this.response;
+ var a = document.createElement("a")
+ var url = window.URL.createObjectURL(blob)
+ a.href = url
+ a.download = fileName || "未命名"
+ }
+ a.click()
+ window.URL.revokeObjectURL(url)
+ }
+ xhr.send();
+ // downloadFile(url)
+ // window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
+}
+
+// 跳转到指定router路径,没有就跳到首页
+export function goPage(path: string, newPage?: boolean) {
+ const {delView } = useTagsViewStore()
+ const currentPath = router.currentRoute.value.path
+ !newPage && delView(currentPath)
+ const routes = router.getRoutes() || []
+ router.push(routes.find(item => item.path === path) ? path :'/home')
+}
+
+// 复制文本到剪切板
+export const copyToClipboard = (text: string) => {
+ const textarea = document.createElement('textarea');
+ textarea.value = text;
+ document.body.appendChild(textarea);
+ textarea.select();
+ document.execCommand('copy');
+ document.body.removeChild(textarea);
+}
\ No newline at end of file
diff --git a/src/modules/admin/utils/element.ts b/src/modules/admin/utils/element.ts
new file mode 100644
index 0000000..d1bff01
--- /dev/null
+++ b/src/modules/admin/utils/element.ts
@@ -0,0 +1,16 @@
+import { ElLoading } from 'element-plus'
+import {
+ Loading
+} from '@element-plus/icons-vue'
+let loading = null
+
+export const openLoading = (options: any = {}) => {
+ const text = options.text || '加载中'
+ loading = ElLoading.service({
+ lock: true,
+ text: text,
+ })
+}
+export const closeLoading = () => {
+ loading && loading.close()
+}
diff --git a/src/modules/admin/utils/element/ElIcons.ts b/src/modules/admin/utils/element/ElIcons.ts
new file mode 100644
index 0000000..fe19fa6
--- /dev/null
+++ b/src/modules/admin/utils/element/ElIcons.ts
@@ -0,0 +1,15 @@
+
+// 注册icon组件
+import * as ElIconsModules from '@element-plus/icons-vue'
+
+export const registerElIcons = (app) => {
+ // 全局注册element-plus icon图标组件
+ Object.keys(ElIconsModules).forEach((key) => {//循环遍历组件名称
+ if ("Menu" !== key) {//如果不是图标组件不是Menu,就跳过,否则加上ICon的后缀
+ app.component(key, ElIconsModules[key]);
+ } else {
+ app.component(key + "Icon", ElIconsModules[key]);
+ }
+ });
+}
+
diff --git a/src/modules/admin/utils/encrypt/crypto.ts b/src/modules/admin/utils/encrypt/crypto.ts
new file mode 100644
index 0000000..64ff277
--- /dev/null
+++ b/src/modules/admin/utils/encrypt/crypto.ts
@@ -0,0 +1,20 @@
+import CryptoJS from 'crypto-js'
+
+export default {
+/**
+* @param {*需要加密的字符串 注:对象转化为json字符串再加密} word
+* @param {*aes加密需要的key值,这个key值后端同学会告诉你} keyStr
+*/
+ encrypt (word: string, keyStr: string) { // 加密
+ let key = CryptoJS.enc.Utf8.parse(keyStr)
+ let srcs = CryptoJS.enc.Utf8.parse(word)
+ let encrypted = CryptoJS.AES.encrypt(srcs, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7}) // 加密模式为ECB,补码方式为PKCS5Padding(也就是PKCS7)
+ return encrypted.toString()
+ },
+
+ decrypt (word: string, keyStr: string) { // 解密
+ let key = CryptoJS.enc.Utf8.parse(keyStr)
+ let decrypt = CryptoJS.AES.decrypt(word, key, {mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7})
+ return CryptoJS.enc.Utf8.stringify(decrypt).toString()
+ }
+}
\ No newline at end of file
diff --git a/src/modules/admin/utils/encrypt/simpleEncrypt.ts b/src/modules/admin/utils/encrypt/simpleEncrypt.ts
new file mode 100644
index 0000000..91dfeb3
--- /dev/null
+++ b/src/modules/admin/utils/encrypt/simpleEncrypt.ts
@@ -0,0 +1,20 @@
+// 加密函数
+export function encrypt(code: any): string {
+ if(!code) return ''
+ var c=String.fromCharCode(code.charCodeAt(0)+code.length);
+ for(var i=1;i {
+ const value = formatObj[key]
+ // Note: getDay() returns 0 on Sunday
+ if (key === 'a') {
+ return ['日', '一', '二', '三', '四', '五', '六'][value]
+ }
+ return value.toString().padStart(2, '0')
+ })
+ return time_str
+}
+
+/**
+ * 时间戳转换为时间格式
+ * @param {number} time
+ * @param {string} option
+ * @returns {string}
+ */
+export const dateFormat = function (timestamp, formats?: string) {
+ // formats格式包括
+ // 1. Y-m-d
+ // 2. Y-m-d H:i:s
+ // 3. Y年m月d日
+ // 4. Y年m月d日 H时i分
+ formats = formats || 'Y-m-d';
+
+ let zero = function (value) {
+ if (value < 10) {
+ return '0' + value;
+ }
+ return value;
+ };
+ if(!timestamp) {
+ return ""
+ }
+ // let myDate = timestamp? new Date(timestamp): new Date();
+ let myDate = new Date(timestamp)
+
+ let year = myDate.getFullYear();
+ let month = zero(myDate.getMonth() + 1);
+ let day = zero(myDate.getDate());
+
+ let hour = zero(myDate.getHours());
+ let minite = zero(myDate.getMinutes());
+ let second = zero(myDate.getSeconds());
+
+ return formats.replace(/Y|m|d|H|i|s/ig, function (matches) {
+ return ({
+ Y: year,
+ m: month,
+ d: day,
+ H: hour,
+ i: minite,
+ s: second
+ })[matches];
+ });
+};
+
+/**
+ * @param {number} time
+ * @param {string} option
+ * @returns {string}
+ */
+export function formatTime(time, option) {
+ if (('' + time).length === 10) {
+ time = parseInt(time) * 1000
+ } else {
+ time = +time
+ }
+ const d: any = new Date(time)
+ const now = Date.now()
+
+ const diff = (now - d) / 1000
+
+ if (diff < 30) {
+ return '刚刚'
+ } else if (diff < 3600) {
+ // less 1 hour
+ return Math.ceil(diff / 60) + '分钟前'
+ } else if (diff < 3600 * 24) {
+ return Math.ceil(diff / 3600) + '小时前'
+ } else if (diff < 3600 * 24 * 2) {
+ return '1天前'
+ }
+ if (option) {
+ return parseTime(time, option)
+ } else {
+ return (
+ d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
+ )
+ }
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function getQueryObject(url) {
+ url = url == null ? window.location.href : url
+ const search = url.substring(url.lastIndexOf('?') + 1)
+ const obj = {}
+ const reg = /([^?&=]+)=([^?&=]*)/g
+ search.replace(reg, (rs, $1, $2) => {
+ const name = decodeURIComponent($1)
+ let val = decodeURIComponent($2)
+ val = String(val)
+ obj[name] = val
+ return rs
+ })
+ return obj
+}
+
+/**
+ * @param {string} input value
+ * @returns {number} output value
+ */
+export function byteLength(str) {
+ // returns the byte length of an utf8 string
+ let s = str.length
+ for (var i = str.length - 1; i >= 0; i--) {
+ const code = str.charCodeAt(i)
+ if (code > 0x7f && code <= 0x7ff) s++
+ else if (code > 0x7ff && code <= 0xffff) s += 2
+ if (code >= 0xdc00 && code <= 0xdfff) i--
+ }
+ return s
+}
+
+/**
+ * @param {Array} actual
+ * @returns {Array}
+ */
+export function cleanArray(actual) {
+ const newArray = []
+ for (let i = 0; i < actual.length; i++) {
+ if (actual[i]) {
+ newArray.push(actual[i])
+ }
+ }
+ return newArray
+}
+
+/**
+ * @param {Object} json
+ * @returns {Array}
+ */
+export function param(json) {
+ if (!json) return ''
+ return cleanArray(
+ Object.keys(json).map((key) => {
+ if (json[key] === undefined) return ''
+ return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
+ }),
+ ).join('&')
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function param2Obj(url) {
+ const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
+ if (!search) {
+ return {}
+ }
+ const obj = {}
+ const searchArr = search.split('&')
+ searchArr.forEach((v) => {
+ const index = v.indexOf('=')
+ if (index !== -1) {
+ const name = v.substring(0, index)
+ const val = v.substring(index + 1, v.length)
+ obj[name] = val
+ }
+ })
+ return obj
+}
+
+/**
+ * @param {string} val
+ * @returns {string}
+ */
+export function html2Text(val) {
+ const div = document.createElement('div')
+ div.innerHTML = val
+ return div.textContent || div.innerText
+}
+
+/**
+ * Merges two objects, giving the last one precedence
+ * @param {Object} target
+ * @param {(Object|Array)} source
+ * @returns {Object}
+ */
+export function objectMerge(target, source) {
+ if (typeof target !== 'object') {
+ target = {}
+ }
+ if (Array.isArray(source)) {
+ return source.slice()
+ }
+ Object.keys(source).forEach((property) => {
+ const sourceProperty = source[property]
+ if (typeof sourceProperty === 'object') {
+ target[property] = objectMerge(target[property], sourceProperty)
+ } else {
+ target[property] = sourceProperty
+ }
+ })
+ return target
+}
+
+/**
+ * @param {HTMLElement} element
+ * @param {string} className
+ */
+export function toggleClass(element, className) {
+ if (!element || !className) {
+ return
+ }
+ let classString = element.className
+ const nameIndex = classString.indexOf(className)
+ if (nameIndex === -1) {
+ classString += '' + className
+ } else {
+ classString =
+ classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length)
+ }
+ element.className = classString
+}
+
+/**
+ * @param {string} type
+ * @returns {Date}
+ */
+export function getTime(type) {
+ if (type === 'start') {
+ return new Date().getTime() - 3600 * 1000 * 24 * 90
+ } else {
+ return new Date(new Date().toDateString())
+ }
+}
+
+/**
+ * @param {Function} func
+ * @param {number} wait
+ * @param {boolean} immediate
+ * @return {*}
+ */
+export function debounce(func, wait, immediate) {
+ let timeout, args, context, timestamp, result
+
+ const later = function () {
+ // 据上一次触发时间间隔
+ const last = +new Date() - timestamp
+
+ // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
+ if (last < wait && last > 0) {
+ timeout = setTimeout(later, wait - last)
+ } else {
+ timeout = null
+ // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
+ if (!immediate) {
+ result = func.apply(context, args)
+ if (!timeout) context = args = null
+ }
+ }
+ }
+
+ return function (...args) {
+ context = this
+ timestamp = +new Date()
+ const callNow = immediate && !timeout
+ // 如果延时不存在,重新设定延时
+ if (!timeout) timeout = setTimeout(later, wait)
+ if (callNow) {
+ result = func.apply(context, args)
+ context = args = null
+ }
+
+ return result
+ }
+}
+
+/**
+ * This is just a simple version of deep copy
+ * Has a lot of edge cases bug
+ * If you want to use a perfect deep copy, use lodash's _.cloneDeep
+ * @param {Object} source
+ * @returns {Object}
+ */
+export function deepClone(source) {
+ if (!source && typeof source !== 'object') {
+ throw new Error('error arguments')
+ }
+ const targetObj = source.constructor === Array ? [] : {}
+ Object.keys(source).forEach((keys) => {
+ if (source[keys] && typeof source[keys] === 'object') {
+ targetObj[keys] = deepClone(source[keys])
+ } else {
+ targetObj[keys] = source[keys]
+ }
+ })
+ return targetObj
+}
+
+/**
+ * @param {Array} arr
+ * @returns {Array}
+ */
+export function uniqueArr(arr) {
+ return Array.from(new Set(arr))
+}
+
+/**
+ * @returns {string}
+ */
+export function createUniqueString() {
+ const timestamp = +new Date() + ''
+ const randomNum = (1 + Math.random()) * 65536 + ''
+ return (+(randomNum + timestamp)).toString(32)
+}
+
+/**
+ * Check if an element has a class
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ * @returns {boolean}
+ */
+export function hasClass(ele, cls) {
+ return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
+}
+
+/**
+ * Add class to element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function addClass(ele, cls) {
+ if (!hasClass(ele, cls)) ele.className += ' ' + cls
+}
+
+/**
+ * Remove class from element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function removeClass(ele, cls) {
+ if (hasClass(ele, cls)) {
+ const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
+ ele.className = ele.className.replace(reg, ' ')
+ }
+}
+
+export function getColor() {
+ var str = '#'
+ var arr = ['1', '2', '3', '4', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
+ for (var i = 0; i < 6; i++) {
+ var num = Math.random() * 16
+ str += arr[num]
+ }
+ return str
+}
+// 检查给定的值是否是数组
+export const isArray = function (value) {
+ return objToString.call(value) === '[object Array]'
+}
+
+let funProto = Function.prototype
+let objProto = Object.prototype
+
+let getPrototypeOf = Object.getPrototypeOf
+
+let objToString = objProto.toString
+let hasOwnProperty = objProto.hasOwnProperty
+let funToString = funProto.toString
+// 检查给定的值是否是字符串
+export const isString = function (value) {
+ return objToString.call(value) === '[object String]'
+}
+// 检查给定的值是否是纯对象,纯对象是指通过 {} 或 new Object() 声明的对象
+export const isPlainObject = function (value) {
+ if (!value || objToString.call(value) !== '[object Object]') {
+ return false
+ }
+
+ let prototype = getPrototypeOf(value)
+
+ if (prototype === null) {
+ return true
+ }
+
+ let constructor = hasOwnProperty.call(prototype, 'constructor') && prototype.constructor
+
+ return (
+ typeof constructor === 'function' && funToString.call(constructor) === funToString.call(Object)
+ )
+}
+
+// // 深度克隆 array 数组或 json 对象,返回克隆后的副本
+export const deepObjClone = function (obj) {
+ let weakMap = new WeakMap()
+ function clone(obj) {
+ if (obj == null) {
+ return obj
+ }
+ if (obj instanceof Date) {
+ return new Date(obj)
+ }
+ if (obj instanceof RegExp) {
+ return new RegExp(obj)
+ }
+ if (typeof obj !== 'object') return obj
+
+ if (weakMap.get(obj)) {
+ return weakMap.get(obj)
+ }
+ let copy = new obj.constructor()
+ weakMap.set(obj, copy)
+ for (let key in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
+ let value = obj[key]
+ copy[key] = clone(value)
+ }
+ }
+ return copy
+ }
+ return clone(obj)
+}
+
+
+export function getTimeStateStr() {
+ let timeNow = new Date();
+ let hours = timeNow.getHours();
+ if (hours >= 6 && hours <= 10) return `早上好`;
+ if (hours >= 10 && hours <= 14) return `中午好`;
+ if (hours >= 14 && hours <= 18) return `下午好`;
+ if (hours >= 18 && hours <= 24) return `晚上好`;
+ if (hours >= 0 && hours <= 6) return `凌晨好`;
+}
+
+export function blobValidate(data) {
+ return data.type !== 'application/json'
+}
+
+
+/**
+* 参数处理
+* @param {*} params 参数
+*/
+export function tansParams(params) {
+ let result = ''
+ for (const propName of Object.keys(params)) {
+ const value = params[propName];
+ var part = encodeURIComponent(propName) + "=";
+ if (value !== null && value !== "" && typeof (value) !== "undefined") {
+ if (typeof value === 'object') {
+ for (const key of Object.keys(value)) {
+ if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
+ let params = propName + '[' + key + ']';
+ var subPart = encodeURIComponent(params) + "=";
+ result += subPart + encodeURIComponent(value[key]) + "&";
+ }
+ }
+ } else {
+ result += part + encodeURIComponent(value) + "&";
+ }
+ }
+ }
+ return result
+}
+
+/**
+ * 定义url字符串拼接的方法
+ * @param {string} url
+ * @returns {Object}
+ */
+export function setUrlQuery (url, query) {
+ if(!url) return '';
+ if(query) {
+ let queryArr = [];
+ for (const key in query) {
+ if (query.hasOwnProperty(key)) {
+ query[key] && queryArr.push(`${key}=${query[key]}`)
+ }
+ }
+ if(queryArr.length === 0) {
+ return url
+ }
+ if(url.indexOf('?') !== -1) {
+ url =`${url}&${queryArr.join('&')}`
+ } else {
+ url =`${url}?${queryArr.join('&')}`
+ }
+ }
+ return url;
+}
+
+//
+/**
+ * 阿拉伯数字转换为中文数字
+ * @param {string} num
+ * @returns {string}
+ */
+export function numberToChinese(num: number): string {
+ const chineseNums = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
+ const chineseUnits = ["", "十", "百", "千", "万", "亿"];
+ let result = "";
+ let unitIndex = 0;
+ while (num > 0) {
+ const digit = num % 10;
+ if (digit === 0) {
+ if (result[0] !== chineseNums[0]) {
+ result = chineseNums[0] + result;
+ }
+ } else {
+ result = chineseNums[digit] + chineseUnits[unitIndex] + result;
+ }
+ unitIndex++;
+ num = Math.floor(num / 10);
+ }
+ return result;
+}
diff --git a/src/modules/admin/utils/request/common.ts b/src/modules/admin/utils/request/common.ts
new file mode 100644
index 0000000..e843bc1
--- /dev/null
+++ b/src/modules/admin/utils/request/common.ts
@@ -0,0 +1,87 @@
+import axios, { AxiosError, AxiosRequestConfig } from 'axios'
+import errorCode from '@admin/utils/request/errorCode'
+import { ElMessage, ElNotification } from "element-plus";
+
+declare module "axios" {
+ interface AxiosInstance {
+ (config: AxiosRequestConfig): Promise;
+ }
+}
+
+// 创建axios实例 进行基本参数配置
+const service = axios.create({
+ baseURL: import.meta.env.VITE_BASE_API,
+ timeout: 3000000,
+ withCredentials: true
+})
+
+// request interceptor 接口请求拦截
+service.interceptors.request.use((config: AxiosRequestConfig) => {
+ if (config.method === 'get') {
+ config.params = {
+ timestamp: new Date().getTime(),
+ ...config.params
+ }
+ }
+ return config
+}, (error: AxiosError) => {
+ return Promise.reject(error);
+})
+
+// response interceptor 接口响应拦截
+service.interceptors.response.use((res) => {
+ // 未设置状态码则默认成功状态
+ const code = res.data.code || 200;
+
+ // 获取错误信息
+ const msg = errorCode[code] || res.data.msg || errorCode['default']
+ // 二进制数据则直接返回
+ if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
+ return res.data
+ }
+ if (code === 401) {
+ return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
+ } else if (code === 500) {
+ ElMessage({ message: msg, type: 'error' })
+ return Promise.reject(new Error(msg))
+ } else if (code === 601) {
+ ElMessage({ message: msg, type: 'warning' })
+ return Promise.reject(new Error(msg))
+ } else if (code !== 200) {
+ ElNotification.error({ title: msg })
+ return Promise.reject('error')
+ } else {
+ return Promise.resolve(res.data)
+ }
+},
+(error: AxiosError) => {
+ let { message } = error;
+ if (message == "Network Error") {
+ message = "后端接口连接异常";
+ }
+ else if (message.includes("timeout")) {
+ message = "系统接口请求超时";
+ }
+ else if (message.includes("Request failed with status code")) {
+ message = "系统接口" + message.substr(message.length - 3) + "异常";
+ }
+ showErrMessage(message)
+ return Promise.reject(error)
+})
+
+
+/**
+ * @description 显示错误消息
+ * message 错误信息
+ * type 消息类型
+ * duration 消息持续时间
+ */
+function showErrMessage(message: string, type: any = 'error', duration: number = 3000) {
+ ElMessage({
+ message,
+ type: type,
+ duration: duration
+ })
+}
+
+export default service
diff --git a/src/modules/admin/utils/request/errorCode.ts b/src/modules/admin/utils/request/errorCode.ts
new file mode 100644
index 0000000..288e7c7
--- /dev/null
+++ b/src/modules/admin/utils/request/errorCode.ts
@@ -0,0 +1,16 @@
+export default {
+ '400': '请求失败!请您稍后重试',
+ '401': '未授权,请重新登录',
+ '403': '当前账号无权限访问!',
+ '404': '你所访问的资源不存在!',
+ '405': '请求方式错误!请您稍后重试',
+ '408': '请求超时!请您稍后重试',
+ '500': '服务器端出错',
+ '501': '网络未实现',
+ '502': '网络错误',
+ '503': '服务不可用',
+ '504': '网络超时',
+ '505': 'http版本不支持该请求',
+ 'default': '系统未知错误,请反馈给管理员'
+}
+
diff --git a/src/modules/admin/utils/request/errorCodeType.ts b/src/modules/admin/utils/request/errorCodeType.ts
new file mode 100644
index 0000000..676e006
--- /dev/null
+++ b/src/modules/admin/utils/request/errorCodeType.ts
@@ -0,0 +1,44 @@
+export const errorCodeType = function(code:string | number):string{
+ let errMessage:string = "未知错误"
+ switch (code) {
+ case 400:
+ errMessage = '请求失败!请您稍后重试'
+ break
+ case 401:
+ errMessage = '未授权,请重新登录'
+ break
+ case 403:
+ errMessage = '当前账号无权限访问!'
+ break
+ case 404:
+ errMessage = '你所访问的资源不存在!'
+ break
+ case 405:
+ errMessage = '请求方式错误!请您稍后重试'
+ break
+ case 408:
+ errMessage = '请求超时!请您稍后重试'
+ break
+ case 500:
+ errMessage = '服务器端出错'
+ break
+ case 501:
+ errMessage = '网络未实现'
+ break
+ case 502:
+ errMessage = '网络错误'
+ break
+ case 503:
+ errMessage = '服务不可用'
+ break
+ case 504:
+ errMessage = '网络超时'
+ break
+ case 505:
+ errMessage = 'http版本不支持该请求'
+ break
+ default:
+ errMessage = `其他连接错误 --${code}`
+ }
+ return errMessage
+}
diff --git a/src/modules/admin/utils/request/index.ts b/src/modules/admin/utils/request/index.ts
new file mode 100644
index 0000000..ec8068e
--- /dev/null
+++ b/src/modules/admin/utils/request/index.ts
@@ -0,0 +1,105 @@
+import axios, { AxiosError, AxiosRequestConfig } from 'axios'
+import errorCode from '@admin/utils/request/errorCode'
+import { ElMessage, ElMessageBox, ElNotification } from "element-plus";
+import { useUserStore } from "@admin/store/modules/user"
+
+
+declare module "axios" {
+ interface AxiosInstance {
+ (config: AxiosRequestConfig): Promise;
+ }
+}
+
+// 是否显示重新登录
+export let isRelogin = { show: false };
+
+// 创建axios实例 进行基本参数配置
+const service = axios.create({
+ baseURL: import.meta.env.VITE_BASE_API,
+ timeout: 3000000,
+ withCredentials: true
+})
+
+// request interceptor 接口请求拦截
+service.interceptors.request.use((config: AxiosRequestConfig) => {
+ const userStore = useUserStore();
+ const token: string = userStore.token;
+ // 自定义请求头
+ if (token) { config.headers['Authorization'] = 'Bearer ' + token }
+ if (config.method === 'get') {
+ config.params = {
+ timestamp: new Date().getTime(),
+ ...config.params
+ }
+ }
+ return config
+}, (error: AxiosError) => {
+ return Promise.reject(error);
+})
+
+// response interceptor 接口响应拦截
+service.interceptors.response.use((res) => {
+ // 未设置状态码则默认成功状态
+ const code = res.data.code || 200;
+
+ // 获取错误信息
+ const msg = errorCode[code] || res.data.msg || errorCode['default']
+ // 二进制数据则直接返回
+ if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
+ return res.data
+ }
+ if (code === 401) {
+ if (!isRelogin.show) {
+ isRelogin.show = true;
+ ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
+ isRelogin.show = false;
+ useUserStore().logout().then(() => {location.href = '/admin/index';})
+ }).catch(() => {
+ isRelogin.show = false;
+ });
+ }
+ return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
+ } else if (code === 500) {
+ ElMessage({ message: msg, type: 'error' })
+ return Promise.reject(new Error(msg))
+ } else if (code === 601) {
+ ElMessage({ message: msg, type: 'warning' })
+ return Promise.reject(new Error(msg))
+ } else if (code !== 200) {
+ ElNotification.error({ title: msg })
+ return Promise.reject('error')
+ } else {
+ return Promise.resolve(res.data)
+ }
+},
+(error: AxiosError) => {
+ let { message } = error;
+ if (message == "Network Error") {
+ message = "后端接口连接异常";
+ }
+ else if (message.includes("timeout")) {
+ message = "系统接口请求超时";
+ }
+ else if (message.includes("Request failed with status code")) {
+ message = "系统接口" + message.substr(message.length - 3) + "异常";
+ }
+ showErrMessage(message)
+ return Promise.reject(error)
+})
+
+
+/**
+ * @description 显示错误消息
+ * message 错误信息
+ * type 消息类型
+ * duration 消息持续时间
+ */
+function showErrMessage(message: string, type: any = 'error', duration: number = 3000) {
+ ElMessage({
+ message,
+ type: type,
+ duration: duration
+ })
+}
+
+export default service
diff --git a/src/modules/admin/utils/request/request.ts b/src/modules/admin/utils/request/request.ts
new file mode 100644
index 0000000..ec8068e
--- /dev/null
+++ b/src/modules/admin/utils/request/request.ts
@@ -0,0 +1,105 @@
+import axios, { AxiosError, AxiosRequestConfig } from 'axios'
+import errorCode from '@admin/utils/request/errorCode'
+import { ElMessage, ElMessageBox, ElNotification } from "element-plus";
+import { useUserStore } from "@admin/store/modules/user"
+
+
+declare module "axios" {
+ interface AxiosInstance {
+ (config: AxiosRequestConfig): Promise;
+ }
+}
+
+// 是否显示重新登录
+export let isRelogin = { show: false };
+
+// 创建axios实例 进行基本参数配置
+const service = axios.create({
+ baseURL: import.meta.env.VITE_BASE_API,
+ timeout: 3000000,
+ withCredentials: true
+})
+
+// request interceptor 接口请求拦截
+service.interceptors.request.use((config: AxiosRequestConfig) => {
+ const userStore = useUserStore();
+ const token: string = userStore.token;
+ // 自定义请求头
+ if (token) { config.headers['Authorization'] = 'Bearer ' + token }
+ if (config.method === 'get') {
+ config.params = {
+ timestamp: new Date().getTime(),
+ ...config.params
+ }
+ }
+ return config
+}, (error: AxiosError) => {
+ return Promise.reject(error);
+})
+
+// response interceptor 接口响应拦截
+service.interceptors.response.use((res) => {
+ // 未设置状态码则默认成功状态
+ const code = res.data.code || 200;
+
+ // 获取错误信息
+ const msg = errorCode[code] || res.data.msg || errorCode['default']
+ // 二进制数据则直接返回
+ if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
+ return res.data
+ }
+ if (code === 401) {
+ if (!isRelogin.show) {
+ isRelogin.show = true;
+ ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
+ isRelogin.show = false;
+ useUserStore().logout().then(() => {location.href = '/admin/index';})
+ }).catch(() => {
+ isRelogin.show = false;
+ });
+ }
+ return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
+ } else if (code === 500) {
+ ElMessage({ message: msg, type: 'error' })
+ return Promise.reject(new Error(msg))
+ } else if (code === 601) {
+ ElMessage({ message: msg, type: 'warning' })
+ return Promise.reject(new Error(msg))
+ } else if (code !== 200) {
+ ElNotification.error({ title: msg })
+ return Promise.reject('error')
+ } else {
+ return Promise.resolve(res.data)
+ }
+},
+(error: AxiosError) => {
+ let { message } = error;
+ if (message == "Network Error") {
+ message = "后端接口连接异常";
+ }
+ else if (message.includes("timeout")) {
+ message = "系统接口请求超时";
+ }
+ else if (message.includes("Request failed with status code")) {
+ message = "系统接口" + message.substr(message.length - 3) + "异常";
+ }
+ showErrMessage(message)
+ return Promise.reject(error)
+})
+
+
+/**
+ * @description 显示错误消息
+ * message 错误信息
+ * type 消息类型
+ * duration 消息持续时间
+ */
+function showErrMessage(message: string, type: any = 'error', duration: number = 3000) {
+ ElMessage({
+ message,
+ type: type,
+ duration: duration
+ })
+}
+
+export default service
diff --git a/src/modules/admin/utils/requestAnimationFrameThrottle.js b/src/modules/admin/utils/requestAnimationFrameThrottle.js
new file mode 100644
index 0000000..962343c
--- /dev/null
+++ b/src/modules/admin/utils/requestAnimationFrameThrottle.js
@@ -0,0 +1,25 @@
+import raf from "raf";
+
+/**
+* requestAnimationFrame 节流
+* scroll 和 touchmove 等事件触发很频繁,比屏幕刷新频率更快,将导致无效的渲染和重绘
+* 这里使用 requestAnimationFrame 来优化滚动处理,在一帧中只进行一次有效重绘
+*/
+export default function requestAnimationFrameThrottle(callback) {
+ let id;
+
+ const factory = args => () => {
+ id = null;
+ callback(...args);
+ };
+
+ const throttled = (...args) => {
+ if (id == null) {
+ id = raf(factory(args));
+ }
+ };
+
+ throttled.cancel = () => raf.cancel(id);
+
+ return throttled;
+};
diff --git a/src/modules/admin/utils/routers.ts b/src/modules/admin/utils/routers.ts
new file mode 100644
index 0000000..ba3d622
--- /dev/null
+++ b/src/modules/admin/utils/routers.ts
@@ -0,0 +1,66 @@
+import path from 'path-browserify'
+/**
+ * 通过递归过滤异步路由表
+ * @param routes asyncRoutes
+ * @param roles
+ */
+export function filterAsyncRoutes(routes, roles) {
+ const res = []
+ routes.forEach(route => {
+ const tmp = { ...route }
+ if (hasPermission(roles, tmp)) {
+ if (tmp.children) {
+ tmp.children = filterAsyncRoutes(tmp.children, roles)
+ }
+ res.push(tmp)
+ }
+ })
+ return res
+}
+
+/**
+ * 使用 meta.role 来确定当前用户是否具有权限
+ * @param roles
+ * @param route
+ */
+export function hasPermission(roles, route) {
+ if (route.meta && route.meta.roles) {
+ return roles.some(role => route.meta.roles.includes(role))
+ } else {
+ return false
+ }
+}
+
+/**
+ * @description 使用递归,过滤需要缓存的路由
+ * @param {Array} _route 所有路由表
+ * @param {Array} _cache 缓存的路由表
+ * @return void
+ * */
+
+export function filterKeepAlive(routers) {
+ let cacheRouter: any[] = [];
+ let deep = (routers) => {
+ routers.forEach(item => {
+ if (item.meta?.keepAlive && item.name) {
+ cacheRouter.push(item.name)
+ }
+ if (item.children && item.children.length) {
+ deep(item.children)
+ }
+ })
+ }
+ deep(routers)
+ return cacheRouter
+}
+
+
+
+export function handleRoutes(routers, pathUrl = '') {
+ routers.forEach(item => {
+ item.path = path.resolve(pathUrl, item.path)
+ if (item.children && item.children.length) {
+
+ }
+ })
+}
diff --git a/src/modules/admin/utils/ruoyi/index.ts b/src/modules/admin/utils/ruoyi/index.ts
new file mode 100644
index 0000000..ed1acb4
--- /dev/null
+++ b/src/modules/admin/utils/ruoyi/index.ts
@@ -0,0 +1,43 @@
+// 回显数据字典
+export function selectDictLabel(datas, value) {
+ if (value === undefined) {
+ return "";
+ }
+ var actions = [];
+ Object.keys(datas).some((key) => {
+ if (datas[key].value == ('' + value)) {
+ actions.push(datas[key].label);
+ return true;
+ }
+ })
+ if (actions.length === 0) {
+ actions.push(value);
+ }
+ return actions.join('');
+}
+
+// 回显数据字典(字符串数组)
+export function selectDictLabels(datas, value, separator) {
+ if (value === undefined || value.length ===0) {
+ return "";
+ }
+ if (Array.isArray(value)) {
+ value = value.join(",");
+ }
+ var actions = [];
+ var currentSeparator = undefined === separator ? "," : separator;
+ var temp = value.split(currentSeparator);
+ Object.keys(value.split(currentSeparator)).some((val) => {
+ var match = false;
+ Object.keys(datas).some((key) => {
+ if (datas[key].value == ('' + temp[val])) {
+ actions.push(datas[key].label + currentSeparator);
+ match = true;
+ }
+ })
+ if (!match) {
+ actions.push(temp[val] + currentSeparator);
+ }
+ })
+ return actions.join('').substring(0, actions.join('').length - 1);
+}
diff --git a/src/modules/admin/utils/validate/element.ts b/src/modules/admin/utils/validate/element.ts
new file mode 100644
index 0000000..552d8d6
--- /dev/null
+++ b/src/modules/admin/utils/validate/element.ts
@@ -0,0 +1,203 @@
+// 表单验证文件
+
+// 是否11位数字手机号
+export function isvalidPhone(str) {
+ const reg = /^1\d{10}$/
+ return reg.test(str)
+}
+
+
+export /**
+ * element form 手机号验证模板
+ *
+ * @param {*} rule
+ * @param {*} value 表单value
+ * @param {*} callback
+ */
+const validPhone = (rule, value,callback)=>{
+ if (!value){
+ callback(new Error('请输入联系电话!'))
+ }else if (!isvalidPhone(value)){
+ callback(new Error('请输入正确的11位手机号码!'))
+ }else {
+ callback()
+ }
+}
+
+export /**
+ * element form 校验正数
+ *
+ * @param {*} rule
+ * @param {*} value 表单value
+ * @param {*} callback
+ */
+const validNumber = (rule, value,callback)=>{
+ const val = +value
+ if(!value) {
+ callback()
+ }else if(val !== +val) {
+ callback(new Error('请填写数字!'))
+ }
+ else if (value < 0){
+ callback(new Error('请填写大于0的数字!'))
+ }else {
+ callback()
+ }
+}
+
+export const validNum = (rule, value,callback)=>{
+ const val = +value
+ if(!value) {
+ callback()
+ }else if(val !== +val) {
+ callback(new Error('请填写数字!'))
+ }else {
+ callback()
+ }
+}
+
+export /**
+ * element form 校验非负整数
+ *
+ * @param {*} rule
+ * @param {*} value 表单value
+ * @param {*} callback
+ */
+const validNaturalNumber = (rule, value,callback)=>{
+ if(!value) {
+ callback()
+ } else if( !/^(0|[1-9][0-9]*)$/.test(value)) {
+ callback('请填写整数')
+ }else {
+ callback()
+ }
+}
+
+export
+/**
+ * element form 校验字符串是否是JSON格式
+ *
+ * @param {*} rule
+ * @param {*} value
+ * @param {*} callback
+ */
+const validJSON = (rule, value, callback) => {
+ console.log(value);
+ console.log(isJSON(value));
+ if(isJSON(value)) {
+ callback()
+ }else {
+ callback(new Error('请填写正确的JSON格式!'))
+ }
+}
+function isJSON(str) {
+ if (typeof str === 'string') {
+ try {
+ const obj = JSON.parse(str)
+ if( obj && typeof obj == 'object'){
+ return true;
+ }else{
+ return false;
+ }
+ } catch (e) {
+ return false
+ }
+ }else {
+ return false
+ }
+}
+
+export /**
+ * element form 校验输入最大字符500
+ *
+ * @param {*} rule
+ * @param {*} value 表单value
+ * @param {*} callback
+ */
+const validMax500 = (rule, value,callback)=>{
+ if (value.length > 500){
+ callback(new Error('输入长度不能超过500!'))
+ }else {
+ callback()
+ }
+}
+export /**
+ * element form 校验最大字符50
+ *
+ * @param {*} rule
+ * @param {*} value 表单value
+ * @param {*} callback
+ */
+const validMax50 = (rule, value,callback)=>{
+ if (value.length > 50){
+ callback(new Error('输入长度不能超过50!'))
+ }else {
+ callback()
+ }
+}
+
+export /**
+ * element form 校验最大字符50
+ *
+ * @param {*} rule
+ * @param {*} value 表单value
+ * @param {*} callback
+ */
+const validLength = (length) => {
+ return {
+ validator: (rule, value,callback)=>{
+ if(!value) {
+ callback()
+ }else if (value.length > length){
+ callback(new Error(` 超出限制!(${value.length}/${length})`))
+ }else {
+ callback()
+ }
+ }
+ }
+}
+
+export /**
+* element form 校验输入最大值
+*
+* @param {*} rule
+* @param {*} value 表单value
+* @param {*} callback
+*/
+const ValidMaxNumber = (max) => {
+ return {
+ validator: (rule, value,callback)=>{
+ const val = parseFloat(value)
+ if(!value) {
+ callback()
+ }else if (!isNaN(val) && val > max){
+ callback(new Error(`输入最大值不超过${max}`))
+ }else {
+ callback()
+ }
+ }
+ }
+}
+
+export /**
+* element form 校验输入最大保留小数位decimalPlaces
+* @param {*} rule
+* @param {*} value 表单value
+* @param {*} callback
+*/
+const validDecimal = (decimalPlaces) => {
+ let pattern = new RegExp(`^\\d+(\\.\\d{0,${decimalPlaces}})?$`);
+ return {
+ validator: (rule, value,callback)=>{
+ const val = parseFloat(value)
+ if(!value) {
+ callback()
+ }else if (!isNaN(val) && !pattern.test(value)){
+ const decimal = value?.split('.')[1]
+ callback(new Error(`输入值最多保留${decimalPlaces}位小数! (${decimal?.length}/${decimalPlaces})`))
+ }else {
+ callback()
+ }
+ }
+ }
+}
diff --git a/src/modules/admin/views/home/index.vue b/src/modules/admin/views/home/index.vue
new file mode 100644
index 0000000..d02a4d1
--- /dev/null
+++ b/src/modules/admin/views/home/index.vue
@@ -0,0 +1,9 @@
+
+
+
+
+ 主页
+
+
\ No newline at end of file
diff --git a/src/modules/admin/views/login/components/LoginForm.vue b/src/modules/admin/views/login/components/LoginForm.vue
new file mode 100644
index 0000000..9b5d922
--- /dev/null
+++ b/src/modules/admin/views/login/components/LoginForm.vue
@@ -0,0 +1,144 @@
+
+
+
+
{{ VITE_SYS_NAME }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 记住密码
+
+ 登录
+
+
+
+
+
+
diff --git a/src/modules/admin/views/login/index.vue b/src/modules/admin/views/login/index.vue
new file mode 100644
index 0000000..d747e54
--- /dev/null
+++ b/src/modules/admin/views/login/index.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/monitor/cache/index.vue b/src/modules/admin/views/monitor/cache/index.vue
new file mode 100644
index 0000000..5370f50
--- /dev/null
+++ b/src/modules/admin/views/monitor/cache/index.vue
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/views/monitor/cache/list.vue b/src/modules/admin/views/monitor/cache/list.vue
new file mode 100644
index 0000000..5370f50
--- /dev/null
+++ b/src/modules/admin/views/monitor/cache/list.vue
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/views/monitor/druid/index.vue b/src/modules/admin/views/monitor/druid/index.vue
new file mode 100644
index 0000000..5370f50
--- /dev/null
+++ b/src/modules/admin/views/monitor/druid/index.vue
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/views/monitor/job/handle.vue b/src/modules/admin/views/monitor/job/handle.vue
new file mode 100644
index 0000000..e090390
--- /dev/null
+++ b/src/modules/admin/views/monitor/job/handle.vue
@@ -0,0 +1,174 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Bean调用示例:ryTask.ryParams('ry')
+ Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry')
+ 参数说明:支持字符串,布尔类型,长整型,浮点型,整型
+
+
+
+
+ 调用方法
+
+
+
+
+
+
+
+
+
+ 生成表达式
+
+
+
+
+
+
+
+
+
+ 立即执行
+ 执行一次
+ 放弃执行
+
+
+
+
+
+
+ 允许
+ 禁止
+
+
+
+
+
+
+ {{ dict.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/monitor/job/index.vue b/src/modules/admin/views/monitor/job/index.vue
new file mode 100644
index 0000000..7014f0a
--- /dev/null
+++ b/src/modules/admin/views/monitor/job/index.vue
@@ -0,0 +1,290 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ detailForm.jobId }}
+ {{ detailForm.jobName }}
+
+
+ {{ jobGroupFormat(detailForm) }}
+ {{ detailForm.createTime }}
+
+
+ {{ detailForm.cronExpression }}
+
+
+ {{ detailForm.nextValidTime }}
+
+
+ {{ detailForm.invokeTarget }}
+
+
+
+ 正常
+ 失败
+
+
+
+
+ 允许
+ 禁止
+
+
+
+
+ 默认策略
+ 立即执行
+ 执行一次
+ 放弃执行
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/monitor/job/log/index.vue b/src/modules/admin/views/monitor/job/log/index.vue
new file mode 100644
index 0000000..64ab971
--- /dev/null
+++ b/src/modules/admin/views/monitor/job/log/index.vue
@@ -0,0 +1,237 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ detailForm.jobLogId }}
+
+
+ {{ detailForm.jobName }}
+
+
+ {{ detailForm.jobGroup }}
+
+
+ {{ detailForm.createTime }}
+
+
+ {{ detailForm.invokeTarget }}
+
+
+ {{ detailForm.jobMessage }}
+
+
+
+ 正常
+ 失败
+
+
+
+ {{ detailForm.exceptionInfo }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/monitor/online/index.vue b/src/modules/admin/views/monitor/online/index.vue
new file mode 100644
index 0000000..f50955b
--- /dev/null
+++ b/src/modules/admin/views/monitor/online/index.vue
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/monitor/server/index.vue b/src/modules/admin/views/monitor/server/index.vue
new file mode 100644
index 0000000..5370f50
--- /dev/null
+++ b/src/modules/admin/views/monitor/server/index.vue
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/views/system/dept/deptDialog.vue b/src/modules/admin/views/system/dept/deptDialog.vue
new file mode 100644
index 0000000..ad8d76f
--- /dev/null
+++ b/src/modules/admin/views/system/dept/deptDialog.vue
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.label }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/dept/index.vue b/src/modules/admin/views/system/dept/index.vue
new file mode 100644
index 0000000..6cf6e75
--- /dev/null
+++ b/src/modules/admin/views/system/dept/index.vue
@@ -0,0 +1,178 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/dict/detail.vue b/src/modules/admin/views/system/dict/detail.vue
new file mode 100644
index 0000000..9559030
--- /dev/null
+++ b/src/modules/admin/views/system/dict/detail.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/dict/dictData/detail.vue b/src/modules/admin/views/system/dict/dictData/detail.vue
new file mode 100644
index 0000000..80d9075
--- /dev/null
+++ b/src/modules/admin/views/system/dict/dictData/detail.vue
@@ -0,0 +1,143 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.label
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/dict/dictData/index.vue b/src/modules/admin/views/system/dict/dictData/index.vue
new file mode 100644
index 0000000..65524b3
--- /dev/null
+++ b/src/modules/admin/views/system/dict/dictData/index.vue
@@ -0,0 +1,203 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/dict/index.vue b/src/modules/admin/views/system/dict/index.vue
new file mode 100644
index 0000000..37e42ba
--- /dev/null
+++ b/src/modules/admin/views/system/dict/index.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/error/403.vue b/src/modules/admin/views/system/error/403.vue
new file mode 100644
index 0000000..378e0f8
--- /dev/null
+++ b/src/modules/admin/views/system/error/403.vue
@@ -0,0 +1,244 @@
+
+
+
+
+
+
+
+
您没有访问权限!
+
+ 请检查URL地址是否正确, 或点击回到首页。
+
+
回到首页
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/error/404.vue b/src/modules/admin/views/system/error/404.vue
new file mode 100644
index 0000000..47e8dad
--- /dev/null
+++ b/src/modules/admin/views/system/error/404.vue
@@ -0,0 +1,230 @@
+
+
+
+
+
+
+
+
页面不存在!
+
地址: {{ path }}
+
请检查URL地址是否正确, 或点击回到首页。
+
回到首页
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/log/login/detail.vue b/src/modules/admin/views/system/log/login/detail.vue
new file mode 100644
index 0000000..9559030
--- /dev/null
+++ b/src/modules/admin/views/system/log/login/detail.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/log/login/index.vue b/src/modules/admin/views/system/log/login/index.vue
new file mode 100644
index 0000000..3fd994f
--- /dev/null
+++ b/src/modules/admin/views/system/log/login/index.vue
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/log/operation/detail.vue b/src/modules/admin/views/system/log/operation/detail.vue
new file mode 100644
index 0000000..d4bf9b1
--- /dev/null
+++ b/src/modules/admin/views/system/log/operation/detail.vue
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+ {{ ruleForm.title }} / {{ typeFormat(ruleForm) }}
+
+
+ {{ ruleForm.operName }} / {{ ruleForm.operIp }} / {{ ruleForm.operLocation
+ }}
+
+
+ {{ ruleForm.operUrl }}
+
+
+ {{ ruleForm.requestMethod }}
+
+
+ {{ ruleForm.method }}
+
+
+ {{ ruleForm.operParam }}
+
+
+ {{ ruleForm.jsonResult }}
+
+
+
+ {{ ruleForm.status === 0 ? '正常' : '失败' }}
+
+
+
+ {{ ruleForm.costTime }}毫秒
+
+
+ {{ ruleForm.operTime }}
+
+
+ {{ ruleForm.errorMsg }}
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/log/operation/index.vue b/src/modules/admin/views/system/log/operation/index.vue
new file mode 100644
index 0000000..74683fd
--- /dev/null
+++ b/src/modules/admin/views/system/log/operation/index.vue
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/menu/index.vue b/src/modules/admin/views/system/menu/index.vue
new file mode 100644
index 0000000..7ea7faf
--- /dev/null
+++ b/src/modules/admin/views/system/menu/index.vue
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/menu/menuDialog.vue b/src/modules/admin/views/system/menu/menuDialog.vue
new file mode 100644
index 0000000..dac0cc4
--- /dev/null
+++ b/src/modules/admin/views/system/menu/menuDialog.vue
@@ -0,0 +1,264 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 目录
+ 菜单
+ 按钮
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 是否外链
+
+
+
+ 是
+ 否
+
+
+
+
+
+
+
+
+
+
+ 路由地址
+
+
+
+
+
+
+
+
+
+
+
+
+ 组件路径
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 权限字符
+
+
+
+
+
+
+
+
+
+
+
+
+ 路由参数
+
+
+
+
+
+
+
+
+
+
+
+ 是否缓存
+
+
+
+ 缓存
+ 不缓存
+
+
+
+
+
+
+
+
+
+
+ 显示状态
+
+
+
+ {{ dict.label }}
+
+
+
+
+
+
+
+
+
+
+ 菜单状态
+
+
+
+ {{ dict.label
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/post/detail.vue b/src/modules/admin/views/system/post/detail.vue
new file mode 100644
index 0000000..8aef7ff
--- /dev/null
+++ b/src/modules/admin/views/system/post/detail.vue
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/post/index.vue b/src/modules/admin/views/system/post/index.vue
new file mode 100644
index 0000000..1cdeea1
--- /dev/null
+++ b/src/modules/admin/views/system/post/index.vue
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/profile/AvatarEdit.vue b/src/modules/admin/views/system/profile/AvatarEdit.vue
new file mode 100644
index 0000000..9a69f17
--- /dev/null
+++ b/src/modules/admin/views/system/profile/AvatarEdit.vue
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 上传图片
+
+
+
+
+
+
+ 放大
+
+
+
+ 缩小
+
+
+
+ 左旋转
+
+
+
+ 右旋转
+
+
+
+ 提 交
+
+
+
+
+
diff --git a/src/modules/admin/views/system/profile/index.vue b/src/modules/admin/views/system/profile/index.vue
new file mode 100644
index 0000000..9282e41
--- /dev/null
+++ b/src/modules/admin/views/system/profile/index.vue
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+ 个人信息
+
+
+
+
+
+
+
+
+
+
{{ item.label }}
+
{{ item.value }}
+
+
+
+
+
+
+
+
+ 个人信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/views/system/profile/resetPwd.vue b/src/modules/admin/views/system/profile/resetPwd.vue
new file mode 100644
index 0000000..b4ca73d
--- /dev/null
+++ b/src/modules/admin/views/system/profile/resetPwd.vue
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 保存
+
+
+
diff --git a/src/modules/admin/views/system/profile/userInfo.vue b/src/modules/admin/views/system/profile/userInfo.vue
new file mode 100644
index 0000000..3803513
--- /dev/null
+++ b/src/modules/admin/views/system/profile/userInfo.vue
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 男
+ 女
+
+
+
+ 保存
+
+
+
diff --git a/src/modules/admin/views/system/role/index.vue b/src/modules/admin/views/system/role/index.vue
new file mode 100644
index 0000000..7440d3d
--- /dev/null
+++ b/src/modules/admin/views/system/role/index.vue
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/role/roleDialog.vue b/src/modules/admin/views/system/role/roleDialog.vue
new file mode 100644
index 0000000..bac53a9
--- /dev/null
+++ b/src/modules/admin/views/system/role/roleDialog.vue
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 权限字符
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.label
+ }}
+
+
+
+
+
+ 展开/折叠
+ 全选/全不选
+ 父子联动
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/user/components/userDialog.vue b/src/modules/admin/views/system/user/components/userDialog.vue
new file mode 100644
index 0000000..dd52578
--- /dev/null
+++ b/src/modules/admin/views/system/user/components/userDialog.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dict.label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/user/components/userTable.vue b/src/modules/admin/views/system/user/components/userTable.vue
new file mode 100644
index 0000000..4cf235a
--- /dev/null
+++ b/src/modules/admin/views/system/user/components/userTable.vue
@@ -0,0 +1,226 @@
+
+
+
+
+ 部门列表
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/system/user/index.scss b/src/modules/admin/views/system/user/index.scss
new file mode 100644
index 0000000..8a7ce91
--- /dev/null
+++ b/src/modules/admin/views/system/user/index.scss
@@ -0,0 +1,101 @@
+.m-user{
+ display: flex;
+ flex-direction: row;
+}
+.m-user-table{
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ position: relative;
+ width: calc(100% - 230px);
+ .header{
+ display: flex;
+ padding: 16px 16px 0px 16px;
+ margin-bottom: 16px;
+ border-radius: 4px;
+ background: white;
+ box-shadow: 0 0 12px rgb(0 0 0 / 5%);
+ }
+ .footer{
+ flex: 1;
+ display: flex;
+ padding: 16px;
+ flex-direction: column;
+ border-radius: 4px;
+ overflow: hidden;
+ background: white;
+ box-shadow: 0 0 12px rgb(0 0 0 / 5%);
+ position: relative;
+ box-sizing: border-box;
+ .util{
+ margin-bottom: 15px;
+ display: flex;
+ flex-shrink: 0;
+ }
+ .table-inner{
+ flex: 1;
+ position: relative;
+ }
+ .table{
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%
+ }
+ }
+ .pagination{
+ width: 100%;
+ display: flex;
+ justify-content: flex-end;
+ padding-top: 20px;
+ box-sizing: border-box;
+ flex-shrink: 0;
+ }
+}
+
+
+.m-dept-side{
+ box-sizing: border-box;
+ width: 220px;
+ height: 100%;
+ padding: 18px;
+ margin-right: 10px;
+ flex-shrink: 0;
+ :deep(.el-card__body){
+ width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ padding: 0!important;
+ .el-tree-node__content{
+ height: 33px;
+ }
+ .el-tree{
+
+ }
+ }
+ .filter-search{
+ flex-shrink: 0;
+ margin-bottom: 10px;
+ }
+ .title{
+ flex-shrink: 0;
+ margin: 0 0 15px;
+ font-size: 18px;
+ font-weight: 700;
+ }
+ .scrollbar{
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+
+ }
+ .filter-tree{
+ flex: 1;
+ overflow: hidden;
+ position: relative;
+ }
+}
diff --git a/src/modules/admin/views/system/user/index.vue b/src/modules/admin/views/system/user/index.vue
new file mode 100644
index 0000000..a87c1f6
--- /dev/null
+++ b/src/modules/admin/views/system/user/index.vue
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/tool/build/index.vue b/src/modules/admin/views/tool/build/index.vue
new file mode 100644
index 0000000..5370f50
--- /dev/null
+++ b/src/modules/admin/views/tool/build/index.vue
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/modules/admin/views/tool/flowable/definition/index.vue b/src/modules/admin/views/tool/flowable/definition/index.vue
new file mode 100644
index 0000000..28e9539
--- /dev/null
+++ b/src/modules/admin/views/tool/flowable/definition/index.vue
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.isActive ? '已激活' : '已挂起' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/tool/flowable/editor/edit/index.vue b/src/modules/admin/views/tool/flowable/editor/edit/index.vue
new file mode 100644
index 0000000..0841d32
--- /dev/null
+++ b/src/modules/admin/views/tool/flowable/editor/edit/index.vue
@@ -0,0 +1,150 @@
+
+
+
+
+
+
+
+
+ {{xmlContent}}
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/tool/flowable/editor/list/index.vue b/src/modules/admin/views/tool/flowable/editor/list/index.vue
new file mode 100644
index 0000000..72a7898
--- /dev/null
+++ b/src/modules/admin/views/tool/flowable/editor/list/index.vue
@@ -0,0 +1,177 @@
+
+
+
+
+
+
+
+ 新增
+ 导入
+
+
+
+
+
+ {{ row.category }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 将文件拖到此处,或
+ 点击上传
+
+
+
+ 流程名称:
+ 流程分类:
+
+ 提示:仅允许导入“bpmn20.xml”格式文件!
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/tool/flowable/node/index.vue b/src/modules/admin/views/tool/flowable/node/index.vue
new file mode 100644
index 0000000..a1bfec6
--- /dev/null
+++ b/src/modules/admin/views/tool/flowable/node/index.vue
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+ 使用预设配置
+ 保存为预设配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ editForm.flow.name }}
+
+ {{ editForm.node.name }}
+ {{ editForm.userFlag ? "指定人员" : '指定角色' }}
+
+
+
+
+
+
+ 取 消
+ 确 定
+
+
+
+
+
+
+
+
+
+
+ 查看配置
+
+
+
+ 取 消
+ {{ isOptionAdd ? '保 存' : '使 用' }}
+
+
+
+
+
+
+
+
+
+ 搜索
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/admin/views/tool/gen/index.vue b/src/modules/admin/views/tool/gen/index.vue
new file mode 100644
index 0000000..bf5b09e
--- /dev/null
+++ b/src/modules/admin/views/tool/gen/index.vue
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/modules/admin/views/tool/swagger/index.vue b/src/modules/admin/views/tool/swagger/index.vue
new file mode 100644
index 0000000..9b57dfe
--- /dev/null
+++ b/src/modules/admin/views/tool/swagger/index.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/src/modules/h5/App.vue b/src/modules/h5/App.vue
new file mode 100644
index 0000000..c3ac0fb
--- /dev/null
+++ b/src/modules/h5/App.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/h5/api/survey.ts b/src/modules/h5/api/survey.ts
new file mode 100644
index 0000000..09f49d4
--- /dev/null
+++ b/src/modules/h5/api/survey.ts
@@ -0,0 +1,20 @@
+import request from '@/utils/request/common'
+
+class requests {
+ static getDetail(id: string | number) {
+ return request({
+ url: `/h5/survey/surveyDetail/${id}`,
+ method: 'get',
+ })
+ }
+ static answer(data: object) {
+ return request({
+ url: `/h5/survey/answerSurvey`,
+ method: 'post',
+ data
+ })
+ }
+}
+
+
+export default requests
diff --git a/src/modules/h5/index.html b/src/modules/h5/index.html
new file mode 100644
index 0000000..1e59038
--- /dev/null
+++ b/src/modules/h5/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ h5模块
+
+
+
+
+
+
diff --git a/src/modules/h5/main.ts b/src/modules/h5/main.ts
new file mode 100644
index 0000000..fb8f3d8
--- /dev/null
+++ b/src/modules/h5/main.ts
@@ -0,0 +1,19 @@
+import "@/styles/tailwind/index.scss"
+import { createApp } from "vue";
+import App from "@h5/App.vue";
+import router from './router'
+// UI框架 element-plus
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+// 引入暗黑模式 element-plus 2.2 内置暗黑模式
+import 'element-plus/theme-chalk/dark/css-vars.css'
+// 自定义暗黑模式
+import "@/styles/element-dark.scss";
+
+import "@/styles/public/index.scss";
+console.log(import.meta.env);
+const app = createApp(App)
+
+app.use(router)
+app.use(ElementPlus)
+app.mount('#app')
\ No newline at end of file
diff --git a/src/modules/h5/router/index.ts b/src/modules/h5/router/index.ts
new file mode 100644
index 0000000..cf69007
--- /dev/null
+++ b/src/modules/h5/router/index.ts
@@ -0,0 +1,31 @@
+import { createRouter, createWebHistory, createWebHashHistory } from "vue-router";
+
+
+const routes: any = [
+ {
+ path: '/',
+ redirect: '/home'
+ },
+ {
+ path: '/home',
+ component: () => import("@h5/views/home/index.vue")
+ },
+ {
+ path: '/survey/:id',
+ name: 'survey',
+ meta: { title: '问卷调查' },
+ component: () => import("@h5/views/survey/index.vue")
+ },
+]
+
+const router = createRouter({
+ history: createWebHistory('/h5'),
+ routes: [...routes],
+});
+
+router.beforeEach((to, from, next) => {
+ (document as any).title = to.meta.title || "德工建设";
+ next();
+});
+export default router;
+
\ No newline at end of file
diff --git a/src/modules/h5/views/home/index.vue b/src/modules/h5/views/home/index.vue
new file mode 100644
index 0000000..0d4e86c
--- /dev/null
+++ b/src/modules/h5/views/home/index.vue
@@ -0,0 +1,9 @@
+
+
+
+
+
德工建设H5
+
+
\ No newline at end of file
diff --git a/src/modules/h5/views/survey/components/textarea.vue b/src/modules/h5/views/survey/components/textarea.vue
new file mode 100644
index 0000000..617c222
--- /dev/null
+++ b/src/modules/h5/views/survey/components/textarea.vue
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/h5/views/survey/index.vue b/src/modules/h5/views/survey/index.vue
new file mode 100644
index 0000000..e832cd2
--- /dev/null
+++ b/src/modules/h5/views/survey/index.vue
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
{{ option.title }}
+
{{ option.description }}
+
+
+
+
+
+ {{ `${index + 1}. ${item.questionTitle}` }}
+ ({{ getModel(item.questionType).tip }})
+
+
+
+ {{ option.questionOption }}
+
+
+ {{ option.questionOption }}
+
+
+
+
+
+ 提交
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/styles/common.scss b/src/styles/common.scss
new file mode 100644
index 0000000..7882301
--- /dev/null
+++ b/src/styles/common.scss
@@ -0,0 +1,163 @@
+html,
+body {
+ height: 100%;
+ width: 100%;
+ overflow: visible;
+ overflow-x: hidden;
+ margin: 0;
+ padding: 0;
+ font-size: 14px;
+}
+
+body {
+ background: #f0f2f5;
+}
+
+/* 常用 flex */
+.flex-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.flex-justify-between {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.flex-align-center {
+ display: flex;
+ align-items: center;
+}
+
+
+
+/** 设置滚动条 **/
+::-webkit-scrollbar {
+ width: 7px;
+ height: 8px;
+}
+
+
+::-webkit-scrollbar-track {
+ background-color: rgb(0 0 0 / 5%);
+}
+
+::-webkit-scrollbar-thumb {
+ // background: rgba(0, 0, 0, 0.6);
+ background-color: rgb(144 147 153 / 30%);
+ // background-color: rgba(144, 147, 153, 0.3);
+ border-radius: 2px;
+ box-shadow: inset 0 0 6px rgb(0 0 0 / 20%);
+}
+
+
+/* nprogress样式 */
+#nprogress .bar {
+ background: $primaryColor !important;
+}
+
+#nprogress .spinner-icon {
+ border-top-color: $primaryColor !important;
+ border-left-color: $primaryColor !important;
+}
+
+#nprogress .peg {
+ box-shadow: 0 0 10px $primaryColor, 0 0 5px $primaryColor !important;
+}
+
+.app-container {
+ height: 100%;
+ width: 100%;
+ padding: 10px 12px;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ .d-header {
+ display: flex;
+ padding: 16px 16px 0px 16px;
+ margin-bottom: 16px;
+ border-radius: 4px;
+ background: white;
+ box-shadow: 0 0 12px rgb(0 0 0 / 5%);
+ }
+ .d-content {
+ flex: 1;
+ display: flex;
+ padding: 16px;
+ flex-direction: column;
+ border-radius: 4px;
+ overflow: hidden;
+ background: white;
+ box-shadow: 0 0 12px rgb(0 0 0 / 5%);
+ position: relative;
+ box-sizing: border-box;
+ .util {
+ margin-bottom: 15px;
+ display: flex;
+ flex-shrink: 0;
+ }
+ .table-inner {
+ flex: 1;
+ position: relative;
+ }
+ .table {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%
+ }
+ }
+}
+
+.app-container-inner {
+ height: 100%;
+ width: 100%;
+ box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
+ background: white;
+ padding: 20px;
+ box-sizing: border-box;
+}
+
+.layout-horizontal {
+ .header-icon {
+ color: #bfcbd9 !important;
+ }
+
+ .el-dropdown-link {
+ color: #bfcbd9 !important;
+ }
+}
+
+.el-pager li:focus {
+ border: none;
+}
+
+.el-dropdown:focus {
+ border: none;
+ outline: none !important;
+}
+
+.svg-icon:focus {
+ border: none !important;
+ outline: none !important;
+}
+
+/* 小屏幕全局样式 */
+@media screen and (max-width: 800px) {
+ .app-container {
+ padding: 0px 0px;
+ .d-header, .d-content {
+ padding: 10px 8px;
+ }
+ .d-header {
+ margin-top: 10px;
+ }
+ }
+ .d-dialog {
+ width: calc(100% - 6px);
+ margin-left: 6px
+ }
+}
\ No newline at end of file
diff --git a/src/styles/element-dark.scss b/src/styles/element-dark.scss
new file mode 100644
index 0000000..2c20d4a
--- /dev/null
+++ b/src/styles/element-dark.scss
@@ -0,0 +1,194 @@
+// 暗黑模式自定义样式
+html.dark {
+ /* 自定义深色背景颜色 */
+
+ //--el-bg-color: #141414;
+ //--el-bg-color-overlay: #1d1e1f;
+
+ --zb-border-light: 1px solid #4c4d4f;
+
+ body{
+ background: none;
+ }
+
+
+ // 编辑器
+ .w-e-toolbar, .w-e-text-container, .w-e-menu-panel{
+ background: none!important;
+ }
+ // 富文本
+ .md{
+ background: none!important;
+ }
+
+ #app{
+ .sidebar-container{
+ background: var(--el-bg-color)!important;
+ & .el-menu .el-sub-menu > .el-sub-menu__title,
+ & .el-sub-menu .el-menu-item {
+ background-color: var(--el-bg-color) !important;
+
+ &:hover {
+ background-color: var(--el-bg-color) !important;
+ }
+ &.is-active{
+ background-color: #060708!important;
+ }
+ }
+ .el-sub-menu__title {
+ &:hover {
+ background-color: var(--el-bg-color) !important;
+ }
+ }
+ }
+ }
+
+
+
+ .sidebar-logo-container{
+ background: none;
+ box-sizing: border-box;
+ border:var(--zb-border-light);
+ border-left: 0;
+ }
+ .el-drawer__header {
+ span {
+ color: var(--el-text-color-primary) !important;
+ }
+ }
+ .theme-item{
+ color: var(--el-text-color-primary) !important;
+ }
+
+
+ .el-table__header th {
+ font-weight: bold;
+ color: white;
+ }
+ .footer-layout{
+ background: none;
+ color: white;
+ }
+
+
+ .zb-pro-table{
+ .header{
+ background: none!important;
+ border: var(--zb-border-light);
+ }
+ .footer{
+ background: none!important;
+ border: var(--zb-border-light);
+ }
+ .el-table__header th{
+ color: white!important;
+ }
+ }
+ .app-container {
+ .d-header, .d-content {
+ border: 1px solid var(--el-border-color-light);
+ background-color: var(--el-bg-color-overlay);
+ // background: none!important;
+ // border: var(--zb-border-light);
+ }
+ .el-table__header th{
+ color: white!important;
+ }
+ }
+ // header
+ .m-layout-header{
+ color: var(--el-text-color-primary) !important;
+ .header-inner{
+ background-color: var(--el-bg-color)!important;
+ border-bottom:var(--zb-border-light);
+ .header-icon{
+ color:#bfcbd9!important;
+ }
+ }
+ // tagviews
+ .m-tags-view{
+ background: var(--el-bg-color)!important;
+ border: var(--zb-border-light);
+ border-top:none ;
+ border-left: none;
+ box-sizing: border-box;
+ .el-tabs--card>.el-tabs__header{
+ border-bottom: none!important;
+ }
+ }
+
+
+ }
+
+ .main-columns {
+ .layout-columns-sub {
+ border-right: 1px solid var(--el-border-color);
+ .logo {
+ color: #fff;
+ }
+ }
+ }
+ // 内容区
+ .app-main{
+ .echarts-map{
+ background: var(--el-bg-color)!important;
+ }
+ .app-echarts{
+ background: none;
+ }
+
+ .app-container{
+ .header, .footer{
+ border: 1px solid var(--el-border-color-light);
+ background-color: var(--el-bg-color-overlay);
+ // background: none;
+ }
+ }
+ .m-container-layout{
+ .m-container-layout-inner{
+ background: none;
+ color: var(--el-text-color-primary) !important;
+ }
+ }
+
+ .item-group-item{
+ background: none!important;
+ border: var(--zb-border-light);
+ color: #cccccc;
+ }
+
+ .app-container-inner{
+ background: none;
+ }
+ }
+
+ // 底部
+ .footer-layout{
+ border-top:var(--zb-border-light);
+ }
+
+
+
+ // 登录
+ .login-container {
+ background-color: #191919 !important;
+ .login-box {
+ background-color: #000000cc !important;
+ .login-form {
+ background-color: #141414 !important;
+ .title {
+ color: var(--el-text-color-primary) !important;
+ }
+ }
+ }
+ .info-qrcode{
+ background: white;
+ }
+ }
+
+ .sidebar-menu-tree{
+ border:var(--zb-border-light);
+ border-top:none ;
+ border-left: 0;
+ }
+}
diff --git a/src/styles/element.scss b/src/styles/element.scss
new file mode 100644
index 0000000..c888a06
--- /dev/null
+++ b/src/styles/element.scss
@@ -0,0 +1,17 @@
+.el-table__header th {
+ font-weight: bold;
+ color: #252525;
+ background: #fafafa;
+}
+
+.el-table .el-table__header th {
+ background: var(--el-fill-color-light)!important;
+}
+
+
+.d-dialog {
+ .el-dialog__header {
+ padding: 16px;
+ }
+
+}
\ No newline at end of file
diff --git a/src/styles/index.scss b/src/styles/index.scss
new file mode 100644
index 0000000..7cce0d7
--- /dev/null
+++ b/src/styles/index.scss
@@ -0,0 +1,7 @@
+@import './variables.scss';
+@import './sidebar.scss';
+@import './transition.scss';
+@import "./common.scss";
+@import "./element.scss";
+
+
diff --git a/src/styles/login/index.scss b/src/styles/login/index.scss
new file mode 100644
index 0000000..eeb332c
--- /dev/null
+++ b/src/styles/login/index.scss
@@ -0,0 +1,143 @@
+$dark_gray: #889aa4;
+.login-box {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background: white;
+ border-radius: 8px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ .login-left{
+ width: 50%;
+ img{
+ width: 100%;
+ max-width: 900px;
+ }
+ }
+ .login-form{
+ max-width: 480px;
+ width: 50%;
+ padding: 40px;
+ border-radius: 10px;
+ box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
+ box-sizing: border-box;
+ position: relative;
+
+ .info-qrcode{
+ width: 150px;
+ height: 40px;
+ border-radius: 8px;
+ box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
+ position: absolute;
+ top: -60px;
+ right: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: #1492ff;
+ font-size: 16px;
+ &::after{
+ content: "";
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 10px;
+ height: 26px;
+ border-top: 13px solid #fff;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-bottom: 13px solid transparent;
+ position: absolute;
+ top: 40px;
+ right: 16px;
+ }
+ }
+ }
+ .login-title{
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 30px;
+ .title{
+ margin: 0;
+ font-size: 30px;
+ white-space: nowrap;
+ }
+ .icon{
+ width: 60px;
+ }
+ }
+ :deep(.el-input__inner){
+ height: 40px;
+ }
+}
+.login-btn{
+ margin-top: 20px;
+ width: 100%; height: 47px
+}
+.show-pwd {
+ position: absolute;
+ right: 10px;
+ top: 7px;
+ font-size: 16px;
+ color: $dark_gray;
+ cursor: pointer;
+ user-select: none;
+ :deep(.svg-icon){
+ vertical-align: 0;
+ }
+}
+.login-container {
+ background-color: #f0f2f5;
+ height: 100%;
+ width: 100%;
+ overflow: hidden;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ padding: 25px 25px;
+ box-sizing: border-box;
+}
+.login-dark{
+ position: absolute;
+ right: 20px;
+ top: 20px;
+}
+
+.qrcode{
+ position: absolute;
+ right: 0;
+ top: 0;
+ cursor: pointer;
+ width: 30px;
+}
+.login-qrcode{
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+ img{
+ width: 60%;
+ }
+ .title{
+
+ }
+}
+
+@media (max-width: 850px){
+ .login-container{
+ padding: 0px;
+ }
+ .login-box{
+ .login-form{
+ width: 88%;
+ .title{
+ font-size: 20px;
+ }
+ }
+ }
+ .login-left{
+ display: none;
+ }
+}
diff --git a/src/styles/public/index.scss b/src/styles/public/index.scss
new file mode 100644
index 0000000..4683aab
--- /dev/null
+++ b/src/styles/public/index.scss
@@ -0,0 +1,89 @@
+
+.d-dialog {
+ .el-dialog__header, .el-dialog__footer{
+ padding: 14px;
+ }
+ .el-dialog__body {
+ border-top: 1px solid var(--el-border-color);
+ border-bottom: 1px solid var(--el-border-color);
+ padding: var(--el-dialog-padding-primary) ;
+ padding-top: calc(var(--el-dialog-padding-primary) + 5px);
+ }
+ .el-dialog__headerbtn {
+ top: 1px
+ }
+}
+
+.d-edit-form {
+ .el-textarea__inner {
+ min-height: 80px !important;
+ }
+}
+.d-detail-form {
+ .el-form-item__label {
+ color: var(--el-text-color-secondary)
+ }
+}
+
+.d-submit-button {
+ padding: 7px 30px;
+}
+
+/* vue Transition特效 */
+/* bounce */
+.bounce-enter-active {
+ animation: bounce-in 0.5s;
+}
+.bounce-leave-active {
+ animation: bounce-in 0.5s reverse;
+}
+@keyframes bounce-in {
+ 0% {
+ transform: scale(0);
+ }
+ 50% {
+ transform: scale(1.25);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
+
+.list-move, /* 对移动中的元素应用的过渡 */
+.list-enter-active,
+.list-leave-active {
+ transition: all 0.5s ease;
+}
+
+.list-enter-from,
+.list-leave-to {
+ opacity: 0;
+ transform: translateX(30px);
+}
+
+// /* 确保将离开的元素从布局流中删除
+// 以便能够正确地计算移动的动画。 */
+// .list-leave-active {
+// position: absolute;
+// }
+
+/* 1. 声明过渡效果 */
+.fade-move,
+.fade-enter-active,
+.fade-leave-active {
+ transition: all 0.5s cubic-bezier(0.55, 0, 0.1, 1);
+}
+
+/* 2. 声明进入和离开的状态 */
+.fade-enter-from,
+.fade-leave-to {
+ opacity: 0;
+ transform: scaleY(0.01) translate(30px, 0);
+}
+
+// /* 3. 确保离开的项目被移除出了布局流
+// 以便正确地计算移动时的动画效果。 */
+// .fade-leave-active {
+// position: absolute;
+// }
\ No newline at end of file
diff --git a/src/styles/sidebar.scss b/src/styles/sidebar.scss
new file mode 100644
index 0000000..47b8a01
--- /dev/null
+++ b/src/styles/sidebar.scss
@@ -0,0 +1,228 @@
+.layout-vertical{
+ .main-container {
+ min-height: 100%;
+ transition: margin-left 0.28s;
+ margin-left: $sideBarWidth;
+ position: relative;
+ }
+
+ .hideSliderLayout {
+ margin-left: 0;
+ .el-menu--horizontal {
+ border-bottom: none;
+ }
+ }
+ .sidebar-container {
+ transition: width 0.28s;
+ width: $sideBarWidth !important;
+ background-color: $menuBg;
+ height: 100%;
+ position: fixed;
+ font-size: 0px;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 98;
+ overflow: hidden;
+ // reset element-ui css
+ .horizontal-collapse-transition {
+ transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
+ }
+
+ .scrollbar-wrapper {
+ overflow-x: hidden !important;
+ }
+
+ .el-scrollbar__bar.is-vertical {
+ right: 0px;
+ }
+
+ .el-scrollbar {
+ height: 100%;
+ }
+
+ &.has-logo {
+ .el-scrollbar {
+ height: calc(100% - 50px);
+ }
+ }
+
+ .is-horizontal {
+ display: none;
+ }
+
+ a {
+ //display: inline-block;
+ width: 100%;
+ overflow: hidden;
+ }
+
+
+ .sub-el-icon {
+ margin-right: 12px;
+ margin-left: -2px;
+ }
+
+ .el-menu {
+ border: none;
+ height: 100%;
+ width: 100% !important;
+ background: none;
+ }
+
+ // menu hover
+ .sub-menu-title-noDropdown,
+ .el-sub-menu__title {
+ &:hover {
+ background-color: $menuHover !important;
+ }
+ }
+
+ .is-active > .el-sub-menu__title {
+ color: $subMenuActiveText !important;
+ }
+
+ & .nest-menu .el-sub-menu > .el-sub-menu__title,
+ & .el-sub-menu .el-menu-item {
+ min-width: $sideBarWidth !important;
+ background-color: $subMenuBg !important;
+
+ &:hover {
+ background-color: $subMenuHover !important;
+ }
+ }
+ }
+
+ .hideSidebar {
+ .sidebar-container {
+ width: 60px !important;
+ }
+
+ .main-container {
+ margin-left: 60px;
+ }
+
+ .sub-menu-title-noDropdown {
+ padding: 0 !important;
+ position: relative;
+
+ .el-tooltip {
+ padding: 0 !important;
+
+ .svg-icon {
+ margin-left: 20px;
+ }
+
+ .sub-el-icon {
+ margin-left: 19px;
+ }
+ }
+ }
+
+ .el-submenu {
+ overflow: hidden;
+
+ & > .el-submenu__title {
+ padding: 0 !important;
+
+ .svg-icon {
+ margin-left: 20px;
+ }
+
+ .sub-el-icon {
+ margin-left: 19px;
+ }
+
+ .el-sub-menu__icon-arrow {
+ display: none;
+ }
+ }
+ }
+
+ .el-menu--collapse {
+ .el-sub-menu {
+ & > .el-sub-menu__title {
+ & > span {
+ height: 0;
+ width: 0;
+ overflow: hidden;
+ visibility: hidden;
+ display: inline-block;
+ }
+ }
+ }
+ }
+ }
+
+ .el-menu--collapse .el-menu .el-sub-menu {
+ min-width: $sideBarWidth !important;
+ }
+
+ // mobile responsive
+ .mobile {
+ .main-container {
+ margin-left: 0px;
+ }
+
+ .sidebar-container {
+ transition: transform 0.28s;
+ width: $sideBarWidth !important;
+ }
+
+ &.hideSidebar {
+ .sidebar-container {
+ pointer-events: none;
+ transition-duration: 0.3s;
+ transform: translate3d(-$sideBarWidth, 0, 0);
+ }
+ }
+ }
+
+ .withoutAnimation {
+ .main-container,
+ .sidebar-container {
+ transition: none;
+ }
+ }
+
+ // when menu collapsed
+ .el-menu--vertical {
+ & > .el-menu {
+ .svg-icon {
+ margin-right: 16px;
+ }
+ .sub-el-icon {
+ margin-right: 12px;
+ margin-left: -2px;
+ }
+ }
+
+ .nest-menu .el-sub-menu > .el-sub-menu__title,
+ .el-menu-item {
+ &:hover {
+ // you can use $subMenuHover
+ background-color: $menuHover !important;
+ }
+ }
+
+ // the scroll bar appears when the subMenu is too long
+ > .el-menu--popup {
+ max-height: 100vh;
+ overflow-y: auto;
+
+ &::-webkit-scrollbar-track-piece {
+ background: #d3dce6;
+ }
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: #99a9bf;
+ border-radius: 20px;
+ }
+ }
+ }
+}
+
diff --git a/src/styles/tailwind/index.scss b/src/styles/tailwind/index.scss
new file mode 100644
index 0000000..b6c4771
--- /dev/null
+++ b/src/styles/tailwind/index.scss
@@ -0,0 +1,21 @@
+@tailwind base;
+@tailwind components;
+@layer components {
+ .d-title {
+ border-color: var(--el-border-color);
+ @apply font-bold border-l-sky-400 border-l-4 pl-4 m-2 bg-slate-100 rounded-sm py-2 dark:bg-transparent dark:border-y dark:border-r;
+ }
+ .d-article-content {
+ img {
+ display: inline;
+ }
+ p {
+ margin: 20px 0;
+ line-height: 30px
+ }
+ }
+}
+@tailwind utilities;
+@layer utilities {
+
+}
diff --git a/src/styles/transition.scss b/src/styles/transition.scss
new file mode 100644
index 0000000..73a1720
--- /dev/null
+++ b/src/styles/transition.scss
@@ -0,0 +1,51 @@
+// global transition css
+
+/* fade */
+.fade-enter-active,
+.fade-leave-active {
+ transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+ opacity: 0;
+}
+
+/* 路由 */
+.fade-slide-leave-active,
+.fade-slide-enter-active {
+ transition: all 0.3s;
+}
+
+.fade-slide-enter-from {
+ opacity: 0;
+ transform: translateX(-30px);
+}
+
+.fade-slide-leave-to {
+ opacity: 0;
+ transform: translateX(30px);
+}
+
+// logo动画
+.sidebarLogoFade-enter-active {
+ transition: opacity 1.5s;
+}
+.sidebarLogoFade-enter-from{
+ opacity: 0;
+}
+.sidebarLogoFade-leave-to {
+ opacity: 0;
+}
+
+
+
+// 面包屑动画 方案1
+.breadcrumb-enter-active {
+ transition: all 0.25s;
+}
+.breadcrumb-enter-from,
+.breadcrumb-leave-active {
+ opacity: 0;
+ transform: translateX(10px) skewX(-10deg);
+}
diff --git a/src/styles/variables.scss b/src/styles/variables.scss
new file mode 100644
index 0000000..92abe7b
--- /dev/null
+++ b/src/styles/variables.scss
@@ -0,0 +1,37 @@
+// base color
+$blue: #324157;
+$light-blue: #3a71a8;
+$red: #c03639;
+$pink: #e65d6e;
+$green: #30b08f;
+$tiffany: #4ab7bd;
+$yellow: #fec171;
+$panGreen: #30b08f;
+
+/* 全局 css 变量 */
+$primaryColor: var(--el-color-primary);
+
+// sidebar
+$menuText: #bfcbd9;
+$menuActiveText: #409eff;
+$subMenuActiveText: #f4f4f5;
+
+$menuBg: #304156;
+$menuHover: #263445;
+
+$subMenuBg: #1f2d3d;
+$subMenuHover: #001528;
+
+$sideBarWidth: 210px;
+
+:export {
+ menuText: $menuText;
+ menuActiveText: $menuActiveText;
+ subMenuActiveText: $subMenuActiveText;
+ menuBg: $menuBg;
+ menuHover: $menuHover;
+ subMenuBg: $subMenuBg;
+ subMenuHover: $subMenuHover;
+ sideBarWidth: $sideBarWidth;
+ primaryColor: $primaryColor;
+}
diff --git a/src/views/home/index.vue b/src/views/home/index.vue
new file mode 100644
index 0000000..d02a4d1
--- /dev/null
+++ b/src/views/home/index.vue
@@ -0,0 +1,9 @@
+
+
+
+
+ 主页
+
+
\ No newline at end of file
diff --git a/src/views/login/components/LoginForm.vue b/src/views/login/components/LoginForm.vue
new file mode 100644
index 0000000..5bab321
--- /dev/null
+++ b/src/views/login/components/LoginForm.vue
@@ -0,0 +1,140 @@
+
+
+
+
心理测评系统后台管理
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 记住密码
+
+ 登录
+
+
+
+
+
+
diff --git a/src/views/login/index.vue b/src/views/login/index.vue
new file mode 100644
index 0000000..d747e54
--- /dev/null
+++ b/src/views/login/index.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
new file mode 100644
index 0000000..323c78a
--- /dev/null
+++ b/src/vite-env.d.ts
@@ -0,0 +1,7 @@
+///
+
+declare module '*.vue' {
+ import type { DefineComponent } from 'vue'
+ const component: DefineComponent<{}, {}, any>
+ export default component
+}
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..7b3288f
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,30 @@
+/** @type {import('tailwindcss').Config} */
+const plugin = require('tailwindcss/plugin')
+
+module.exports = {
+ content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
+ darkMode: 'class',
+ theme: {
+ extend: {},
+ },
+ plugins: [
+ plugin(function ({ addComponents, theme }) {
+ addComponents({
+ '.el-bg-color': {
+ backgroundColor: 'var(--el-bg-color)',
+ },
+ '.el-bg-color-overlay': {
+ backgroundColor: 'var(--el-bg-color-overlay)',
+ },
+ '.el-border-color': {
+ borderColor: 'var(--el-border-color)',
+ },
+ '.el-border': {
+ border: '1px solid var(--el-border-color)',
+ },
+ })
+ })
+ ]
+ // plugins: [require("@tailwindcss/typography")],
+}
+
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..e93029c
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,32 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "strict": false,
+ "jsx": "preserve",
+ "sourceMap": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "lib": ["ESNext", "DOM"],
+ "noUnusedLocals": false,
+ "allowSyntheticDefaultImports": true,
+ // 跳过库检查,解决打包失败
+ "skipLibCheck": true,
+ // 解析非相对模块名的基准目录
+ "baseUrl": "./",
+ // 模块名到基于 baseUrl 的路径映射的列表。
+ "paths": {
+ "@": ["src"],
+ "@/*": ["src/*"],
+ "@lib/*": ["src/libs/*"],
+ "@h5/*": ["src/modules/h5/*"],
+ "@admin/*": ["src/modules/admin/*"],
+
+ }
+ },
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
+ "exclude": ["node_modules","dist","**/*.js"]
+}
diff --git a/vite.config.ts b/vite.config.ts
new file mode 100644
index 0000000..ed49113
--- /dev/null
+++ b/vite.config.ts
@@ -0,0 +1,131 @@
+import { defineConfig, ConfigEnv, UserConfig, loadEnv } from 'vite'
+import { resolve, join } from 'path'
+import vue from '@vitejs/plugin-vue'
+import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
+import { readdirSync } from "fs";
+import dotenv from 'dotenv'
+dotenv.config()
+if (process.env.NODE_ENV === 'development') {
+ dotenv.config({ path: '.env.development' });
+}
+
+// 增加 vue文件 script name值
+import vueSetupExtend from 'vite-plugin-vue-setup-extend'
+// 生产gz文件
+import viteCompression from 'vite-plugin-compression'
+
+const pagePath = 'src/modules'
+// 获取npm run dev后缀 配置的环境变量
+const npm_config_page: string = process.env.npm_config_page || ''
+let entryPath = resolve(__dirname, `./${pagePath}`);
+const entrys = readdirSync(entryPath).reduce((obj, dirname) => {
+ obj[dirname] = join(entryPath, dirname, "index.html");
+ return obj;
+}, {});
+if(npm_config_page && !entrys[npm_config_page]!) {
+ throw new Error(`找不到${npm_config_page}页面,请检查${pagePath}目录下是否存在该页面`)
+}
+const rollupOptions = npm_config_page ? { [npm_config_page]: entrys[npm_config_page] } : {...entrys, index: resolve(__dirname, 'index.html')};
+
+export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
+ const { VITE_PORT, VITE_BASE_API, VITE_BASE_PORT } = loadEnv(mode, process.cwd());
+ // 多页面代理配置
+ const mpaProxy = {}
+ const target = `http://localhost:${Number(VITE_PORT)}`;
+ if(!npm_config_page) for (let mpaName in entrys) {
+ mpaProxy[`^/${mpaName}/.*/main\.ts$`] = {
+ target,
+ rewrite: () => `/${mpaName}/main.ts`
+ }
+ mpaProxy[`^/${mpaName}/.*`] = {
+ target,
+ rewrite: (path: string) => path.replace(`/${mpaName}`, `/${pagePath}/${mpaName}/`)
+ };
+ }
+ // vite配置 https://vitejs.dev/config/
+ return {
+ root: npm_config_page ? resolve(__dirname, `./src/modules/${npm_config_page}`) : process.cwd(),
+ plugins: [
+ vue(),
+ vueSetupExtend(),
+ // * 使用 svg 图标
+ createSvgIconsPlugin({
+ // 指定需要缓存的图标文件夹
+ iconDirs: [resolve(process.cwd(), 'src/icons/svg')],
+ // 指定symbolId格式
+ symbolId: 'icon-[dir]-[name]',
+ }),
+ // gzip压缩 生产环境生成 .gz 文件
+ mode === 'production' && viteCompression({
+ verbose: true,
+ disable: false,
+ threshold: 10240,
+ algorithm: 'gzip',
+ ext: '.gz',
+ }),
+ mode === 'development' && (() => {
+ return {
+ name: 'configure-server',
+ configureServer(server) {
+ return () => {
+ server.middlewares.use(async (req, res, next) => {
+ for (let mpaName in entrys) {
+ mpaName = 'src/modules/' + mpaName;
+ const regex = new RegExp(`(^${server.config.base}${mpaName})(?=/)|(^${server.config.base}${mpaName}$)`);
+ if (req.originalUrl?.match(regex)) {
+ req.url = `/${mpaName}/index.html`;
+ break;
+ }
+ }
+ next();
+ });
+ };
+ },
+ }
+ })(),
+ ],
+ css: {
+ preprocessorOptions: {
+ scss: {
+ additionalData: `@use "./src/styles/index.scss" as *;`
+ }
+ }
+ },
+ // 配置别名
+ resolve: {
+ alias: {
+ '@': resolve(__dirname, 'src'),
+ '@lib': resolve(__dirname, 'src/libs'),
+ 'static': resolve(__dirname, 'public/static'),
+ "@h5": resolve(__dirname, `${pagePath}/h5`),
+ "@admin": resolve(__dirname, `${pagePath}/admin`),
+ },
+ extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
+ },
+ //启动服务配置
+ server: {
+ port: Number(VITE_PORT),
+ open: true,
+ https: false,
+ proxy: {
+ [VITE_BASE_API]: {
+ target: `http://175.178.70.208/stage-api/`,
+ changeOrigin: true,
+ rewrite: path => path.replace(new RegExp(VITE_BASE_API), "")
+ },
+ ...mpaProxy,
+ }
+ },
+ optimizeDeps: {
+ exclude: ['path']
+ },
+ build: {
+ rollupOptions: {
+ input: {
+ ...rollupOptions
+ },
+ output: { dir: "./dist" },
+ },
+ },
+ }
+})