特性: 增加 husky
This commit is contained in:
parent
3c1001dd76
commit
7103c121f3
42
.eslintrc.js
42
.eslintrc.js
|
|
@ -16,11 +16,51 @@ module.exports = {
|
||||||
ecmaVersion: 'latest',
|
ecmaVersion: 'latest',
|
||||||
parser: '@typescript-eslint/parser',
|
parser: '@typescript-eslint/parser',
|
||||||
sourceType: 'module',
|
sourceType: 'module',
|
||||||
|
ecmaFeatures: {
|
||||||
|
jsx: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
plugins: ['vue', '@typescript-eslint'],
|
plugins: ['vue', '@typescript-eslint'],
|
||||||
globals: {
|
globals: {
|
||||||
defineProps: 'readonly',
|
defineProps: 'readonly',
|
||||||
defineEmits: 'readonly',
|
defineEmits: 'readonly',
|
||||||
},
|
},
|
||||||
rules: {},
|
rules: {
|
||||||
|
'no-console': 'off', // 禁止调用console对象的方法。
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
|
||||||
|
'no-use-before-define': 'off',
|
||||||
|
'@typescript-eslint/no-use-before-define': 'off',
|
||||||
|
'@typescript-eslint/ban-ts-comment': 'off',
|
||||||
|
'@typescript-eslint/no-empty-function': ['off'], // 关闭空函数警告
|
||||||
|
'@typescript-eslint/no-inferrable-types': 'off', // 可以轻松推断的显式类型可能会增加不必要的冗长
|
||||||
|
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间
|
||||||
|
'@typescript-eslint/ban-types': 'off', // 禁止使用特定类型
|
||||||
|
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
|
||||||
|
'vue/no-v-html': 'off', // 禁止使用 v-html
|
||||||
|
'no-undef': 'off',
|
||||||
|
'no-redeclare': 'off',
|
||||||
|
'no-self-assign': 'off',
|
||||||
|
'no-sparse-arrays': 'off',
|
||||||
|
'vue/valid-v-for': 'off',
|
||||||
|
'vue/no-unused-vars': 'off',
|
||||||
|
'vue/require-v-for-key': 'off',
|
||||||
|
'no-useless-escape': 'off',
|
||||||
|
'vue/require-explicit-emits': 'off',
|
||||||
|
'no-case-declarations': 'off', // 不允许在 case 子句中使用词法声明
|
||||||
|
//禁止非空断言非空断言是在变量后面添加一个感叹号(!),表示该变量一定存在,不会为 null 或 undefined
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||||
|
'vue/require-prop-types': 'off',
|
||||||
|
'@typescript-eslint/no-this-alias': 'off',
|
||||||
|
'no-async-promise-executor': 'off',
|
||||||
|
'vue/no-template-shadow': 'off',
|
||||||
|
'vue/require-default-prop': 'off', // 此规则要求为每个 prop 为必填时,必须提供默认值
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
// // 禁止定义未使用的变量
|
||||||
|
'off',
|
||||||
|
{
|
||||||
|
argsIgnorePattern: '^_',
|
||||||
|
varsIgnorePattern: '^_',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// 一行的字符数,如果超过会进行换行,默认为80
|
// 一行的字符数,如果超过会进行换行,默认为80
|
||||||
printWidth: 100,
|
printWidth: 140,
|
||||||
|
// 缩进制表符宽度 | 空格数
|
||||||
|
tabWidth: 2,
|
||||||
// 行位是否使用分号,默认为true
|
// 行位是否使用分号,默认为true
|
||||||
semi: false,
|
semi: false,
|
||||||
vueIndentScriptAndStyle: true,
|
vueIndentScriptAndStyle: true,
|
||||||
|
|
|
||||||
|
|
@ -2,82 +2,83 @@
|
||||||
// cz.config.js kk
|
// cz.config.js kk
|
||||||
/** @type {import('cz-git').CommitizenGitOptions} */
|
/** @type {import('cz-git').CommitizenGitOptions} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
ignores: [commit => commit.includes("init")],
|
ignores: [(commit) => commit.includes('init')],
|
||||||
extends: ["@commitlint/config-conventional"],
|
extends: ['@commitlint/config-conventional'],
|
||||||
// alias: { fd: 'docs: fix typos' },
|
// alias: { fd: 'docs: fix typos' },
|
||||||
// messages: {
|
// messages: {
|
||||||
// type: 'Select the type of change that you\'re committing:',
|
// type: 'Select the type of change that you\'re committing:',
|
||||||
// scope: 'Denote the SCOPE of this change (optional):',
|
// scope: 'Denote the SCOPE of this change (optional):',
|
||||||
// customScope: 'Denote the SCOPE of this chang e:',
|
// customScope: 'Denote the SCOPE of this chang e:',
|
||||||
// subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
|
// 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',
|
// 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',
|
// breaking: 'List any BREAKING CHANGES (optional). Use "|" to break new line:\n',
|
||||||
// footerPrefixsSelect: 'Select the ISSUES type of changeList by this change (optional):',
|
// footerPrefixsSelect: 'Select the ISSUES type of changeList by this change (optional):',
|
||||||
// customFooterPrefixs: 'Input ISSUES prefix:',
|
// customFooterPrefixs: 'Input ISSUES prefix:',
|
||||||
// footer: 'List any ISSUES by this change. E.g.: #31, #34:\n',
|
// footer: 'List any ISSUES by this change. E.g.: #31, #34:\n',
|
||||||
// confirmCommit: 'Are you sure you want to proceed with the commit above?'
|
// confirmCommit: 'Are you sure you want to proceed with the commit above?'
|
||||||
// },
|
// },
|
||||||
prompt: {
|
prompt: {
|
||||||
// 中英文对照版
|
// 中英文对照版
|
||||||
messages: {
|
messages: {
|
||||||
type: '选择你要提交的类型 :',
|
type: '选择你要提交的类型 :',
|
||||||
scope: '选择一个提交范围(可选):',
|
scope: '选择一个提交范围(可选):',
|
||||||
customScope: '请输入自定义的提交范围 :',
|
customScope: '请输入自定义的提交范围 :',
|
||||||
subject: '填写简短精炼的变更描述 :\n',
|
subject: '填写简短精炼的变更描述 :\n',
|
||||||
body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
|
body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
|
||||||
breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
|
breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
|
||||||
footerPrefixesSelect: '选择关联issue前缀(可选):',
|
footerPrefixesSelect: '选择关联issue前缀(可选):',
|
||||||
customFooterPrefix: '输入自定义issue前缀 :',
|
customFooterPrefix: '输入自定义issue前缀 :',
|
||||||
footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
|
footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
|
||||||
confirmCommit: '是否提交或修改commit ?'
|
confirmCommit: '是否提交或修改commit ?',
|
||||||
},
|
},
|
||||||
types: [
|
types: [
|
||||||
{ value: '特性', name: '特性: 新增功能' },
|
{ value: '特性', name: '特性: 新增功能' },
|
||||||
{ value: '修复', name: '修复: 修复缺陷' },
|
{ value: '修复', name: '修复: 修复缺陷' },
|
||||||
{ value: '文档', name: '文档: 文档变更' },
|
{ value: '文档', name: '文档: 文档变更' },
|
||||||
{ value: '格式', name: '格式: 代码格式(不影响功能,例如空格、分号等格式修正)' },
|
{ value: '格式', name: '格式: 代码格式(不影响功能,例如空格、分号等格式修正)' },
|
||||||
{ value: '重构', name: '重构: 代码重构(不包括 bug 修复、功能新增)' },
|
{ value: '重构', name: '重构: 代码重构(不包括 bug 修复、功能新增)' },
|
||||||
{ value: '性能', name: '性能: 性能优化' },
|
{ value: '性能', name: '性能: 性能优化' },
|
||||||
{ value: '测试', name: '测试: 添加疏漏测试或已有测试改动' },
|
{ value: '测试', name: '测试: 添加疏漏测试或已有测试改动' },
|
||||||
{ value: '构建', name: '构建: 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)' },
|
{
|
||||||
{ value: '集成', name: '集成: 修改 CI 配置、脚本' },
|
value: '构建',
|
||||||
{ value: '回退', name: '回退: 回滚 commit' },
|
name: '构建: 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)',
|
||||||
{ value: '其他', name: '其他: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)' },
|
},
|
||||||
|
{ value: '集成', name: '集成: 修改 CI 配置、脚本' },
|
||||||
],
|
{ value: '回退', name: '回退: 回滚 commit' },
|
||||||
// emptyScopesAlias: 'empty: 不填写',
|
{ value: '其他', name: '其他: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)' },
|
||||||
// customScopesAlias: 'custom: 自定义',
|
],
|
||||||
|
// emptyScopesAlias: 'empty: 不填写',
|
||||||
useEmoji: true,
|
// customScopesAlias: 'custom: 自定义',
|
||||||
// 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: ''
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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: '',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"build:ts": "vue-tsc --noEmit --skipLibCheck && vite build",
|
"build:ts": "vue-tsc --noEmit --skipLibCheck && vite build",
|
||||||
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx",
|
"lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx",
|
||||||
"lint:fix": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
|
"lint:fix": "eslint . --ext .vue,.js,.ts,.jsx,.tsx --fix",
|
||||||
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
|
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install"
|
||||||
},
|
},
|
||||||
|
|
@ -61,6 +61,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^17.3.0",
|
"@commitlint/cli": "^17.3.0",
|
||||||
"@commitlint/config-conventional": "^17.3.0",
|
"@commitlint/config-conventional": "^17.3.0",
|
||||||
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.32.0",
|
"@typescript-eslint/eslint-plugin": "^5.32.0",
|
||||||
"@typescript-eslint/parser": "^5.32.0",
|
"@typescript-eslint/parser": "^5.32.0",
|
||||||
"@vitejs/plugin-vue": "^3.0.0",
|
"@vitejs/plugin-vue": "^3.0.0",
|
||||||
|
|
@ -96,6 +97,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.{vue,js,ts,jsx,tsx}": ["npm run lint","git add"]
|
"src/s*.{vue,js,ts,jsx,tsx}": [
|
||||||
|
"npm run lint:prettier",
|
||||||
|
"npm run lint:fix",
|
||||||
|
"git add ."
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,9 @@ devDependencies:
|
||||||
'@commitlint/config-conventional':
|
'@commitlint/config-conventional':
|
||||||
specifier: ^17.3.0
|
specifier: ^17.3.0
|
||||||
version: 17.8.1
|
version: 17.8.1
|
||||||
|
'@element-plus/icons-vue':
|
||||||
|
specifier: ^2.3.1
|
||||||
|
version: 2.3.1(vue@3.3.13)
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: ^5.32.0
|
specifier: ^5.32.0
|
||||||
version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.56.0)(typescript@4.9.5)
|
version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.56.0)(typescript@4.9.5)
|
||||||
|
|
@ -201,7 +204,7 @@ devDependencies:
|
||||||
version: 0.7.3(vite@3.2.7)(vue@3.3.13)
|
version: 0.7.3(vite@3.2.7)(vue@3.3.13)
|
||||||
vite:
|
vite:
|
||||||
specifier: ^3.0.0
|
specifier: ^3.0.0
|
||||||
version: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
version: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||||
vite-plugin-compression:
|
vite-plugin-compression:
|
||||||
specifier: ^0.5.1
|
specifier: ^0.5.1
|
||||||
version: 0.5.1(vite@3.2.7)
|
version: 0.5.1(vite@3.2.7)
|
||||||
|
|
@ -397,7 +400,7 @@ packages:
|
||||||
lodash.merge: 4.6.2
|
lodash.merge: 4.6.2
|
||||||
lodash.uniq: 4.5.0
|
lodash.uniq: 4.5.0
|
||||||
resolve-from: 5.0.0
|
resolve-from: 5.0.0
|
||||||
ts-node: 10.9.2(@types/node@18.19.3)(typescript@4.9.5)
|
ts-node: 10.9.2(@types/node@20.5.1)(typescript@4.9.5)
|
||||||
typescript: 4.9.5
|
typescript: 4.9.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@swc/core'
|
- '@swc/core'
|
||||||
|
|
@ -534,7 +537,6 @@ packages:
|
||||||
vue: ^3.2.0
|
vue: ^3.2.0
|
||||||
dependencies:
|
dependencies:
|
||||||
vue: 3.3.13(typescript@4.9.5)
|
vue: 3.3.13(typescript@4.9.5)
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@esbuild/android-arm@0.15.18:
|
/@esbuild/android-arm@0.15.18:
|
||||||
resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
|
resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
|
||||||
|
|
@ -774,6 +776,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 5.26.5
|
undici-types: 5.26.5
|
||||||
dev: true
|
dev: true
|
||||||
|
optional: true
|
||||||
|
|
||||||
/@types/node@20.10.5:
|
/@types/node@20.10.5:
|
||||||
resolution: {integrity: sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==}
|
resolution: {integrity: sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==}
|
||||||
|
|
@ -1121,7 +1124,7 @@ packages:
|
||||||
vite: ^3.0.0
|
vite: ^3.0.0
|
||||||
vue: ^3.2.25
|
vue: ^3.2.25
|
||||||
dependencies:
|
dependencies:
|
||||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||||
vue: 3.3.13(typescript@4.9.5)
|
vue: 3.3.13(typescript@4.9.5)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
|
@ -2350,7 +2353,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.5.1
|
'@types/node': 20.5.1
|
||||||
cosmiconfig: 8.3.6(typescript@4.9.5)
|
cosmiconfig: 8.3.6(typescript@4.9.5)
|
||||||
ts-node: 10.9.2(@types/node@18.19.3)(typescript@4.9.5)
|
ts-node: 10.9.2(@types/node@20.5.1)(typescript@4.9.5)
|
||||||
typescript: 4.9.5
|
typescript: 4.9.5
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
|
@ -6672,7 +6675,7 @@ packages:
|
||||||
typescript: 4.9.5
|
typescript: 4.9.5
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/ts-node@10.9.2(@types/node@18.19.3)(typescript@4.9.5):
|
/ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.5):
|
||||||
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -6691,7 +6694,7 @@ packages:
|
||||||
'@tsconfig/node12': 1.0.11
|
'@tsconfig/node12': 1.0.11
|
||||||
'@tsconfig/node14': 1.0.3
|
'@tsconfig/node14': 1.0.3
|
||||||
'@tsconfig/node16': 1.0.4
|
'@tsconfig/node16': 1.0.4
|
||||||
'@types/node': 18.19.3
|
'@types/node': 20.5.1
|
||||||
acorn: 8.11.2
|
acorn: 8.11.2
|
||||||
acorn-walk: 8.3.1
|
acorn-walk: 8.3.1
|
||||||
arg: 4.1.3
|
arg: 4.1.3
|
||||||
|
|
@ -6937,7 +6940,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.11.2
|
acorn: 8.11.2
|
||||||
chokidar: 3.5.3
|
chokidar: 3.5.3
|
||||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||||
webpack-sources: 3.2.3
|
webpack-sources: 3.2.3
|
||||||
webpack-virtual-modules: 0.4.6
|
webpack-virtual-modules: 0.4.6
|
||||||
dev: true
|
dev: true
|
||||||
|
|
@ -6961,7 +6964,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.11.2
|
acorn: 8.11.2
|
||||||
chokidar: 3.5.3
|
chokidar: 3.5.3
|
||||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||||
webpack-sources: 3.2.3
|
webpack-sources: 3.2.3
|
||||||
webpack-virtual-modules: 0.4.6
|
webpack-virtual-modules: 0.4.6
|
||||||
dev: true
|
dev: true
|
||||||
|
|
@ -7135,7 +7138,7 @@ packages:
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
debug: 4.3.4(supports-color@9.4.0)
|
debug: 4.3.4(supports-color@9.4.0)
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
@ -7152,7 +7155,7 @@ packages:
|
||||||
fs-extra: 10.1.0
|
fs-extra: 10.1.0
|
||||||
magic-string: 0.25.9
|
magic-string: 0.25.9
|
||||||
pathe: 0.2.0
|
pathe: 0.2.0
|
||||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite-plugin-svg-icons@2.0.1(vite@3.2.7):
|
/vite-plugin-svg-icons@2.0.1(vite@3.2.7):
|
||||||
|
|
@ -7168,7 +7171,7 @@ packages:
|
||||||
pathe: 0.2.0
|
pathe: 0.2.0
|
||||||
svg-baker: 1.7.0
|
svg-baker: 1.7.0
|
||||||
svgo: 2.8.0
|
svgo: 2.8.0
|
||||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
@ -7180,10 +7183,10 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vue/compiler-sfc': 3.3.13
|
'@vue/compiler-sfc': 3.3.13
|
||||||
magic-string: 0.25.9
|
magic-string: 0.25.9
|
||||||
vite: 3.2.7(@types/node@18.19.3)(sass@1.69.5)
|
vite: 3.2.7(@types/node@20.5.1)(sass@1.69.5)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/vite@3.2.7(@types/node@18.19.3)(sass@1.69.5):
|
/vite@3.2.7(@types/node@20.5.1)(sass@1.69.5):
|
||||||
resolution: {integrity: sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==}
|
resolution: {integrity: sha512-29pdXjk49xAP0QBr0xXqu2s5jiQIXNvE/xwd0vUizYT2Hzqe4BksNNoWllFVXJf4eLZ+UlVQmXfB4lWrc+t18g==}
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
engines: {node: ^14.18.0 || >=16.0.0}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -7208,7 +7211,7 @@ packages:
|
||||||
terser:
|
terser:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 18.19.3
|
'@types/node': 20.5.1
|
||||||
esbuild: 0.15.18
|
esbuild: 0.15.18
|
||||||
postcss: 8.4.32
|
postcss: 8.4.32
|
||||||
resolve: 1.22.8
|
resolve: 1.22.8
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {computed} from "vue";
|
import { computed } from 'vue'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
// 配置element中文
|
// 配置element中文
|
||||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||||
|
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
// 配置全局组件大小
|
// 配置全局组件大小
|
||||||
const globalComSize = computed(():string=>SettingStore.themeConfig.globalComSize)
|
const globalComSize = computed((): string => SettingStore.themeConfig.globalComSize)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,44 @@
|
||||||
export const errorCodeType = function(code:string):string{
|
export const errorCodeType = function (code: string): string {
|
||||||
let errMessage:string = "未知错误"
|
let errMessage = '未知错误'
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 400:
|
case 400:
|
||||||
errMessage = '请求失败!请您稍后重试'
|
errMessage = '请求失败!请您稍后重试'
|
||||||
break
|
break
|
||||||
case 401:
|
case 401:
|
||||||
errMessage = '未授权,请重新登录'
|
errMessage = '未授权,请重新登录'
|
||||||
break
|
break
|
||||||
case 403:
|
case 403:
|
||||||
errMessage = '当前账号无权限访问!'
|
errMessage = '当前账号无权限访问!'
|
||||||
break
|
break
|
||||||
case 404:
|
case 404:
|
||||||
errMessage = '你所访问的资源不存在!'
|
errMessage = '你所访问的资源不存在!'
|
||||||
break
|
break
|
||||||
case 405:
|
case 405:
|
||||||
errMessage = '请求方式错误!请您稍后重试'
|
errMessage = '请求方式错误!请您稍后重试'
|
||||||
break
|
break
|
||||||
case 408:
|
case 408:
|
||||||
errMessage = '请求超时!请您稍后重试'
|
errMessage = '请求超时!请您稍后重试'
|
||||||
break
|
break
|
||||||
case 500:
|
case 500:
|
||||||
errMessage = '服务器端出错'
|
errMessage = '服务器端出错'
|
||||||
break
|
break
|
||||||
case 501:
|
case 501:
|
||||||
errMessage = '网络未实现'
|
errMessage = '网络未实现'
|
||||||
break
|
break
|
||||||
case 502:
|
case 502:
|
||||||
errMessage = '网络错误'
|
errMessage = '网络错误'
|
||||||
break
|
break
|
||||||
case 503:
|
case 503:
|
||||||
errMessage = '服务不可用'
|
errMessage = '服务不可用'
|
||||||
break
|
break
|
||||||
case 504:
|
case 504:
|
||||||
errMessage = '网络超时'
|
errMessage = '网络超时'
|
||||||
break
|
break
|
||||||
case 505:
|
case 505:
|
||||||
errMessage = 'http版本不支持该请求'
|
errMessage = 'http版本不支持该请求'
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
errMessage = `其他连接错误 --${code}`
|
errMessage = `其他连接错误 --${code}`
|
||||||
}
|
}
|
||||||
return errMessage
|
return errMessage
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,62 @@
|
||||||
import axios, { AxiosInstance, AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'
|
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from 'element-plus'
|
||||||
import {useUserStore} from "@/store/modules/user"
|
import { useUserStore } from '@/store/modules/user'
|
||||||
// 创建axios实例 进行基本参数配置
|
// 创建axios实例 进行基本参数配置
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
// 默认请求地址,根据环境的不同可在.env 文件中进行修改
|
// 默认请求地址,根据环境的不同可在.env 文件中进行修改
|
||||||
baseURL: import.meta.env.VUE_APP_BASE_API,
|
baseURL: import.meta.env.VUE_APP_BASE_API,
|
||||||
// 设置接口访问超时时间
|
// 设置接口访问超时时间
|
||||||
timeout: 3000000, // request timeout,
|
timeout: 3000000, // request timeout,
|
||||||
// 跨域时候允许携带凭证
|
// 跨域时候允许携带凭证
|
||||||
withCredentials: true
|
withCredentials: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
// request interceptor 接口请求拦截
|
// request interceptor 接口请求拦截
|
||||||
service.interceptors.request.use((config:AxiosRequestConfig)=>{
|
service.interceptors.request.use(
|
||||||
|
(config: AxiosRequestConfig) => {
|
||||||
/**
|
/**
|
||||||
* 用户登录之后获取服务端返回的token,后面每次请求都在请求头中带上token进行JWT校验
|
* 用户登录之后获取服务端返回的token,后面每次请求都在请求头中带上token进行JWT校验
|
||||||
* token 存储在本地储存中(storage)、vuex、pinia
|
* token 存储在本地储存中(storage)、vuex、pinia
|
||||||
*/
|
*/
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore()
|
||||||
const token: string = userStore.token;
|
const token: string = userStore.token
|
||||||
// 自定义请求头
|
// 自定义请求头
|
||||||
if(token){ config.headers['Authorization'] = token}
|
if (token) {
|
||||||
|
config.headers['Authorization'] = token
|
||||||
|
}
|
||||||
return config
|
return config
|
||||||
},(error: AxiosError) => {
|
},
|
||||||
|
(error: AxiosError) => {
|
||||||
// 请求错误,这里可以用全局提示框进行提示
|
// 请求错误,这里可以用全局提示框进行提示
|
||||||
return Promise.reject(error);
|
return Promise.reject(error)
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
// response interceptor 接口响应拦截
|
// response interceptor 接口响应拦截
|
||||||
service.interceptors.response.use((response: AxiosResponse) =>{
|
service.interceptors.response.use(
|
||||||
|
(response: AxiosResponse) => {
|
||||||
// 直接返回res,当然你也可以只返回res.data
|
// 直接返回res,当然你也可以只返回res.data
|
||||||
// 系统如果有自定义code也可以在这里处理
|
// 系统如果有自定义code也可以在这里处理
|
||||||
return response
|
return response
|
||||||
|
},
|
||||||
|
(error: AxiosError) => {
|
||||||
},(error: AxiosError) => {
|
|
||||||
return Promise.reject(error)
|
return Promise.reject(error)
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// /**
|
||||||
/**
|
// * @description 显示错误消息
|
||||||
* @description 显示错误消息
|
// * opt 传入参数
|
||||||
* opt 传入参数
|
// * err 错误信息
|
||||||
* err 错误信息
|
// * type 消息类型
|
||||||
* type 消息类型
|
// * duration 消息持续时间
|
||||||
* duration 消息持续时间
|
// */
|
||||||
*/
|
// function showErrMessage(opt, err, type: any = 'error', duration = 5000) {
|
||||||
function showErrMessage (opt, err, type:any= 'error', duration:number = 5000){
|
// ElMessage({
|
||||||
ElMessage({
|
// message: err.msg,
|
||||||
message: err.msg,
|
// type: type,
|
||||||
type:type,
|
// duration: duration,
|
||||||
duration: duration
|
// });
|
||||||
})
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
export default service
|
export default service
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import request from './request'
|
import request from './request'
|
||||||
|
|
||||||
export function login(data) {
|
export function login(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/vue-element-perfect/user/login',
|
url: '/vue-element-perfect/user/login',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 3641732 */
|
font-family: 'iconfont'; /* Project id 3641732 */
|
||||||
src: url('./iconfont.woff2?t=1663216428515') format('woff2'),
|
src: url('./iconfont.woff2?t=1663216428515') format('woff2'), url('./iconfont.woff?t=1663216428515') format('woff'),
|
||||||
url('./iconfont.woff?t=1663216428515') format('woff'),
|
url('./iconfont.ttf?t=1663216428515') format('truetype');
|
||||||
url('./iconfont.ttf?t=1663216428515') format('truetype');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
font-family: "iconfont" !important;
|
font-family: 'iconfont' !important;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
|
|
@ -14,102 +13,101 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-yin:before {
|
.icon-yin:before {
|
||||||
content: "\e6a0";
|
content: '\e6a0';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-dabaoyu:before {
|
.icon-dabaoyu:before {
|
||||||
content: "\e6a7";
|
content: '\e6a7';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-shuaxin1:before {
|
.icon-shuaxin1:before {
|
||||||
content: "\e627";
|
content: '\e627';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-shuaxin:before {
|
.icon-shuaxin:before {
|
||||||
content: "\e629";
|
content: '\e629';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-duoyun-2-copy:before {
|
.icon-duoyun-2-copy:before {
|
||||||
content: "\e68d";
|
content: '\e68d';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-duoyun-1:before {
|
.icon-duoyun-1:before {
|
||||||
content: "\e679";
|
content: '\e679';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-daxue:before {
|
.icon-daxue:before {
|
||||||
content: "\e67a";
|
content: '\e67a';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-dayu:before {
|
.icon-dayu:before {
|
||||||
content: "\e67b";
|
content: '\e67b';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-feng:before {
|
.icon-feng:before {
|
||||||
content: "\e67c";
|
content: '\e67c';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-duoyun-3:before {
|
.icon-duoyun-3:before {
|
||||||
content: "\e67d";
|
content: '\e67d';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-duoyun-2:before {
|
.icon-duoyun-2:before {
|
||||||
content: "\e67e";
|
content: '\e67e';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-leiyujiaojia:before {
|
.icon-leiyujiaojia:before {
|
||||||
content: "\e67f";
|
content: '\e67f';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-duoyun:before {
|
.icon-duoyun:before {
|
||||||
content: "\e680";
|
content: '\e680';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-zhongyu:before {
|
.icon-zhongyu:before {
|
||||||
content: "\e681";
|
content: '\e681';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-wu:before {
|
.icon-wu:before {
|
||||||
content: "\e682";
|
content: '\e682';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-xiaoyu:before {
|
.icon-xiaoyu:before {
|
||||||
content: "\e683";
|
content: '\e683';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-xiaoxue:before {
|
.icon-xiaoxue:before {
|
||||||
content: "\e684";
|
content: '\e684';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-shandian:before {
|
.icon-shandian:before {
|
||||||
content: "\e685";
|
content: '\e685';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-xue:before {
|
.icon-xue:before {
|
||||||
content: "\e686";
|
content: '\e686';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-zhongxue:before {
|
.icon-zhongxue:before {
|
||||||
content: "\e687";
|
content: '\e687';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-yangchen:before {
|
.icon-yangchen:before {
|
||||||
content: "\e688";
|
content: '\e688';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-yueliang:before {
|
.icon-yueliang:before {
|
||||||
content: "\e689";
|
content: '\e689';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-yujiaxue:before {
|
.icon-yujiaxue:before {
|
||||||
content: "\e68a";
|
content: '\e68a';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-qing:before {
|
.icon-qing:before {
|
||||||
content: "\e68b";
|
content: '\e68b';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-mai:before {
|
.icon-mai:before {
|
||||||
content: "\e68c";
|
content: '\e68c';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,86 +1,85 @@
|
||||||
<template>
|
<template>
|
||||||
<vue-cropper
|
<vue-cropper
|
||||||
ref="cropper"
|
ref="cropper"
|
||||||
:img="avatarUrl"
|
:img="avatarUrl"
|
||||||
:output-size="defaultOptions.outputSize"
|
:output-size="defaultOptions.outputSize"
|
||||||
:output-type="defaultOptions.outputType"
|
:output-type="defaultOptions.outputType"
|
||||||
:info="defaultOptions.info"
|
:info="defaultOptions.info"
|
||||||
:full="defaultOptions.full"
|
:full="defaultOptions.full"
|
||||||
:fixed="defaultOptions.fixed"
|
:fixed="defaultOptions.fixed"
|
||||||
:autoCropWidth="defaultOptions.autoCropWidth"
|
:auto-crop-width="defaultOptions.autoCropWidth"
|
||||||
:autoCropHeight="defaultOptions.autoCropHeight"
|
:auto-crop-height="defaultOptions.autoCropHeight"
|
||||||
:fixed-box="defaultOptions.fixedBox"
|
:fixed-box="defaultOptions.fixedBox"
|
||||||
:auto-crop="defaultOptions.autoCrop"
|
:auto-crop="defaultOptions.autoCrop"
|
||||||
:center-box="defaultOptions.centerBox"
|
:center-box="defaultOptions.centerBox"
|
||||||
@real-time="realTime"
|
@real-time="realTime"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {defineExpose, reactive, ref} from 'vue'
|
import { defineExpose, reactive, ref } from 'vue'
|
||||||
import { VueCropper } from 'vue-cropper'
|
import { VueCropper } from 'vue-cropper'
|
||||||
import 'vue-cropper/dist/index.css'
|
import 'vue-cropper/dist/index.css'
|
||||||
|
|
||||||
const emit = defineEmits(['change'])
|
const emit = defineEmits(['change'])
|
||||||
let props = defineProps({
|
let props = defineProps({
|
||||||
avatarUrl:{
|
avatarUrl: {
|
||||||
type:String
|
type: String,
|
||||||
},
|
},
|
||||||
options:{
|
options: {
|
||||||
type:Object,
|
type: Object,
|
||||||
default:()=>{}
|
default: () => {},
|
||||||
}
|
},
|
||||||
})
|
|
||||||
|
|
||||||
let cropper = ref()
|
|
||||||
|
|
||||||
const defaultOptions = reactive({
|
|
||||||
outputSize:0.8, // 裁剪生成图片的质量
|
|
||||||
outputType: 'png', // 生成图片的格式
|
|
||||||
info: true, // 裁剪框的大小信息
|
|
||||||
fixed: true, // 是否开启截图框宽高固定比例
|
|
||||||
autoCrop: true, // 是否默认生成截图框
|
|
||||||
anMoveBox: true, // 截图框能否拖动
|
|
||||||
original: false, // 上传图片按照原始比例渲染
|
|
||||||
autoCropWidth: 300, // 默认生成截图框宽度
|
|
||||||
autoCropHeight: 300, // 默认生成截图框高度
|
|
||||||
// 只有自动截图开启 宽度高度才生效
|
|
||||||
centerBox: false, // 截图框是否被限制在图片里面
|
|
||||||
high: true, // 是否按照dpr设备比例图片
|
|
||||||
fixedBox: false, // 固定截图框大小 不允许改变
|
|
||||||
full: false, // 是否输出原图比例的截图
|
|
||||||
...props.options
|
|
||||||
})
|
|
||||||
|
|
||||||
const getBase64 = ()=>{
|
|
||||||
return new Promise(resolve => {
|
|
||||||
cropper.value.getCropData((data) => {
|
|
||||||
resolve(data)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
const rotateLeft = () => {
|
let cropper = ref()
|
||||||
cropper.value.rotateLeft()
|
|
||||||
}
|
|
||||||
const rotateRight = () => {
|
|
||||||
cropper.value.rotateRight()
|
|
||||||
}
|
|
||||||
|
|
||||||
const zoom = (percent) => {
|
const defaultOptions = reactive({
|
||||||
cropper.value.changeScale(percent)
|
outputSize: 0.8, // 裁剪生成图片的质量
|
||||||
}
|
outputType: 'png', // 生成图片的格式
|
||||||
|
info: true, // 裁剪框的大小信息
|
||||||
|
fixed: true, // 是否开启截图框宽高固定比例
|
||||||
|
autoCrop: true, // 是否默认生成截图框
|
||||||
|
anMoveBox: true, // 截图框能否拖动
|
||||||
|
original: false, // 上传图片按照原始比例渲染
|
||||||
|
autoCropWidth: 300, // 默认生成截图框宽度
|
||||||
|
autoCropHeight: 300, // 默认生成截图框高度
|
||||||
|
// 只有自动截图开启 宽度高度才生效
|
||||||
|
centerBox: false, // 截图框是否被限制在图片里面
|
||||||
|
high: true, // 是否按照dpr设备比例图片
|
||||||
|
fixedBox: false, // 固定截图框大小 不允许改变
|
||||||
|
full: false, // 是否输出原图比例的截图
|
||||||
|
...props.options,
|
||||||
|
})
|
||||||
|
|
||||||
// 实时预览图片
|
const getBase64 = () => {
|
||||||
const realTime = (data)=>{
|
return new Promise((resolve) => {
|
||||||
emit('change',data)
|
cropper.value.getCropData((data) => {
|
||||||
}
|
resolve(data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const rotateLeft = () => {
|
||||||
|
cropper.value.rotateLeft()
|
||||||
|
}
|
||||||
|
const rotateRight = () => {
|
||||||
|
cropper.value.rotateRight()
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
const zoom = (percent) => {
|
||||||
getBase64,
|
cropper.value.changeScale(percent)
|
||||||
rotateLeft,
|
}
|
||||||
rotateRight,
|
|
||||||
zoom
|
// 实时预览图片
|
||||||
})
|
const realTime = (data) => {
|
||||||
|
emit('change', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
getBase64,
|
||||||
|
rotateLeft,
|
||||||
|
rotateRight,
|
||||||
|
zoom,
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,121 +1,120 @@
|
||||||
<template>
|
<template>
|
||||||
<textarea ref="codeEditor" placeholder="请输入..." ></textarea>
|
<textarea ref="codeEditor" placeholder="请输入..."></textarea>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { defineComponent, onBeforeUnmount, onMounted, ref, toRefs, watch } from "vue";
|
import { defineComponent, onBeforeUnmount, onMounted, ref, toRefs, watch } from 'vue'
|
||||||
// codemirror基础资源引入
|
// codemirror基础资源引入
|
||||||
import _CodeMirror from "codemirror";
|
import _CodeMirror from 'codemirror'
|
||||||
import "codemirror/lib/codemirror.css";
|
import 'codemirror/lib/codemirror.css'
|
||||||
// language
|
// language
|
||||||
import 'codemirror/mode/javascript/javascript.js'
|
import 'codemirror/mode/javascript/javascript.js'
|
||||||
|
|
||||||
// theme css
|
// theme css
|
||||||
import 'codemirror/theme/monokai.css'
|
import 'codemirror/theme/monokai.css'
|
||||||
// 折叠资源引入:开始
|
// 折叠资源引入:开始
|
||||||
import "codemirror/addon/fold/foldgutter.css";
|
import 'codemirror/addon/fold/foldgutter.css'
|
||||||
import "codemirror/addon/fold/foldcode.js";
|
import 'codemirror/addon/fold/foldcode.js'
|
||||||
import "codemirror/addon/fold/brace-fold.js";
|
import 'codemirror/addon/fold/brace-fold.js'
|
||||||
import "codemirror/addon/fold/comment-fold.js";
|
import 'codemirror/addon/fold/comment-fold.js'
|
||||||
import "codemirror/addon/fold/indent-fold.js";
|
import 'codemirror/addon/fold/indent-fold.js'
|
||||||
import "codemirror/addon/fold/foldgutter.js";
|
import 'codemirror/addon/fold/foldgutter.js'
|
||||||
// 折叠资源引入:结束
|
// 折叠资源引入:结束
|
||||||
|
|
||||||
// 搜索资源引入:开始
|
// 搜索资源引入:开始
|
||||||
import "codemirror/addon/scroll/annotatescrollbar.js";
|
import 'codemirror/addon/scroll/annotatescrollbar.js'
|
||||||
import "codemirror/addon/search/matchesonscrollbar.js";
|
import 'codemirror/addon/search/matchesonscrollbar.js'
|
||||||
import "codemirror/addon/search/match-highlighter.js";
|
import 'codemirror/addon/search/match-highlighter.js'
|
||||||
import "codemirror/addon/search/jump-to-line.js";
|
import 'codemirror/addon/search/jump-to-line.js'
|
||||||
|
|
||||||
import "codemirror/addon/dialog/dialog.js";
|
import 'codemirror/addon/dialog/dialog.js'
|
||||||
import "codemirror/addon/dialog/dialog.css";
|
import 'codemirror/addon/dialog/dialog.css'
|
||||||
import "codemirror/addon/search/searchcursor.js";
|
import 'codemirror/addon/search/searchcursor.js'
|
||||||
import "codemirror/addon/search/search.js";
|
import 'codemirror/addon/search/search.js'
|
||||||
// 搜索资源引入:结束
|
// 搜索资源引入:结束
|
||||||
|
|
||||||
// 启用placeholder
|
// 启用placeholder
|
||||||
import "codemirror/addon/display/placeholder.js";
|
import 'codemirror/addon/display/placeholder.js'
|
||||||
|
|
||||||
import "codemirror/addon/selection/active-line.js"; //光标行背景高亮,配置里面也需要styleActiveLine设置为true
|
import 'codemirror/addon/selection/active-line.js' //光标行背景高亮,配置里面也需要styleActiveLine设置为true
|
||||||
|
|
||||||
const CodeMirror = window.CodeMirror || _CodeMirror;
|
const CodeMirror = window.CodeMirror || _CodeMirror
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
modelValue: String,
|
modelValue: String,
|
||||||
defaultValue: String,
|
defaultValue: String,
|
||||||
readOnly: {
|
readOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
const { modelValue, defaultValue, readOnly } = toRefs(props);
|
const { modelValue, defaultValue, readOnly } = toRefs(props)
|
||||||
const codeEditor = ref();
|
const codeEditor = ref()
|
||||||
let editor;
|
let editor
|
||||||
watch(modelValue, () => {
|
watch(modelValue, () => {
|
||||||
if (null != editor && modelValue.value && modelValue.value !== editor.getValue()) {
|
if (null != editor && modelValue.value && modelValue.value !== editor.getValue()) {
|
||||||
// 触发v-model的双向绑定
|
// 触发v-model的双向绑定
|
||||||
editor.setValue(modelValue.value);
|
editor.setValue(modelValue.value)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
watch(readOnly, () => {
|
watch(readOnly, () => {
|
||||||
if (null != editor) {
|
if (null != editor) {
|
||||||
editor.setOption("readOnly", readOnly.value);
|
editor.setOption('readOnly', readOnly.value)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
editor = CodeMirror.fromTextArea(codeEditor.value, {
|
editor = CodeMirror.fromTextArea(codeEditor.value, {
|
||||||
value: modelValue.value,
|
value: modelValue.value,
|
||||||
// mime: "text/javascript",
|
// mime: "text/javascript",
|
||||||
mode: "application/json",
|
mode: 'application/json',
|
||||||
indentWithTabs: false, // 在缩进时,是否需要把 n*tab宽度个空格替换成n个tab字符,默认为false
|
indentWithTabs: false, // 在缩进时,是否需要把 n*tab宽度个空格替换成n个tab字符,默认为false
|
||||||
smartIndent: true, // 自动缩进,设置是否根据上下文自动缩进(和上一行相同的缩进量)。默认为true
|
smartIndent: true, // 自动缩进,设置是否根据上下文自动缩进(和上一行相同的缩进量)。默认为true
|
||||||
lineNumbers: true, // 是否在编辑器左侧显示行号
|
lineNumbers: true, // 是否在编辑器左侧显示行号
|
||||||
matchBrackets: true, // 括号匹配
|
matchBrackets: true, // 括号匹配
|
||||||
readOnly: readOnly.value,
|
readOnly: readOnly.value,
|
||||||
// 启用代码折叠相关功能:开始
|
// 启用代码折叠相关功能:开始
|
||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
lineWrapping: true, //是否自动换行
|
lineWrapping: true, //是否自动换行
|
||||||
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter", "CodeMirror-lint-markers"],
|
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
|
||||||
// 启用代码折叠相关功能:结束
|
// 启用代码折叠相关功能:结束
|
||||||
styleActiveLine: false // 光标行高亮
|
styleActiveLine: false, // 光标行高亮
|
||||||
});
|
})
|
||||||
// 监听编辑器的change事件
|
// 监听编辑器的change事件
|
||||||
editor.on("change", () => {
|
editor.on('change', () => {
|
||||||
// 触发v-model的双向绑定
|
// 触发v-model的双向绑定
|
||||||
context.emit("update:modelValue", editor.getValue());
|
context.emit('update:modelValue', editor.getValue())
|
||||||
});
|
})
|
||||||
if (defaultValue.value) {
|
if (defaultValue.value) {
|
||||||
editor.setValue(defaultValue.value);
|
editor.setValue(defaultValue.value)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
if (null !== editor) {
|
if (null !== editor) {
|
||||||
editor.toTextArea();
|
editor.toTextArea()
|
||||||
editor = null;
|
editor = null
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
return { codeEditor };
|
return { codeEditor }
|
||||||
}
|
},
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.CodeMirror-wrap{
|
.CodeMirror-wrap {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.CodeMirror-gutters {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 3;
|
|
||||||
min-height: 100%;
|
|
||||||
white-space: nowrap;
|
|
||||||
background-color: transparent;
|
|
||||||
border-right: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.CodeMirror-gutters {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 3;
|
||||||
|
min-height: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
background-color: transparent;
|
||||||
|
border-right: 1px solid #ddd;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,9 @@
|
||||||
}
|
}
|
||||||
this.$emit('mountedCallback')
|
this.$emit('mountedCallback')
|
||||||
},
|
},
|
||||||
|
unmounted() {
|
||||||
|
cancelAnimationFrame(this.rAF)
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
start() {
|
start() {
|
||||||
this.localStartVal = this.startVal
|
this.localStartVal = this.startVal
|
||||||
|
|
@ -142,26 +145,15 @@
|
||||||
|
|
||||||
if (this.useEasing) {
|
if (this.useEasing) {
|
||||||
if (this.countDown) {
|
if (this.countDown) {
|
||||||
this.printVal =
|
this.printVal = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration)
|
||||||
this.localStartVal -
|
|
||||||
this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration)
|
|
||||||
} else {
|
} else {
|
||||||
this.printVal = this.easingFn(
|
this.printVal = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration)
|
||||||
progress,
|
|
||||||
this.localStartVal,
|
|
||||||
this.endVal - this.localStartVal,
|
|
||||||
this.localDuration,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (this.countDown) {
|
if (this.countDown) {
|
||||||
this.printVal =
|
this.printVal = this.localStartVal - (this.localStartVal - this.endVal) * (progress / this.localDuration)
|
||||||
this.localStartVal -
|
|
||||||
(this.localStartVal - this.endVal) * (progress / this.localDuration)
|
|
||||||
} else {
|
} else {
|
||||||
this.printVal =
|
this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration)
|
||||||
this.localStartVal +
|
|
||||||
(this.endVal - this.localStartVal) * (progress / this.localDuration)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.countDown) {
|
if (this.countDown) {
|
||||||
|
|
@ -195,8 +187,5 @@
|
||||||
return this.prefix + x1 + x2 + this.suffix
|
return this.prefix + x1 + x2 + this.suffix
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
destroyed() {
|
|
||||||
cancelAnimationFrame(this.rAF)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,7 @@ if (isServer) {
|
||||||
}
|
}
|
||||||
prefix = prefixes[i]
|
prefix = prefixes[i]
|
||||||
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
|
requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
|
||||||
cancelAnimationFrame =
|
cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
|
||||||
cancelAnimationFrame ||
|
|
||||||
window[prefix + 'CancelAnimationFrame'] ||
|
|
||||||
window[prefix + 'CancelRequestAnimationFrame']
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
|
// 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
|
||||||
|
|
|
||||||
|
|
@ -1,269 +1,269 @@
|
||||||
<template>
|
<template>
|
||||||
<div ref="chartsRef" class="echarts"/>
|
<div ref="chartsRef" class="echarts" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import { EChartsType } from 'echarts/core'
|
import { EChartsType } from 'echarts/core'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
const chartsRef = ref<HTMLElement | null>()
|
const chartsRef = ref<HTMLElement | null>()
|
||||||
|
|
||||||
let colorList = ['#46ea91', '#2ba0ff', '#ed593b', '#7357ff', '#f2d750'];
|
let colorList = ['#46ea91', '#2ba0ff', '#ed593b', '#7357ff', '#f2d750']
|
||||||
const options = {
|
const options = {
|
||||||
legend: {
|
legend: {
|
||||||
icon: 'circle',
|
icon: 'circle',
|
||||||
top: '5%',
|
top: '5%',
|
||||||
right: '5%',
|
right: '5%',
|
||||||
itemWidth: 6,
|
itemWidth: 6,
|
||||||
itemGap: 5,
|
itemGap: 5,
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
padding: [3, 0, 0, 0],
|
padding: [3, 0, 0, 0],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
tooltip: {
|
||||||
tooltip: {
|
trigger: 'axis',
|
||||||
trigger: 'axis',
|
},
|
||||||
},
|
grid: {
|
||||||
grid: {
|
top: '14%',
|
||||||
top: '14%',
|
left: '3%',
|
||||||
left: '3%',
|
right: '4%',
|
||||||
right: '4%',
|
bottom: '10%',
|
||||||
bottom: '10%',
|
containLabel: true,
|
||||||
containLabel: true,
|
},
|
||||||
},
|
xAxis: [
|
||||||
xAxis: [
|
{
|
||||||
{
|
type: 'category',
|
||||||
type: 'category',
|
data: ['1', '2', '3', '4', '5', '6', '7', '8'],
|
||||||
data: ['1', '2', '3', '4', '5', '6', '7', '8'],
|
axisLine: {
|
||||||
axisLine: {
|
lineStyle: {
|
||||||
lineStyle: {
|
color: '#33BBFF',
|
||||||
color: '#33BBFF',
|
},
|
||||||
},
|
},
|
||||||
},
|
axisTick: {
|
||||||
axisTick: {
|
show: false,
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
axisLabel: {
|
|
||||||
interval: 0,
|
|
||||||
textStyle: {
|
|
||||||
color: '#5FBBEB',
|
|
||||||
},
|
},
|
||||||
// 默认x轴字体大小
|
axisLabel: {
|
||||||
fontSize: 12,
|
interval: 0,
|
||||||
// margin:文字到x轴的距离
|
textStyle: {
|
||||||
margin: 10,
|
color: '#5FBBEB',
|
||||||
},
|
},
|
||||||
axisPointer: {
|
// 默认x轴字体大小
|
||||||
label: {
|
|
||||||
// padding: [11, 5, 7],
|
|
||||||
padding: [0, 0, 0, 0],
|
|
||||||
// 这里的margin和axisLabel的margin要一致!
|
|
||||||
margin: 10,
|
|
||||||
// 移入时的字体大小
|
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
backgroundColor: 'rgba(0,0,0,0)',
|
// margin:文字到x轴的距离
|
||||||
|
margin: 10,
|
||||||
|
},
|
||||||
|
axisPointer: {
|
||||||
|
label: {
|
||||||
|
// padding: [11, 5, 7],
|
||||||
|
padding: [0, 0, 0, 0],
|
||||||
|
// 这里的margin和axisLabel的margin要一致!
|
||||||
|
margin: 10,
|
||||||
|
// 移入时的字体大小
|
||||||
|
fontSize: 12,
|
||||||
|
backgroundColor: 'rgba(0,0,0,0)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
boundaryGap: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
name: '单位/件',
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#05D5FF',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#5FBBEB',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
boundaryGap: false,
|
],
|
||||||
},
|
series: [
|
||||||
],
|
{
|
||||||
yAxis: [
|
name: '咨询',
|
||||||
{
|
type: 'line',
|
||||||
name: '单位/件',
|
data: [100, 20, 30, 102, 15, 30, 20, 18],
|
||||||
axisTick: {
|
symbolSize: 1,
|
||||||
show: false,
|
symbol: 'circle',
|
||||||
},
|
smooth: true,
|
||||||
axisLine: {
|
showSymbol: false,
|
||||||
show: true,
|
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: '#05D5FF',
|
width: 2,
|
||||||
|
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: '#90ffc6',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: '#46ea91',
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
shadowColor: 'rgba(144, 255, 198, .3)',
|
||||||
|
shadowBlur: 5,
|
||||||
|
shadowOffsetY: 5,
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: colorList[0],
|
||||||
|
borderColor: colorList[0],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
axisLabel: {
|
{
|
||||||
textStyle: {
|
name: '求助',
|
||||||
color: '#5FBBEB',
|
type: 'line',
|
||||||
|
data: [20, 12, 11, 14, 25, 16, 10, 20],
|
||||||
|
symbolSize: 1,
|
||||||
|
symbol: 'circle',
|
||||||
|
smooth: true,
|
||||||
|
showSymbol: false,
|
||||||
|
lineStyle: {
|
||||||
|
width: 2,
|
||||||
|
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: '#67bcfc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: '#2ba0ff',
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
shadowColor: 'rgba(105, 188, 252,.3)',
|
||||||
|
shadowBlur: 5,
|
||||||
|
shadowOffsetY: 5,
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: colorList[1],
|
||||||
|
borderColor: colorList[1],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
splitLine: {
|
{
|
||||||
show: false,
|
name: '无效',
|
||||||
},
|
type: 'line',
|
||||||
},
|
data: [150, 120, 170, 140, 100, 160, 110, 110],
|
||||||
],
|
symbolSize: 1,
|
||||||
series: [
|
symbol: 'circle',
|
||||||
{
|
smooth: true,
|
||||||
name: '咨询',
|
showSymbol: false,
|
||||||
type: 'line',
|
lineStyle: {
|
||||||
data: [100, 20, 30, 102, 15, 30, 20, 18],
|
width: 2,
|
||||||
symbolSize: 1,
|
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
||||||
symbol: 'circle',
|
{
|
||||||
smooth: true,
|
offset: 0,
|
||||||
showSymbol: false,
|
color: '#fc937e ',
|
||||||
lineStyle: {
|
},
|
||||||
width: 2,
|
{
|
||||||
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
offset: 1,
|
||||||
{
|
color: '#ed593b',
|
||||||
offset: 0,
|
},
|
||||||
color: '#90ffc6',
|
]),
|
||||||
|
shadowColor: 'rgb(252, 147, 126,.3)',
|
||||||
|
shadowBlur: 2,
|
||||||
|
shadowOffsetY: 2,
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: colorList[2],
|
||||||
|
borderColor: colorList[2],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
offset: 1,
|
|
||||||
color: '#46ea91',
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
shadowColor: 'rgba(144, 255, 198, .3)',
|
|
||||||
shadowBlur: 5,
|
|
||||||
shadowOffsetY: 5,
|
|
||||||
},
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
color: colorList[0],
|
|
||||||
borderColor: colorList[0],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: '投诉举报',
|
||||||
name: '求助',
|
type: 'line',
|
||||||
type: 'line',
|
data: [200, 80, 100, 30, 60, 50, 110, 20],
|
||||||
data: [20, 12, 11, 14, 25, 16, 10, 20],
|
symbolSize: 1,
|
||||||
symbolSize: 1,
|
symbol: 'circle',
|
||||||
symbol: 'circle',
|
smooth: true,
|
||||||
smooth: true,
|
showSymbol: false,
|
||||||
showSymbol: false,
|
lineStyle: {
|
||||||
lineStyle: {
|
width: 2,
|
||||||
width: 2,
|
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
||||||
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
{
|
||||||
{
|
offset: 0,
|
||||||
offset: 0,
|
color: '#a390ff',
|
||||||
color: '#67bcfc',
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: '#7357ff',
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
shadowColor: 'rgba(115, 87, 255, .1)',
|
||||||
|
shadowBlur: 5,
|
||||||
|
shadowOffsetY: 5,
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: colorList[3],
|
||||||
|
borderColor: colorList[3],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
offset: 1,
|
|
||||||
color: '#2ba0ff',
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
shadowColor: 'rgba(105, 188, 252,.3)',
|
|
||||||
shadowBlur: 5,
|
|
||||||
shadowOffsetY: 5,
|
|
||||||
},
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
color: colorList[1],
|
|
||||||
borderColor: colorList[1],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: '建议',
|
||||||
name: '无效',
|
type: 'line',
|
||||||
type: 'line',
|
data: [20, 80, 150, 30, 60, 50, 50, 20],
|
||||||
data: [150, 120, 170, 140, 100, 160, 110, 110],
|
symbolSize: 1,
|
||||||
symbolSize: 1,
|
symbol: 'circle',
|
||||||
symbol: 'circle',
|
smooth: true,
|
||||||
smooth: true,
|
showSymbol: false,
|
||||||
showSymbol: false,
|
lineStyle: {
|
||||||
lineStyle: {
|
width: 2,
|
||||||
width: 2,
|
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
||||||
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
{
|
||||||
{
|
offset: 0,
|
||||||
offset: 0,
|
color: '#ffeb86',
|
||||||
color: '#fc937e ',
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: '#f2d750',
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
shadowColor: 'rgba(255, 235, 134, .5)',
|
||||||
|
shadowBlur: 5,
|
||||||
|
shadowOffsetY: 5,
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: colorList[4],
|
||||||
|
borderColor: colorList[4],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
offset: 1,
|
|
||||||
color: '#ed593b',
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
shadowColor: 'rgb(252, 147, 126,.3)',
|
|
||||||
shadowBlur: 2,
|
|
||||||
shadowOffsetY: 2,
|
|
||||||
},
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
color: colorList[2],
|
|
||||||
borderColor: colorList[2],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
{
|
}
|
||||||
name: '投诉举报',
|
|
||||||
type: 'line',
|
|
||||||
data: [200, 80, 100, 30, 60, 50, 110, 20],
|
|
||||||
symbolSize: 1,
|
|
||||||
symbol: 'circle',
|
|
||||||
smooth: true,
|
|
||||||
showSymbol: false,
|
|
||||||
lineStyle: {
|
|
||||||
width: 2,
|
|
||||||
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
|
||||||
{
|
|
||||||
offset: 0,
|
|
||||||
color: '#a390ff',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
offset: 1,
|
|
||||||
color: '#7357ff',
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
shadowColor: 'rgba(115, 87, 255, .1)',
|
|
||||||
shadowBlur: 5,
|
|
||||||
shadowOffsetY: 5,
|
|
||||||
},
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
color: colorList[3],
|
|
||||||
borderColor: colorList[3],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '建议',
|
|
||||||
type: 'line',
|
|
||||||
data: [20, 80, 150, 30, 60, 50, 50, 20],
|
|
||||||
symbolSize: 1,
|
|
||||||
symbol: 'circle',
|
|
||||||
smooth: true,
|
|
||||||
showSymbol: false,
|
|
||||||
lineStyle: {
|
|
||||||
width: 2,
|
|
||||||
color: new echarts.graphic.LinearGradient(1, 1, 0, 0, [
|
|
||||||
{
|
|
||||||
offset: 0,
|
|
||||||
color: '#ffeb86',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
offset: 1,
|
|
||||||
color: '#f2d750',
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
shadowColor: 'rgba(255, 235, 134, .5)',
|
|
||||||
shadowBlur: 5,
|
|
||||||
shadowOffsetY: 5,
|
|
||||||
},
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
color: colorList[4],
|
|
||||||
borderColor: colorList[4],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
let chart: EChartsType
|
let chart: EChartsType
|
||||||
const initChart = () => {
|
const initChart = () => {
|
||||||
const chart = echarts.init(chartsRef.value)
|
const chart = echarts.init(chartsRef.value)
|
||||||
chart.setOption(options)
|
chart.setOption(options)
|
||||||
return chart
|
return chart
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
chart = initChart()
|
chart = initChart()
|
||||||
window.addEventListener('resize', function () {
|
window.addEventListener('resize', function () {
|
||||||
chart && chart.resize()
|
chart && chart.resize()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.echarts{
|
.echarts {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="echarts" ref="chartsRef" />
|
<div ref="chartsRef" class="echarts" />
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import BarCharts from './components/bar.vue'
|
import BarCharts from './components/bar.vue'
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import { EChartsType } from 'echarts/core'
|
import { EChartsType } from 'echarts/core'
|
||||||
import { onMounted, ref,reactive } from 'vue'
|
import { onMounted, ref, reactive } from 'vue'
|
||||||
const chartsRef = ref<HTMLElement | null>()
|
const chartsRef = ref<HTMLElement | null>()
|
||||||
const data = [154, 230, 224, 218, 135, 147, 260]
|
const data = [154, 230, 224, 218, 135, 147, 260]
|
||||||
const color = ['#fa796f', '#54c1fb', '#ca6cd4', '#59dcc1', '#09a4ea', '#e98f4d', '#ea8e49']
|
const color = ['#fa796f', '#54c1fb', '#ca6cd4', '#59dcc1', '#09a4ea', '#e98f4d', '#ea8e49']
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
dataOptions.push(obj)
|
dataOptions.push(obj)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
color,
|
color,
|
||||||
grid: {
|
grid: {
|
||||||
|
|
@ -95,7 +94,6 @@
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let chart: EChartsType
|
let chart: EChartsType
|
||||||
|
|
|
||||||
|
|
@ -1,113 +1,111 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="echarts" ref="chartsRef" />
|
<div ref="chartsRef" class="echarts" />
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import BarCharts from './components/bar.vue'
|
import BarCharts from './components/bar.vue'
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import { EChartsType } from 'echarts/core'
|
import { EChartsType } from 'echarts/core'
|
||||||
import { onMounted, ref,reactive } from 'vue'
|
import { onMounted, ref, reactive } from 'vue'
|
||||||
const chartsRef = ref<HTMLElement | null>()
|
const chartsRef = ref<HTMLElement | null>()
|
||||||
|
|
||||||
|
const options = {
|
||||||
const options = {
|
grid: {
|
||||||
grid: {
|
top: '10%',
|
||||||
top: '10%',
|
left: '3%',
|
||||||
left: '3%',
|
right: '4%',
|
||||||
right: '4%',
|
bottom: '10%',
|
||||||
bottom: '10%',
|
containLabel: true,
|
||||||
containLabel: true,
|
},
|
||||||
},
|
tooltip: {
|
||||||
tooltip: {
|
trigger: 'axis',
|
||||||
trigger: 'axis',
|
backgroundColor: 'rgba(0,0,0,0.7)',
|
||||||
backgroundColor: 'rgba(0,0,0,0.7)',
|
borderWidth: 0,
|
||||||
borderWidth: 0,
|
borderColor: 'rgba(0,0,0,0.7)',
|
||||||
borderColor: 'rgba(0,0,0,0.7)',
|
formatter: (name, val) => {
|
||||||
formatter: (name, val) => {
|
const tipHtml = `
|
||||||
const tipHtml = `
|
|
||||||
<div class="m-info" style=" opacity: 0.95;font-size: 12px; color: white;" >
|
<div class="m-info" style=" opacity: 0.95;font-size: 12px; color: white;" >
|
||||||
<div class="title" ></div>
|
<div class="title" ></div>
|
||||||
<div class="title" >完成占比${name[0].data}</div>
|
<div class="title" >完成占比${name[0].data}</div>
|
||||||
</div>`
|
</div>`
|
||||||
return tipHtml
|
return tipHtml
|
||||||
},
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
// 设置坐标轴的 文字样式
|
|
||||||
axisLabel: {
|
|
||||||
color: '#bbdaff',
|
|
||||||
margin: 20, // 刻度标签与轴线之间的距离。
|
|
||||||
},
|
|
||||||
// 坐标轴轴线相关设置。
|
|
||||||
splitLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: '#2d5baf',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
yAxis: {
|
||||||
xAxis: {
|
|
||||||
splitLine: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
// 坐标轴轴线相关设置。
|
|
||||||
axisLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: '#2d5baf',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
type: 'category',
|
|
||||||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
|
||||||
axisLabel: {
|
|
||||||
// 设置坐标轴的 文字样式
|
// 设置坐标轴的 文字样式
|
||||||
color: '#bbdaff',
|
axisLabel: {
|
||||||
margin: 20, // 刻度标签与轴线之间的距离。
|
color: '#bbdaff',
|
||||||
},
|
margin: 20, // 刻度标签与轴线之间的距离。
|
||||||
boundaryGap: false, // 设置坐标轴两边的留白 ,从刻度原点开始,
|
|
||||||
axisTick: {
|
|
||||||
// 取消坐标轴刻度线
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
data: [154, 230, 224, 218, 135, 147, 260],
|
|
||||||
type: 'line',
|
|
||||||
// smooth:false, //关键点,为true是不支持虚线的,实线就用true
|
|
||||||
symbolSize: 12, // 拐点圆的大小
|
|
||||||
symbol: 'circle',
|
|
||||||
markLine: {
|
|
||||||
silent: true,
|
|
||||||
},
|
},
|
||||||
itemStyle: {
|
// 坐标轴轴线相关设置。
|
||||||
normal: {
|
splitLine: {
|
||||||
color: '#920783', // 设置 symbol的颜色
|
lineStyle: {
|
||||||
lineStyle: {
|
color: '#2d5baf',
|
||||||
width: 3,
|
|
||||||
color: '#920783',
|
|
||||||
type: 'solid', // 'dotted'虚线 'solid'实线
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
xAxis: {
|
||||||
|
splitLine: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
// 坐标轴轴线相关设置。
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#2d5baf',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: 'category',
|
||||||
|
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
||||||
|
axisLabel: {
|
||||||
|
// 设置坐标轴的 文字样式
|
||||||
|
color: '#bbdaff',
|
||||||
|
margin: 20, // 刻度标签与轴线之间的距离。
|
||||||
|
},
|
||||||
|
boundaryGap: false, // 设置坐标轴两边的留白 ,从刻度原点开始,
|
||||||
|
axisTick: {
|
||||||
|
// 取消坐标轴刻度线
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
data: [154, 230, 224, 218, 135, 147, 260],
|
||||||
|
type: 'line',
|
||||||
|
// smooth:false, //关键点,为true是不支持虚线的,实线就用true
|
||||||
|
symbolSize: 12, // 拐点圆的大小
|
||||||
|
symbol: 'circle',
|
||||||
|
markLine: {
|
||||||
|
silent: true,
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: '#920783', // 设置 symbol的颜色
|
||||||
|
lineStyle: {
|
||||||
|
width: 3,
|
||||||
|
color: '#920783',
|
||||||
|
type: 'solid', // 'dotted'虚线 'solid'实线
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
}
|
let chart: EChartsType
|
||||||
|
const initChart = () => {
|
||||||
let chart: EChartsType
|
const chart = echarts.init(chartsRef.value)
|
||||||
const initChart = () => {
|
chart.setOption(options)
|
||||||
const chart = echarts.init(chartsRef.value)
|
return chart
|
||||||
chart.setOption(options)
|
}
|
||||||
return chart
|
onMounted(() => {
|
||||||
}
|
chart = initChart()
|
||||||
onMounted(() => {
|
window.addEventListener('resize', function () {
|
||||||
chart = initChart()
|
chart && chart.resize()
|
||||||
window.addEventListener('resize', function () {
|
})
|
||||||
chart && chart.resize()
|
|
||||||
})
|
})
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.echarts {
|
.echarts {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
import { geoJson } from './map.js'
|
import { geoJson } from './map.js'
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import { EChartsType } from 'echarts/core'
|
import { EChartsType } from 'echarts/core'
|
||||||
import { onMounted, onUnmounted } from "vue";
|
import { onMounted, onUnmounted } from 'vue'
|
||||||
import { cityIconData } from './data.js'
|
import { cityIconData } from './data.js'
|
||||||
import logo from '@/assets/image/logo.png'
|
import logo from '@/assets/image/logo.png'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|
@ -319,8 +319,8 @@
|
||||||
return chart
|
return chart
|
||||||
}
|
}
|
||||||
|
|
||||||
onUnmounted(()=>{
|
onUnmounted(() => {
|
||||||
chart&&chart.dispose()
|
chart && chart.dispose()
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,36 @@
|
||||||
<template>
|
<template>
|
||||||
<div ref="chartsRef" class="echarts"/>
|
<div ref="chartsRef" class="echarts" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as echarts from 'echarts'
|
import * as echarts from 'echarts'
|
||||||
import { EChartsType } from 'echarts/core'
|
import { EChartsType } from 'echarts/core'
|
||||||
import { onMounted, ref } from 'vue'
|
import { onMounted, ref } from 'vue'
|
||||||
const chartsRef = ref<HTMLElement | null>()
|
const chartsRef = ref<HTMLElement | null>()
|
||||||
var trafficWay = [
|
var trafficWay = [
|
||||||
{
|
{
|
||||||
name: 'Ⅰ类',
|
name: 'Ⅰ类',
|
||||||
value: 20,
|
value: 20,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Ⅱ类',
|
name: 'Ⅱ类',
|
||||||
value: 20,
|
value: 20,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Ⅲ类',
|
name: 'Ⅲ类',
|
||||||
value: 20,
|
value: 20,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Ⅳ类',
|
name: 'Ⅳ类',
|
||||||
value: 20,
|
value: 20,
|
||||||
},
|
},
|
||||||
{ name: 'Ⅴ类', value: 20 },
|
{ name: 'Ⅴ类', value: 20 },
|
||||||
{ name: '劣Ⅴ类', value: 20 },
|
{ name: '劣Ⅴ类', value: 20 },
|
||||||
];
|
]
|
||||||
|
|
||||||
var data = [];
|
var data = []
|
||||||
var color = ['#fd566a', '#9787ff', '#fdb36a', '#fdd56a', '#6da7ff', '#63e1f2', '#ff3000'];
|
var color = ['#fd566a', '#9787ff', '#fdb36a', '#fdd56a', '#6da7ff', '#63e1f2', '#ff3000']
|
||||||
for (var i = 0; i < trafficWay.length; i++) {
|
for (var i = 0; i < trafficWay.length; i++) {
|
||||||
data.push(
|
data.push(
|
||||||
{
|
{
|
||||||
value: trafficWay[i].value,
|
value: trafficWay[i].value,
|
||||||
name: trafficWay[i].name,
|
name: trafficWay[i].name,
|
||||||
|
|
@ -59,121 +59,125 @@ for (var i = 0; i < trafficWay.length; i++) {
|
||||||
borderWidth: 0,
|
borderWidth: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
var seriesOption = [
|
var seriesOption = [
|
||||||
{
|
{
|
||||||
name: '',
|
name: '',
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
clockWise: false,
|
clockWise: false,
|
||||||
radius: [105, 109],
|
radius: [105, 109],
|
||||||
hoverAnimation: false,
|
hoverAnimation: false,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
normal: {
|
normal: {
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
position: 'outside',
|
position: 'outside',
|
||||||
|
|
||||||
formatter: function (params) {
|
formatter: function (params) {
|
||||||
var percent = 0;
|
var percent = 0
|
||||||
var total = 0;
|
var total = 0
|
||||||
for (var i = 0; i < trafficWay.length; i++) {
|
for (var i = 0; i < trafficWay.length; i++) {
|
||||||
total += trafficWay[i].value;
|
total += trafficWay[i].value
|
||||||
}
|
}
|
||||||
percent = ((params.value / total) * 100).toFixed(0);
|
percent = ((params.value / total) * 100).toFixed(0)
|
||||||
if (params.name !== '') {
|
if (params.name !== '') {
|
||||||
return params.name + '\t' + percent + '%';
|
return params.name + '\t' + percent + '%'
|
||||||
} else {
|
} else {
|
||||||
return '';
|
return ''
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
length: 10,
|
||||||
|
length2: 20,
|
||||||
|
show: true,
|
||||||
|
color: '#00ffff',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
labelLine: {
|
},
|
||||||
length: 10,
|
data: data,
|
||||||
length2: 20,
|
},
|
||||||
show: true,
|
]
|
||||||
color: '#00ffff',
|
let options = {
|
||||||
|
color: color,
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
text: '水质监测',
|
||||||
|
top: '44%',
|
||||||
|
textAlign: 'center',
|
||||||
|
left: '49.50%',
|
||||||
|
backgroundColor: '#163253',
|
||||||
|
borderRadius: 100,
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: '400',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: '水环境监测站',
|
||||||
|
top: '49%',
|
||||||
|
textAlign: 'center',
|
||||||
|
left: '49.50%',
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: '400',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '9',
|
||||||
|
top: '53%',
|
||||||
|
textAlign: 'center',
|
||||||
|
left: '48%',
|
||||||
|
textStyle: {
|
||||||
|
color: '#f6ea2f',
|
||||||
|
fontSize: 25,
|
||||||
|
fontWeight: '800',
|
||||||
|
fontStyle: 'italic',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '个',
|
||||||
|
top: '53.5%',
|
||||||
|
textAlign: 'center',
|
||||||
|
left: '50.5%',
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '400',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tooltip: {
|
||||||
|
show: false,
|
||||||
},
|
},
|
||||||
data: data,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
let options = {
|
|
||||||
color: color,
|
|
||||||
title: [{
|
|
||||||
text: '水质监测',
|
|
||||||
top: '44%',
|
|
||||||
textAlign: 'center',
|
|
||||||
left: '49.50%',
|
|
||||||
backgroundColor: '#163253',
|
|
||||||
borderRadius: 100,
|
|
||||||
textStyle: {
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: '400',
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
text: '水环境监测站',
|
|
||||||
top: '49%',
|
|
||||||
textAlign: 'center',
|
|
||||||
left: '49.50%',
|
|
||||||
textStyle: {
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: '400',
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
text: '9',
|
|
||||||
top: '53%',
|
|
||||||
textAlign: 'center',
|
|
||||||
left: '48%',
|
|
||||||
textStyle: {
|
|
||||||
color: '#f6ea2f',
|
|
||||||
fontSize: 25,
|
|
||||||
fontWeight: '800',
|
|
||||||
fontStyle: 'italic'
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
text: '个',
|
|
||||||
top: '53.5%',
|
|
||||||
textAlign: 'center',
|
|
||||||
left: '50.5%',
|
|
||||||
textStyle: {
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: '400',
|
|
||||||
},
|
|
||||||
}],
|
|
||||||
tooltip: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
toolbox: {
|
toolbox: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
series: seriesOption,
|
series: seriesOption,
|
||||||
};
|
}
|
||||||
|
|
||||||
let chart: EChartsType
|
let chart: EChartsType
|
||||||
const initChart = () => {
|
const initChart = () => {
|
||||||
const chart = echarts.init(chartsRef.value)
|
const chart = echarts.init(chartsRef.value)
|
||||||
chart.setOption(options)
|
chart.setOption(options)
|
||||||
return chart
|
return chart
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
chart = initChart()
|
chart = initChart()
|
||||||
window.addEventListener('resize', function () {
|
window.addEventListener('resize', function () {
|
||||||
chart && chart.resize()
|
chart && chart.resize()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.echarts{
|
.echarts {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,5 @@
|
||||||
<script lang="ts" setup></script>
|
<script lang="ts" setup></script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./index.scss";
|
@import './index.scss';
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="g-right-click-menu" :style="style" v-if="isShow" ref="rightMenu">
|
<div v-if="isShow" ref="rightMenu" class="g-right-click-menu" :style="style">
|
||||||
<div
|
<div v-for="(item, index) in data" :key="index" class="operating" @click.stop="operatingRightAction($event, item)">{{
|
||||||
v-for="(item, index) in data"
|
item.label
|
||||||
:key="index"
|
}}</div>
|
||||||
class="operating"
|
|
||||||
@click.stop="operatingRightAction($event, item)"
|
|
||||||
>{{ item.label }}</div
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
@ -37,16 +33,10 @@
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
data() {
|
||||||
left: {
|
return {
|
||||||
handler(newName, oldName) {
|
isShow: false,
|
||||||
if (newName) {
|
}
|
||||||
this.isShow = true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
|
|
||||||
// immediate: true
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
|
|
@ -59,19 +49,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
watch: {
|
||||||
return {
|
left: {
|
||||||
isShow: false,
|
handler(newName, oldName) {
|
||||||
}
|
if (newName) {
|
||||||
},
|
this.isShow = true
|
||||||
methods: {
|
}
|
||||||
/**
|
},
|
||||||
* @func 点击操作
|
// 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
|
||||||
* @param val 1、置顶/取消置顶 2、开启/关闭免打扰 3、开启/关闭星标 4、删除会话
|
// immediate: true
|
||||||
*/
|
|
||||||
operatingRightAction($event, val) {
|
|
||||||
this.$emit('ok', $event, val)
|
|
||||||
this.isShow = false
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -85,6 +71,16 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* @func 点击操作
|
||||||
|
* @param val 1、置顶/取消置顶 2、开启/关闭免打扰 3、开启/关闭星标 4、删除会话
|
||||||
|
*/
|
||||||
|
operatingRightAction($event, val) {
|
||||||
|
this.$emit('ok', $event, val)
|
||||||
|
this.isShow = false
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<el-form-item :label="config?.label" v-if="config.valueType === 'input'" style="width: 100%">
|
<el-form-item v-if="config.valueType === 'input'" :label="config?.label" style="width: 100%">
|
||||||
<el-input v-model="value" v-bind="$attrs" />
|
<el-input v-model="value" v-bind="$attrs" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="config?.label" v-if="config.valueType === 'select'" style="width: 100%">
|
<el-form-item v-if="config.valueType === 'select'" :label="config?.label" style="width: 100%">
|
||||||
<el-select v-model="value" v-bind="$attrs" style="width: 100%">
|
<el-select v-model="value" v-bind="$attrs" style="width: 100%">
|
||||||
<el-option
|
<el-option v-for="item in config.options" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
v-for="item in config.options"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="config?.label" v-if="config.valueType === 'date-picker'" style="width: 100%">
|
<el-form-item v-if="config.valueType === 'date-picker'" :label="config?.label" style="width: 100%">
|
||||||
<el-date-picker v-model="value" v-bind="$attrs" style="width: 100%" />
|
<el-date-picker v-model="value" v-bind="$attrs" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="config?.label" v-if="config.valueType === 'cascader'" style="width: 100%">
|
<el-form-item v-if="config.valueType === 'cascader'" :label="config?.label" style="width: 100%">
|
||||||
<el-cascader v-model="value" v-bind="$attrs" style="width: 100%" />
|
<el-cascader v-model="value" v-bind="$attrs" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="config?.label" v-if="config.valueType === 'time-select'" style="width: 100%">
|
<el-form-item v-if="config.valueType === 'time-select'" :label="config?.label" style="width: 100%">
|
||||||
<el-time-select v-model="value" v-bind="$attrs" style="width: 100%" />
|
<el-time-select v-model="value" v-bind="$attrs" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -36,7 +31,6 @@
|
||||||
(e: 'update:modelValue', value: any): void
|
(e: 'update:modelValue', value: any): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
|
||||||
const value = computed({
|
const value = computed({
|
||||||
get() {
|
get() {
|
||||||
return props?.modelValue
|
return props?.modelValue
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="advancedForm">
|
<div class="advancedForm">
|
||||||
<el-form
|
<el-form ref="ruleFormRef" :inline="true" :label-position="'right'" :model="formParams" class="form-inline">
|
||||||
ref="ruleFormRef"
|
|
||||||
:inline="true"
|
|
||||||
:label-position="'right'"
|
|
||||||
:model="formParams"
|
|
||||||
class="form-inline"
|
|
||||||
>
|
|
||||||
<el-row :class="{ 'not-show': byHeight && !isExpand }" :gutter="gutterWidth">
|
<el-row :class="{ 'not-show': byHeight && !isExpand }" :gutter="gutterWidth">
|
||||||
<template v-for="(item, index) in columns">
|
<template v-for="(item, index) in columns">
|
||||||
<el-col
|
<el-col v-if="item.valueType" v-show="byHeight ? true : index < showRow * 3 || isExpand" :span="item.span">
|
||||||
v-if="item.valueType"
|
<BaseFormItem :key="index" v-bind="item.attrs" v-model="item.value" :config="item" />
|
||||||
:span="item.span"
|
|
||||||
v-show="byHeight ? true : index < showRow * 3 || isExpand"
|
|
||||||
>
|
|
||||||
<BaseFormItem :key="index" :config="item" v-bind="item.attrs" v-model="item.value" />
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</template>
|
</template>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
@ -22,7 +12,7 @@
|
||||||
<div class="search-btn">
|
<div class="search-btn">
|
||||||
<el-button type="primary" @click="onSubmit">查询</el-button>
|
<el-button type="primary" @click="onSubmit">查询</el-button>
|
||||||
<el-button @click="resetForm(ruleFormRef)">重置</el-button>
|
<el-button @click="resetForm(ruleFormRef)">重置</el-button>
|
||||||
<el-button link type="primary" @click="isExpand = !isExpand" v-if="columns.length > 3">
|
<el-button v-if="columns.length > 3" link type="primary" @click="isExpand = !isExpand">
|
||||||
{{ isExpand ? '合并' : '展开' }}
|
{{ isExpand ? '合并' : '展开' }}
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<arrow-down v-if="!isExpand" />
|
<arrow-down v-if="!isExpand" />
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'baseSvgIcon',
|
name: 'BaseSvgIcon',
|
||||||
props: {
|
props: {
|
||||||
iconClass: { type: String },
|
iconClass: { type: String },
|
||||||
className: { type: String },
|
className: { type: String },
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<el-switch
|
<el-switch v-model="themeConfig.isDark" inline-prompt :active-icon="Sunny" :inactive-icon="Moon" @change="switchDark" />
|
||||||
@change="switchDark"
|
|
||||||
inline-prompt
|
|
||||||
v-model="themeConfig.isDark"
|
|
||||||
:active-icon="Sunny"
|
|
||||||
:inactive-icon="Moon"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="switchDark">
|
<script setup lang="ts" name="switchDark">
|
||||||
import { Sunny, Moon } from "@element-plus/icons-vue";
|
import { Sunny, Moon } from '@element-plus/icons-vue'
|
||||||
import {computed, ref} from "vue";
|
import { computed, ref } from 'vue'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
|
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
// 设置信息
|
// 设置信息
|
||||||
const themeConfig = computed(()=>SettingStore.themeConfig)
|
const themeConfig = computed(() => SettingStore.themeConfig)
|
||||||
|
|
||||||
// 切换暗黑模式
|
// 切换暗黑模式
|
||||||
const switchDark = () => {
|
const switchDark = () => {
|
||||||
const body = document.documentElement as HTMLElement;
|
const body = document.documentElement as HTMLElement
|
||||||
if (themeConfig.value.isDark) body.setAttribute("class", "dark");
|
if (themeConfig.value.isDark) body.setAttribute('class', 'dark')
|
||||||
else body.setAttribute("class", "");
|
else body.setAttribute('class', '')
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="m-edit-table">
|
<div class="m-edit-table">
|
||||||
<div style="margin-top: 15px; margin-bottom: 15px" v-if="mode !== 'hide' && mode !== 'bottom'">
|
<div v-if="mode !== 'hide' && mode !== 'bottom'" style="margin-top: 15px; margin-bottom: 15px">
|
||||||
<el-button style="width: 100%" @click="add">
|
<el-button style="width: 100%" @click="add">
|
||||||
<el-icon style="margin-right: 4px"><plus /></el-icon> 添加一行数据</el-button
|
<el-icon style="margin-right: 4px"><plus /></el-icon> 添加一行数据</el-button
|
||||||
>
|
>
|
||||||
|
|
@ -8,61 +8,39 @@
|
||||||
<el-table :data="transData" style="width: 100%" row-key="id" border>
|
<el-table :data="transData" style="width: 100%" row-key="id" border>
|
||||||
<template v-for="item in columns">
|
<template v-for="item in columns">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
v-if="item.type"
|
v-if="item.type"
|
||||||
:type="item.type"
|
:type="item.type"
|
||||||
:width="item.width"
|
:width="item.width"
|
||||||
:align="item.align"
|
:align="item.align"
|
||||||
:fixed="item.fixed"
|
:fixed="item.fixed"
|
||||||
:label="item.label"
|
:label="item.label"
|
||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column v-else :prop="item.name" :width="item.width" :align="item.align" :fixed="item.fixed" :label="item.label">
|
||||||
v-else
|
|
||||||
:prop="item.name"
|
|
||||||
:width="item.width"
|
|
||||||
:align="item.align"
|
|
||||||
:fixed="item.fixed"
|
|
||||||
:label="item.label"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<template v-if="!item.slot">
|
<template v-if="!item.slot">
|
||||||
<template v-if="item.readonly">
|
<template v-if="item.readonly">
|
||||||
{{ scope.row[item.name] }}
|
{{ scope.row[item.name] }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="item.valueType === 'select'">
|
<template v-else-if="item.valueType === 'select'">
|
||||||
<el-select
|
<el-select v-if="scope.row.edit" v-model="scope.row[item.name]" clearable :placeholder="`请选择`">
|
||||||
clearable
|
<el-option v-for="ite in item.options" :key="ite.value" :label="ite.label" :value="ite.value" />
|
||||||
:placeholder="`请选择`"
|
|
||||||
v-model="scope.row[item.name]"
|
|
||||||
v-if="scope.row.edit"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="ite in item.options"
|
|
||||||
:key="ite.value"
|
|
||||||
:label="ite.label"
|
|
||||||
:value="ite.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
<span v-else>{{ filterOption(item, scope) }}</span>
|
<span v-else>{{ filterOption(item, scope) }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="item.valueType === 'date'">
|
<template v-else-if="item.valueType === 'date'">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
v-model="scope.row[item.name]"
|
v-if="scope.row.edit"
|
||||||
type="date"
|
v-model="scope.row[item.name]"
|
||||||
value-format="YYYY-MM-DD"
|
type="date"
|
||||||
clearable
|
value-format="YYYY-MM-DD"
|
||||||
placeholder="请选择"
|
clearable
|
||||||
v-if="scope.row.edit"
|
placeholder="请选择"
|
||||||
/>
|
/>
|
||||||
<span v-else>{{ scope.row[item.name] || '--' }}</span>
|
<span v-else>{{ scope.row[item.name] || '--' }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-input
|
<el-input v-if="scope.row.edit" v-model="scope.row[item.name]" clearable placeholder="请输入"></el-input>
|
||||||
clearable
|
|
||||||
placeholder="请输入"
|
|
||||||
v-model="scope.row[item.name]"
|
|
||||||
v-if="scope.row.edit"
|
|
||||||
></el-input>
|
|
||||||
<span v-else>{{ scope.row[item.name] || '--' }}</span>
|
<span v-else>{{ scope.row[item.name] || '--' }}</span>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -72,59 +50,28 @@
|
||||||
</template>
|
</template>
|
||||||
<el-table-column prop="operator" label="操作" width="250px" fixed="right">
|
<el-table-column prop="operator" label="操作" width="250px" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button v-if="scope.row.edit" type="primary" size="small" icon="CircleCheckFilled" @click="confirmEdit(scope.row)">
|
||||||
v-if="scope.row.edit"
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
icon="CircleCheckFilled"
|
|
||||||
@click="confirmEdit(scope.row)"
|
|
||||||
>
|
|
||||||
保存
|
保存
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button v-else type="primary" size="small" icon="Edit" @click="scope.row.edit = !scope.row.edit"> 编辑 </el-button>
|
||||||
v-else
|
<el-popover v-model:visible="scope.row.visible" trigger="click" placement="top" :width="160">
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
icon="Edit"
|
|
||||||
@click="scope.row.edit = !scope.row.edit"
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</el-button>
|
|
||||||
<el-popover
|
|
||||||
trigger="click"
|
|
||||||
v-model:visible="scope.row.visible"
|
|
||||||
placement="top"
|
|
||||||
:width="160"
|
|
||||||
>
|
|
||||||
<p style="display: flex; align-items: center; margin-bottom: 10px">
|
<p style="display: flex; align-items: center; margin-bottom: 10px">
|
||||||
<el-icon color="#faad14" style="margin-right: 10px"><warning-filled /></el-icon>
|
<el-icon color="#faad14" style="margin-right: 10px"><warning-filled /></el-icon>
|
||||||
删除此行?</p
|
删除此行?</p
|
||||||
>
|
>
|
||||||
<div style="text-align: right; margin: 0">
|
<div style="text-align: right; margin: 0">
|
||||||
<el-button size="small" @click="scope.row.visible = false">取消</el-button>
|
<el-button size="small" @click="scope.row.visible = false">取消</el-button>
|
||||||
<el-button size="small" type="primary" @click="deleteAction(scope.row)"
|
<el-button size="small" type="primary" @click="deleteAction(scope.row)">确定</el-button>
|
||||||
>确定</el-button
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button icon="Delete" @click="deleteCurrent(scope.row)" type="danger" size="small"
|
<el-button icon="Delete" type="danger" size="small" @click="deleteCurrent(scope.row)">删除</el-button>
|
||||||
>删除</el-button
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<el-button
|
<el-button v-if="scope.row.edit" type="primary" size="small" icon="Edit" @click="cancelEdit(scope.row)"> 取消 </el-button>
|
||||||
v-if="scope.row.edit"
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
icon="Edit"
|
|
||||||
@click="cancelEdit(scope.row)"
|
|
||||||
>
|
|
||||||
取消
|
|
||||||
</el-button>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<div style="margin-top: 15px" v-if="mode !== 'hide' && mode !== 'top'">
|
<div v-if="mode !== 'hide' && mode !== 'top'" style="margin-top: 15px">
|
||||||
<el-button style="width: 100%" @click="add">
|
<el-button style="width: 100%" @click="add">
|
||||||
<el-icon style="margin-right: 4px"><plus /></el-icon> 添加一行数据</el-button
|
<el-icon style="margin-right: 4px"><plus /></el-icon> 添加一行数据</el-button
|
||||||
>
|
>
|
||||||
|
|
@ -132,72 +79,72 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, ref, watch } from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
import { deepObjClone } from '@/utils/index'
|
import { deepObjClone } from '@/utils/index'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
const emit = defineEmits(['del', 'add', 'onChange'])
|
const emit = defineEmits(['del', 'add', 'onChange'])
|
||||||
let transData = ref([])
|
let transData = ref([])
|
||||||
|
|
||||||
let props = defineProps({
|
let props = defineProps({
|
||||||
columns: {
|
columns: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
editableKeys: {
|
editableKeys: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
mode: {
|
mode: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'bottom',
|
default: 'bottom',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// 删除当前此行
|
// 删除当前此行
|
||||||
const deleteCurrent = (row)=>{
|
const deleteCurrent = (row) => {
|
||||||
// console.log('----------',row)
|
// console.log('----------',row)
|
||||||
// row.visible = true
|
// row.visible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
let arr = deepObjClone(transData.value)
|
let arr = deepObjClone(transData.value)
|
||||||
for (let item of arr) {
|
for (let item of arr) {
|
||||||
for (let attr in item) {
|
for (let attr in item) {
|
||||||
if (attr.includes('te__mp')) {
|
if (attr.includes('te__mp')) {
|
||||||
delete item[attr]
|
delete item[attr]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
emit('onChange', arr)
|
||||||
}
|
}
|
||||||
emit('onChange', arr)
|
|
||||||
}
|
|
||||||
|
|
||||||
let obj = {}
|
let obj = {}
|
||||||
for (let item of props.columns) {
|
for (let item of props.columns) {
|
||||||
props.data.forEach((it) => {
|
props.data.forEach((it) => {
|
||||||
if (!obj[item.name]) {
|
if (!obj[item.name]) {
|
||||||
obj[item.name] = null
|
obj[item.name] = null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 重置数据
|
|
||||||
const reset = () => {
|
|
||||||
transData.value = props.data
|
|
||||||
for (let item of transData.value) {
|
|
||||||
if (props.editableKeys.includes(item.id)) {
|
|
||||||
item.edit = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
getData()
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
// 重置数据
|
||||||
watch(
|
const reset = () => {
|
||||||
|
transData.value = props.data
|
||||||
|
for (let item of transData.value) {
|
||||||
|
if (props.editableKeys.includes(item.id)) {
|
||||||
|
item.edit = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
watch(
|
||||||
() => props.data,
|
() => props.data,
|
||||||
(val) => {
|
(val) => {
|
||||||
// // 转换数据
|
// // 转换数据
|
||||||
|
|
@ -217,88 +164,88 @@ onMounted(() => {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
deep: true,
|
deep: true,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
|
|
||||||
const handleSizeChange = (val: number) => {
|
const handleSizeChange = (val: number) => {
|
||||||
console.log(`${val} items per page`)
|
console.log(`${val} items per page`)
|
||||||
}
|
|
||||||
|
|
||||||
const listLoading = ref(false)
|
|
||||||
|
|
||||||
// 保存
|
|
||||||
const confirmEdit = (row) => {
|
|
||||||
row.edit = false
|
|
||||||
for (let attr in row) {
|
|
||||||
if (attr.includes('te__mp')) {
|
|
||||||
row[attr] = row[attr.replace('te__mp', '')]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
getData()
|
|
||||||
}
|
const listLoading = ref(false)
|
||||||
// 取消
|
|
||||||
const cancelEdit = (row) => {
|
// 保存
|
||||||
row.edit = !row.edit
|
const confirmEdit = (row) => {
|
||||||
for (let attr in row) {
|
row.edit = false
|
||||||
if (attr !== 'edit') {
|
for (let attr in row) {
|
||||||
if (!attr.includes('te__mp')) {
|
if (attr.includes('te__mp')) {
|
||||||
row[attr] = row[attr + 'te__mp']
|
row[attr] = row[attr.replace('te__mp', '')]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getData()
|
||||||
|
}
|
||||||
|
// 取消
|
||||||
|
const cancelEdit = (row) => {
|
||||||
|
row.edit = !row.edit
|
||||||
|
for (let attr in row) {
|
||||||
|
if (attr !== 'edit') {
|
||||||
|
if (!attr.includes('te__mp')) {
|
||||||
|
row[attr] = row[attr + 'te__mp']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const deleteAction = (row) => {
|
const deleteAction = (row) => {
|
||||||
row.visible = false
|
row.visible = false
|
||||||
transData.value = transData.value.filter((item) => item.id !== row.id)
|
transData.value = transData.value.filter((item) => item.id !== row.id)
|
||||||
emit('del', row)
|
emit('del', row)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加
|
// 添加
|
||||||
const add = () => {
|
const add = () => {
|
||||||
let id = ~~(Math.random() * 1000000).toFixed(0)
|
let id = ~~(Math.random() * 1000000).toFixed(0)
|
||||||
let obj1 = Object.assign({}, obj, {
|
let obj1 = Object.assign({}, obj, {
|
||||||
id: id,
|
id: id,
|
||||||
edit: true,
|
edit: true,
|
||||||
visible: false,
|
visible: false,
|
||||||
|
})
|
||||||
|
for (let attr in obj1) {
|
||||||
|
let temp = `${attr}te__mp`
|
||||||
|
obj1[temp] = obj1[attr]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.mode === 'bottom') {
|
||||||
|
transData.value.push(obj1)
|
||||||
|
}
|
||||||
|
if (props.mode === 'top') {
|
||||||
|
transData.value.unshift(obj1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterOption = (item, scope) => {
|
||||||
|
let obj = item.options.find((ite) => ite.value === scope.row[item.name])
|
||||||
|
if (obj) {
|
||||||
|
return obj.label
|
||||||
|
}
|
||||||
|
return '--'
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
reset,
|
||||||
})
|
})
|
||||||
for (let attr in obj1) {
|
|
||||||
let temp = `${attr}te__mp`
|
|
||||||
obj1[temp] = obj1[attr]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.mode === 'bottom') {
|
|
||||||
transData.value.push(obj1)
|
|
||||||
}
|
|
||||||
if (props.mode === 'top') {
|
|
||||||
transData.value.unshift(obj1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const filterOption = (item, scope) => {
|
|
||||||
let obj = item.options.find((ite) => ite.value === scope.row[item.name])
|
|
||||||
if (obj) {
|
|
||||||
return obj.label
|
|
||||||
}
|
|
||||||
return '--'
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({
|
|
||||||
reset,
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.edit-input {
|
.edit-input {
|
||||||
padding-right: 100px;
|
padding-right: 100px;
|
||||||
}
|
}
|
||||||
.cancel-btn {
|
.cancel-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 15px;
|
right: 15px;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
}
|
}
|
||||||
.inline-edit-table {
|
.inline-edit-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="zb-pro-table">
|
<div class="zb-pro-table">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<SearchForm @submit="onSubmit" :columns="baseFormColumns" />
|
<SearchForm :columns="baseFormColumns" @submit="onSubmit" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!----------底部---------------------->
|
<!----------底部---------------------->
|
||||||
|
|
@ -14,14 +14,14 @@
|
||||||
<!-- ------------表格--------------->
|
<!-- ------------表格--------------->
|
||||||
<div class="table">
|
<div class="table">
|
||||||
<el-table
|
<el-table
|
||||||
class="zb-table"
|
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
@selection-change="(val) => emit('selection-change', val)"
|
class="zb-table"
|
||||||
:data="list"
|
:data="list"
|
||||||
:border="true"
|
:border="true"
|
||||||
|
@selection-change="(val) => emit('selection-change', val)"
|
||||||
>
|
>
|
||||||
<template v-for="item in columns">
|
<template v-for="item in columns">
|
||||||
<el-table-column v-bind="{ ...item, ...{ prop: item.name } }" v-if="item.slot">
|
<el-table-column v-if="item.slot" v-bind="{ ...item, ...{ prop: item.name } }">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<slot :name="item.name" :item="item" :row="scope.row"></slot>
|
<slot :name="item.name" :item="item" :row="scope.row"></slot>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-drawer
|
<el-drawer v-model="drawer" title="主题配置" size="300px">
|
||||||
v-model="drawer" title="主题配置" size="300px">
|
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<label>导航栏布局</label>
|
<label>导航栏布局</label>
|
||||||
<el-select
|
<el-select v-model="layout" placeholder="请选择" style="width: 150px" @change="(val) => changeSwitch('mode', val)">
|
||||||
v-model="layout"
|
|
||||||
placeholder="请选择"
|
|
||||||
style="width: 150px"
|
|
||||||
@change="(val) => changeSwitch('mode',val)"
|
|
||||||
>
|
|
||||||
<el-option label="纵向" value="vertical"></el-option>
|
<el-option label="纵向" value="vertical"></el-option>
|
||||||
<el-option label="横向" value="horizontal"></el-option>
|
<el-option label="横向" value="horizontal"></el-option>
|
||||||
<el-option label="分栏" value="columns"></el-option>
|
<el-option label="分栏" value="columns"></el-option>
|
||||||
|
|
@ -37,39 +31,39 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<label>灰色模式</label>
|
<label>灰色模式</label>
|
||||||
<el-switch v-model="gray" @change="(val) => changeGrayWeak('gray',val)" />
|
<el-switch v-model="gray" @change="(val) => changeGrayWeak('gray', val)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<label>色弱模式</label>
|
<label>色弱模式</label>
|
||||||
<el-switch v-model="weak" @change="(val) => changeGrayWeak('weak',val)" />
|
<el-switch v-model="weak" @change="(val) => changeGrayWeak('weak', val)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<label>标签栏</label>
|
<label>标签栏</label>
|
||||||
<el-switch v-model="showTag" @change="(val) => changeSwitch('showTag',val)" />
|
<el-switch v-model="showTag" @change="(val) => changeSwitch('showTag', val)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<label>侧边栏 Logo</label>
|
<label>侧边栏 Logo</label>
|
||||||
<el-switch v-model="showLogo" @change="(val) => changeSwitch('showLogo',val)" />
|
<el-switch v-model="showLogo" @change="(val) => changeSwitch('showLogo', val)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<label>保持一个子菜单的展开</label>
|
<label>保持一个子菜单的展开</label>
|
||||||
<el-switch v-model="uniqueOpened" @change="(val) => changeSwitch('uniqueOpened',val)" />
|
<el-switch v-model="uniqueOpened" @change="(val) => changeSwitch('uniqueOpened', val)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<label>固定header</label>
|
<label>固定header</label>
|
||||||
<el-switch v-model="fixedHeader" @change="(val) => changeSwitch('fixedHeader',val)" />
|
<el-switch v-model="fixedHeader" @change="(val) => changeSwitch('fixedHeader', val)" />
|
||||||
</div>
|
</div>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {computed, ref,watch} from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
import {ElMessage} from "element-plus";
|
import { ElMessage } from 'element-plus'
|
||||||
import {openLoading,closeLoading} from "@/utils/element"
|
import { openLoading, closeLoading } from '@/utils/element'
|
||||||
import SwitchDark from '@/components/SwitchDark/index.vue'
|
import SwitchDark from '@/components/SwitchDark/index.vue'
|
||||||
import {PRIMARY_COLOR} from "@/config/index";
|
import { PRIMARY_COLOR } from '@/config/index'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
|
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
const layout = ref(SettingStore.themeConfig.mode)
|
const layout = ref(SettingStore.themeConfig.mode)
|
||||||
|
|
@ -83,17 +77,15 @@
|
||||||
|
|
||||||
const drawer = computed({
|
const drawer = computed({
|
||||||
get() {
|
get() {
|
||||||
return SettingStore.themeConfig.showSetting;
|
return SettingStore.themeConfig.showSetting
|
||||||
},
|
},
|
||||||
set() {
|
set() {
|
||||||
changeSwitch('showSetting',!SettingStore.themeConfig.showSetting)
|
changeSwitch('showSetting', !SettingStore.themeConfig.showSetting)
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// 预定义主题颜色
|
// 预定义主题颜色
|
||||||
const predefineColor = [
|
const predefineColor = ['#409EFF', '#1890ff', '#304156', '#212121', '#11a983', '#13c2c2', '#6959CD', '#f5222d']
|
||||||
'#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d'
|
|
||||||
];
|
|
||||||
|
|
||||||
const operator = (type) => {
|
const operator = (type) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
@ -107,53 +99,52 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// 进行配置
|
// 进行配置
|
||||||
const changeSwitch = (key,val) => {
|
const changeSwitch = (key, val) => {
|
||||||
SettingStore.setThemeConfig({key, val})
|
SettingStore.setThemeConfig({ key, val })
|
||||||
if(key==='mode'){
|
if (key === 'mode') {
|
||||||
openLoading()
|
openLoading()
|
||||||
setTimeout(()=>{
|
setTimeout(() => {
|
||||||
closeLoading()
|
closeLoading()
|
||||||
},600)
|
}, 600)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听布局变化
|
// 监听布局变化
|
||||||
watch(
|
watch(
|
||||||
() => layout.value,
|
() => layout.value,
|
||||||
() => {
|
() => {
|
||||||
const body = document.body as HTMLElement;
|
const body = document.body as HTMLElement
|
||||||
body.setAttribute("class", `layout-${layout.value}`);
|
body.setAttribute('class', `layout-${layout.value}`)
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true },
|
||||||
);
|
)
|
||||||
|
|
||||||
// 修改主题颜色
|
// 修改主题颜色
|
||||||
const changePrimary = (val)=>{
|
const changePrimary = (val) => {
|
||||||
if (!val) {
|
if (!val) {
|
||||||
primary.value = val = PRIMARY_COLOR;
|
primary.value = val = PRIMARY_COLOR
|
||||||
ElMessage({ type: "success", message: `主题颜色已重置为 ${PRIMARY_COLOR}` });
|
ElMessage({ type: 'success', message: `主题颜色已重置为 ${PRIMARY_COLOR}` })
|
||||||
}
|
}
|
||||||
document.documentElement.style.setProperty("--el-color-primary", val);
|
document.documentElement.style.setProperty('--el-color-primary', val)
|
||||||
changeSwitch('primary',val)
|
changeSwitch('primary', val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改灰色模式
|
// 修改灰色模式
|
||||||
const changeGrayWeak = (type,val)=>{
|
const changeGrayWeak = (type, val) => {
|
||||||
const body = document.documentElement as HTMLElement;
|
const body = document.documentElement as HTMLElement
|
||||||
if (!val) return body.setAttribute("style", "");
|
if (!val) return body.setAttribute('style', '')
|
||||||
if (type === "gray") body.setAttribute("style", "filter: grayscale(1)");
|
if (type === 'gray') body.setAttribute('style', 'filter: grayscale(1)')
|
||||||
if (type === "weak") body.setAttribute("style", "filter: invert(80%)");
|
if (type === 'weak') body.setAttribute('style', 'filter: invert(80%)')
|
||||||
changeSwitch(type,val)
|
changeSwitch(type, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
::v-deep(.el-drawer__header){
|
::v-deep(.el-drawer__header) {
|
||||||
border-bottom: 1px solid #ebeef5;
|
border-bottom: 1px solid #ebeef5;
|
||||||
padding: 15px 20px 14px;
|
padding: 15px 20px 14px;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
.m-setting-fix {
|
.m-setting-fix {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
|
|
@ -193,19 +184,17 @@
|
||||||
border-radius: 5.5px;
|
border-radius: 5.5px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
background: #ebf5ff;
|
background: #ebf5ff;
|
||||||
transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease,
|
transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
|
||||||
box-shadow 0.15s ease;
|
|
||||||
}
|
}
|
||||||
.item-child2 {
|
.item-child2 {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
color: #b37feb;
|
color: #b37feb;
|
||||||
background: #f7f2fd;
|
background: #f7f2fd;
|
||||||
transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease,
|
transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
|
||||||
box-shadow 0.15s ease;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-drawer__title) {
|
:deep(.el-drawer__title) {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
@ -217,6 +206,5 @@
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: black;
|
color: black;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="m-wangEditor">
|
<div class="m-wangEditor">
|
||||||
<Toolbar
|
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :default-config="toolbarConfig" :mode="mode" />
|
||||||
style="border-bottom: 1px solid #ccc"
|
|
||||||
:editor="editorRef"
|
|
||||||
:defaultConfig="toolbarConfig"
|
|
||||||
:mode="mode"
|
|
||||||
/>
|
|
||||||
<Editor
|
<Editor
|
||||||
class="editor-content'"
|
v-model="valueHtml"
|
||||||
style="height: 300px; overflow-y: hidden;"
|
class="editor-content'"
|
||||||
v-model="valueHtml"
|
style="height: 300px; overflow-y: hidden"
|
||||||
:defaultConfig="editorConfig"
|
:default-config="editorConfig"
|
||||||
:mode="mode"
|
:mode="mode"
|
||||||
@onCreated="handleCreated"
|
@on-created="handleCreated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// 引入 wangEditor
|
// 引入 wangEditor
|
||||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||||
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
||||||
import {onBeforeUnmount, onMounted, watch, shallowRef, ref, computed} from 'vue'
|
import { onBeforeUnmount, onMounted, watch, shallowRef, ref, computed } from 'vue'
|
||||||
let editors = null
|
let editors = null
|
||||||
// 编辑器实例,必须用 shallowRef
|
// 编辑器实例,必须用 shallowRef
|
||||||
const editorRef = shallowRef()
|
const editorRef = shallowRef()
|
||||||
|
|
@ -45,18 +40,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const valueHtml = computed({
|
const valueHtml = computed({
|
||||||
get(){
|
get() {
|
||||||
return props.modelValue
|
return props.modelValue
|
||||||
},
|
},
|
||||||
set(val){
|
set(val) {
|
||||||
// 防止富文本内容为空时,校验失败
|
// 防止富文本内容为空时,校验失败
|
||||||
if (editorRef.value.isEmpty()) val = "";
|
if (editorRef.value.isEmpty()) val = ''
|
||||||
emit('update:modelValue', val)
|
emit('update:modelValue', val)
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// 组件销毁时,也及时销毁编辑器
|
// 组件销毁时,也及时销毁编辑器
|
||||||
onBeforeUnmount(()=>{
|
onBeforeUnmount(() => {
|
||||||
// 调用销毁 API 对当前编辑器实例进行销毁
|
// 调用销毁 API 对当前编辑器实例进行销毁
|
||||||
const editor = editorRef.value
|
const editor = editorRef.value
|
||||||
if (editor == null) {
|
if (editor == null) {
|
||||||
|
|
@ -66,15 +61,15 @@
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.m-wangEditor{
|
.m-wangEditor {
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid #cccccc;
|
border: 1px solid #cccccc;
|
||||||
.editor-toolbar {
|
.editor-toolbar {
|
||||||
border-bottom: 1px solid #cccccc;
|
border-bottom: 1px solid #cccccc;
|
||||||
|
}
|
||||||
|
.editor-content {
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.editor-content {
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="zb-pipeline-start-wrapper">
|
<div class="zb-pipeline-start-wrapper">
|
||||||
<div
|
<div class="zb-pipeline-start" :class="control === value ? 'active' : ''" @click="handleClick">
|
||||||
class="zb-pipeline-start"
|
|
||||||
v-bind:class="control === value ? 'active' : ''"
|
|
||||||
v-on:click="handleClick"
|
|
||||||
>
|
|
||||||
<div class="zb-pipeline-start-header">
|
<div class="zb-pipeline-start-header">
|
||||||
<zb-icon type="play-filled" />
|
<zb-icon type="play-filled" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
// * 默认主题颜色
|
// * 默认主题颜色
|
||||||
export const PRIMARY_COLOR: string = "#409eff";
|
export const PRIMARY_COLOR = '#409eff'
|
||||||
|
|
|
||||||
|
|
@ -4,120 +4,109 @@
|
||||||
* 它原理原理实现如下:
|
* 它原理原理实现如下:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from 'element-plus'
|
||||||
import {onMounted} from "vue";
|
import { onMounted } from 'vue'
|
||||||
|
|
||||||
export const useFullscreen = () => {
|
export const useFullscreen = () => {
|
||||||
/**
|
/**
|
||||||
* @description: 是否支持全屏+判断浏览器前缀
|
* @description: 是否支持全屏+判断浏览器前缀
|
||||||
*/
|
*/
|
||||||
const isFullscreen = ()=> {
|
const isFullscreen = () => {
|
||||||
let prefixName = ""; // 浏览器前缀
|
let prefixName = '' // 浏览器前缀
|
||||||
let fullscreenEnabled = false;
|
let fullscreenEnabled = false
|
||||||
// 判断浏览器前缀
|
// 判断浏览器前缀
|
||||||
if (document.fullscreenEnabled) {
|
if (document.fullscreenEnabled) {
|
||||||
fullscreenEnabled = document.fullscreenEnabled;
|
fullscreenEnabled = document.fullscreenEnabled
|
||||||
// webkit
|
// webkit
|
||||||
} else if (document.webkitFullscreenEnabled) {
|
} else if (document.webkitFullscreenEnabled) {
|
||||||
fullscreenEnabled = document.webkitFullscreenEnabled;
|
fullscreenEnabled = document.webkitFullscreenEnabled
|
||||||
prefixName = "webkit";
|
prefixName = 'webkit'
|
||||||
// moz
|
// moz
|
||||||
} else if (document.mozFullScreenEnabled) {
|
} else if (document.mozFullScreenEnabled) {
|
||||||
fullscreenEnabled = document.mozFullScreenEnabled;
|
fullscreenEnabled = document.mozFullScreenEnabled
|
||||||
prefixName = "moz";
|
prefixName = 'moz'
|
||||||
// ms
|
// ms
|
||||||
} else if (document.msFullscreenEnabled) {
|
} else if (document.msFullscreenEnabled) {
|
||||||
fullscreenEnabled = document.msFullscreenEnabled;
|
fullscreenEnabled = document.msFullscreenEnabled
|
||||||
prefixName = "ms";
|
prefixName = 'ms'
|
||||||
}
|
|
||||||
return {
|
|
||||||
fullscreenEnabled,
|
|
||||||
prefixName
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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: 将传进来的元素全屏
|
* @description: 检测有没有元素处于全屏状态
|
||||||
* @param {String} domName 要全屏的dom名称
|
* @return 布尔值
|
||||||
*/
|
*/
|
||||||
const Fullscreen = (target)=> {
|
const isElementFullScreen = () => {
|
||||||
const targetRef = target || (document == null ? void 0 : document.querySelector("html"));
|
const fullscreenElement =
|
||||||
const {prefixName} = isFullscreen()
|
document.fullscreenElement || document.msFullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement
|
||||||
const methodName =
|
if (fullscreenElement === null) {
|
||||||
prefixName === ""
|
return false // 当前没有元素在全屏状态
|
||||||
? "requestFullscreen"
|
} else {
|
||||||
: `${prefixName}RequestFullScreen`;
|
return true // 有元素在全屏状态
|
||||||
targetRef[methodName]();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 退出全屏
|
/**
|
||||||
const exitFullscreen =()=> {
|
* @description: 将传进来的元素全屏
|
||||||
const {prefixName} = isFullscreen()
|
* @param {String} domName 要全屏的dom名称
|
||||||
const methodName =
|
*/
|
||||||
prefixName === ""
|
const Fullscreen = (target) => {
|
||||||
? "exitFullscreen"
|
const targetRef = target || (document == null ? void 0 : document.querySelector('html'))
|
||||||
: `${prefixName}ExitFullscreen`;
|
const { prefixName } = isFullscreen()
|
||||||
document[methodName]();
|
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: 浏览器无法进入全屏时触发,可能是技术原因,也可能是用户拒绝:比如全屏请求不是在事件处理函数中调用,会在这里拦截到错误
|
* @description: 监听进入/离开全屏
|
||||||
* @param {Function} enterErrorFn 回调
|
* @param {Function} enter 进入全屏的回调
|
||||||
*/
|
* @param {Function} quit 离开全屏的回调
|
||||||
const screenError = ()=> {
|
*/
|
||||||
const {prefixName} = isFullscreen()
|
const screenChange = (enter, quit) => {
|
||||||
const methodName = `on${prefixName}fullscreenerror`;
|
const { fullscreenEnabled, prefixName } = isFullscreen()
|
||||||
document[methodName] = e => {
|
if (!fullscreenEnabled) return
|
||||||
ElMessage.error('进入全屏失败')
|
const methodName = `on${prefixName}fullscreenchange`
|
||||||
};
|
document[methodName] = (e) => {
|
||||||
|
if (isElementFullScreen()) {
|
||||||
|
enter && enter(e) // 进入全屏回调
|
||||||
|
} else {
|
||||||
|
quit && quit(e) // 离开全屏的回调
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
onMounted(() => {
|
||||||
* @description: 监听进入/离开全屏
|
screenError()
|
||||||
* @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(()=>{
|
return {
|
||||||
screenError()
|
isFullscreen,
|
||||||
})
|
isElementFullScreen,
|
||||||
|
Fullscreen,
|
||||||
|
exitFullscreen,
|
||||||
return{
|
screenChange,
|
||||||
isFullscreen,
|
}
|
||||||
isElementFullScreen,
|
|
||||||
Fullscreen,
|
|
||||||
exitFullscreen,
|
|
||||||
screenChange
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,39 @@
|
||||||
import ResizeObserver from "resize-observer-polyfill";
|
import ResizeObserver from 'resize-observer-polyfill'
|
||||||
import { onBeforeUnmount } from "vue";
|
import { onBeforeUnmount } from 'vue'
|
||||||
import requestAnimationFrameThrottle from "@/utils/requestAnimationFrameThrottle"
|
import requestAnimationFrameThrottle from '@/utils/requestAnimationFrameThrottle'
|
||||||
export const useResizeElement = (chart, chartsRef)=>{
|
export const useResizeElement = (chart, chartsRef) => {
|
||||||
let observer = null ;
|
let observer = null
|
||||||
let widthW = 0;
|
let widthW = 0
|
||||||
let heightW = 0;
|
let heightW = 0
|
||||||
const handleResize = (entries )=>{
|
const handleResize = (entries) => {
|
||||||
const { contentRect } = entries[0];
|
const { contentRect } = entries[0]
|
||||||
let {width,height} = contentRect
|
let { width, height } = contentRect
|
||||||
width = Math.floor(width);
|
width = Math.floor(width)
|
||||||
height = Math.floor(height);
|
height = Math.floor(height)
|
||||||
if(widthW!==width|| heightW !== height){
|
if (widthW !== width || heightW !== height) {
|
||||||
widthW = width
|
widthW = width
|
||||||
heightW = height
|
heightW = height
|
||||||
chart && chart.resize()
|
chart && chart.resize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const addObserver = ()=>{
|
const addObserver = () => {
|
||||||
observer = new ResizeObserver(requestAnimationFrameThrottle(handleResize))
|
observer = new ResizeObserver(requestAnimationFrameThrottle(handleResize))
|
||||||
observer.observe(chartsRef)
|
observer.observe(chartsRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeObserver = ()=>{
|
const removeObserver = () => {
|
||||||
if (observer) {
|
if (observer) {
|
||||||
observer.disconnect();
|
observer.disconnect()
|
||||||
observer = null;
|
observer = null
|
||||||
}
|
}
|
||||||
chart&&chart.dispose()
|
chart && chart.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeUnmount(()=>{
|
onBeforeUnmount(() => {
|
||||||
removeObserver()
|
removeObserver()
|
||||||
})
|
})
|
||||||
|
|
||||||
return{
|
return {
|
||||||
addObserver
|
addObserver,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,70 +1,66 @@
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
import {computed, onMounted, onUnmounted, watch} from "vue";
|
import { computed, onMounted, onUnmounted, watch } from 'vue'
|
||||||
import {useRoute} from "vue-router";
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
const { body } = document
|
const { body } = document
|
||||||
|
|
||||||
const WIDTH = 800 // refer to Bootstrap's responsive design
|
const WIDTH = 800 // refer to Bootstrap's responsive design
|
||||||
const MAX_WIDTH = 1200
|
const MAX_WIDTH = 1200
|
||||||
|
|
||||||
export const useResizeHandler = ()=>{
|
export const useResizeHandler = () => {
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const device = computed(()=>{
|
const device = computed(() => {
|
||||||
return SettingStore.device
|
return SettingStore.device
|
||||||
})
|
})
|
||||||
function $_isMobile(){
|
function $_isMobile() {
|
||||||
const rect = body.getBoundingClientRect()
|
const rect = body.getBoundingClientRect()
|
||||||
return rect.width - 1 < WIDTH
|
return rect.width - 1 < WIDTH
|
||||||
|
}
|
||||||
|
|
||||||
|
function collapse() {
|
||||||
|
const rect = body.getBoundingClientRect()
|
||||||
|
if (rect.width - 1 > MAX_WIDTH) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function collapse(){
|
function $_resizeHandler() {
|
||||||
const rect = body.getBoundingClientRect()
|
if (!document.hidden) {
|
||||||
if(rect.width - 1 > MAX_WIDTH){
|
// bool型,表示页面是否处于隐藏状态。页面隐藏包括页面在后台标签页或者浏览器最小化
|
||||||
return true
|
const isMobile = $_isMobile()
|
||||||
}else {
|
const isCollapse = collapse()
|
||||||
return false
|
SettingStore.toggleDevice(isMobile ? 'mobile' : 'desktop')
|
||||||
}
|
|
||||||
|
|
||||||
|
if (isMobile) {
|
||||||
|
SettingStore.closeSideBar({ withoutAnimation: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isMobile) {
|
||||||
|
SettingStore.setCollapse(isCollapse)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function $_resizeHandler(){
|
onMounted(() => {
|
||||||
if (!document.hidden) { // bool型,表示页面是否处于隐藏状态。页面隐藏包括页面在后台标签页或者浏览器最小化
|
const isMobile = $_isMobile()
|
||||||
const isMobile = $_isMobile()
|
if (isMobile) {
|
||||||
const isCollapse = collapse()
|
SettingStore.toggleDevice('mobile')
|
||||||
SettingStore.toggleDevice(isMobile ? 'mobile' : 'desktop')
|
SettingStore.closeSideBar({ withoutAnimation: true })
|
||||||
|
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
SettingStore.closeSideBar({ withoutAnimation: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!isMobile){
|
|
||||||
SettingStore.setCollapse(isCollapse)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
onMounted(()=>{
|
window.addEventListener('resize', $_resizeHandler)
|
||||||
const isMobile = $_isMobile()
|
|
||||||
if (isMobile) {
|
|
||||||
SettingStore.toggleDevice('mobile')
|
|
||||||
SettingStore.closeSideBar({ withoutAnimation: true })
|
|
||||||
}
|
|
||||||
window.addEventListener('resize', $_resizeHandler)
|
|
||||||
|
|
||||||
watch(route,()=>{
|
watch(route, () => {
|
||||||
if (device.value === 'mobile' && SettingStore.isCollapse) {
|
if (device.value === 'mobile' && SettingStore.isCollapse) {
|
||||||
SettingStore.closeSideBar({ withoutAnimation: false })
|
SettingStore.closeSideBar({ withoutAnimation: false })
|
||||||
}
|
}
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
onUnmounted(()=>{
|
onUnmounted(() => {
|
||||||
window.removeEventListener('resize', $_resizeHandler)
|
window.removeEventListener('resize', $_resizeHandler)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return { device }
|
||||||
return {device}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,23 @@
|
||||||
// 自定义name的壳的集合
|
// 自定义name的壳的集合
|
||||||
import {h} from "vue";
|
import { h } from 'vue'
|
||||||
|
|
||||||
const wrapperMap = new Map()
|
const wrapperMap = new Map()
|
||||||
|
|
||||||
export const useWrapComponents = (Component,route)=>{
|
export const useWrapComponents = (Component, route) => {
|
||||||
let wrapper
|
let wrapper
|
||||||
if (Component) {
|
if (Component) {
|
||||||
const wrapperName = route.name
|
const wrapperName = route.name
|
||||||
if (wrapperMap.has(wrapperName)) {
|
if (wrapperMap.has(wrapperName)) {
|
||||||
wrapper = wrapperMap.get(wrapperName)
|
wrapper = wrapperMap.get(wrapperName)
|
||||||
} else {
|
} else {
|
||||||
wrapper = {
|
wrapper = {
|
||||||
name: wrapperName,
|
name: wrapperName,
|
||||||
render() {
|
render() {
|
||||||
return h("div", {className: "app-main-inner"}, Component)
|
return h('div', { className: 'app-main-inner' }, Component)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
wrapperMap.set(wrapperName, wrapper)
|
wrapperMap.set(wrapperName, wrapper)
|
||||||
}
|
|
||||||
return h(wrapper)
|
|
||||||
}
|
}
|
||||||
|
return h(wrapper)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import SvgIcon from '@/components/SvgIcon' // svg component
|
import SvgIcon from '@/components/SvgIcon' // svg component
|
||||||
|
|
||||||
|
|
||||||
// const req = require.context('./svg', false, /\.svg$/)
|
// const req = require.context('./svg', false, /\.svg$/)
|
||||||
const req = import.meta.globEager('./svg/*.svg')
|
const req = import.meta.globEager('./svg/*.svg')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<div class="menu-wrap">
|
<div class="menu-wrap">
|
||||||
<div
|
<div
|
||||||
class="item-menu-wrap"
|
|
||||||
:class="{
|
|
||||||
'active-menu':activeCurrentMenu===item.path
|
|
||||||
}"
|
|
||||||
v-for="item in menusRoutes"
|
v-for="item in menusRoutes"
|
||||||
:key="item.path"
|
:key="item.path"
|
||||||
|
class="item-menu-wrap"
|
||||||
|
:class="{
|
||||||
|
'active-menu': activeCurrentMenu === item.path,
|
||||||
|
}"
|
||||||
@click="handleChangeMenu(item)"
|
@click="handleChangeMenu(item)"
|
||||||
>
|
>
|
||||||
<el-icon :size="20">
|
<el-icon :size="20">
|
||||||
|
|
@ -26,9 +26,9 @@
|
||||||
|
|
||||||
<div class="layout-columns-sub" :style="{ width: isCollapse ? '60px' : '210px' }">
|
<div class="layout-columns-sub" :style="{ width: isCollapse ? '60px' : '210px' }">
|
||||||
<div class="logo flex-center">
|
<div class="logo flex-center">
|
||||||
<span v-show="subMenus.length">{{ isCollapse ? "Vue" : "Vue Admin Perfect" }}</span>
|
<span v-show="subMenus.length">{{ isCollapse ? 'Vue' : 'Vue Admin Perfect' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<el-scrollbar >
|
<el-scrollbar>
|
||||||
<el-menu
|
<el-menu
|
||||||
:collapse="isCollapse"
|
:collapse="isCollapse"
|
||||||
:router="false"
|
:router="false"
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
:collapse-transition="false"
|
:collapse-transition="false"
|
||||||
class="menu-columns"
|
class="menu-columns"
|
||||||
>
|
>
|
||||||
<SubMenu :menuList="subMenus" />
|
<SubMenu :menu-list="subMenus" />
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -45,171 +45,174 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="layout-header">
|
<div class="layout-header">
|
||||||
<div class="header-tool">
|
<div class="header-tool">
|
||||||
<HeaderToolLeft/>
|
<HeaderToolLeft />
|
||||||
<HeaderToolRight/>
|
<HeaderToolRight />
|
||||||
</div>
|
</div>
|
||||||
<TagsView v-if="themeConfig.showTag"/>
|
<TagsView v-if="themeConfig.showTag" />
|
||||||
</div>
|
</div>
|
||||||
<Main/>
|
<Main />
|
||||||
<Footer/>
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch } from "vue";
|
import { ref, computed, watch } from 'vue'
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import {usePermissionStore} from "@/store/modules/permission"
|
import { usePermissionStore } from '@/store/modules/permission'
|
||||||
import { useSettingStore } from "@/store/modules/setting";
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
import Footer from '../components/Footer/index.vue'
|
import Footer from '../components/Footer/index.vue'
|
||||||
import SubMenu from '../components/SubMenu/SubMenu.vue'
|
import SubMenu from '../components/SubMenu/SubMenu.vue'
|
||||||
import TagsView from '../components/TagsView/index.vue'
|
import TagsView from '../components/TagsView/index.vue'
|
||||||
const PermissionStore = usePermissionStore()
|
const PermissionStore = usePermissionStore()
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
import HeaderToolRight from '../components/Header/ToolRight.vue'
|
import HeaderToolRight from '../components/Header/ToolRight.vue'
|
||||||
import HeaderToolLeft from '../components/Header/ToolLeft.vue'
|
import HeaderToolLeft from '../components/Header/ToolLeft.vue'
|
||||||
import Main from '../components/Main/index.vue'
|
import Main from '../components/Main/index.vue'
|
||||||
// 获取路由
|
// 获取路由
|
||||||
const permission_routes = computed(() => PermissionStore.permission_routes)
|
const permission_routes = computed(() => PermissionStore.permission_routes)
|
||||||
|
|
||||||
// 获取路由
|
// 获取路由
|
||||||
const menusRoutes = computed(()=>{
|
const menusRoutes = computed(() => {
|
||||||
return PermissionStore.permission_routes.filter(item=>!item.hidden)
|
return PermissionStore.permission_routes.filter((item) => !item.hidden)
|
||||||
})
|
})
|
||||||
|
|
||||||
const activeCurrentMenu = ref('')
|
const activeCurrentMenu = ref('')
|
||||||
// 主题配置
|
// 主题配置
|
||||||
const themeConfig = computed(() =>SettingStore.themeConfig)
|
const themeConfig = computed(() => SettingStore.themeConfig)
|
||||||
const isCollapse = computed(() =>!SettingStore.isCollapse)
|
const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => {
|
||||||
const { meta, path } = route
|
const { meta, path } = route
|
||||||
return path
|
return path
|
||||||
})
|
})
|
||||||
const basePath = ref<string>('/')
|
const basePath = ref<string>('/')
|
||||||
const subMenus = ref([])
|
const subMenus = ref([])
|
||||||
|
|
||||||
watch(()=>[route],()=>{
|
watch(
|
||||||
if (!menusRoutes.value.length) return;
|
() => [route],
|
||||||
const [firstMenu] = route.matched
|
() => {
|
||||||
activeCurrentMenu.value = firstMenu.path;
|
if (!menusRoutes.value.length) return
|
||||||
let menuItem = menusRoutes.value.find(item=>firstMenu.path === item.path)
|
const [firstMenu] = route.matched
|
||||||
if(menuItem&&menuItem.children?.length) {
|
activeCurrentMenu.value = firstMenu.path
|
||||||
subMenus.value = menuItem.children
|
let menuItem = menusRoutes.value.find((item) => firstMenu.path === item.path)
|
||||||
}else {
|
if (menuItem && menuItem.children?.length) {
|
||||||
subMenus.value = []
|
subMenus.value = menuItem.children
|
||||||
}
|
} else {
|
||||||
basePath.value = firstMenu.path
|
subMenus.value = []
|
||||||
},{
|
}
|
||||||
deep: true,
|
basePath.value = firstMenu.path
|
||||||
immediate:true
|
},
|
||||||
})
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const handleChangeMenu = (item)=>{
|
const handleChangeMenu = (item) => {
|
||||||
router.push(item.path);
|
router.push(item.path)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.main-columns{
|
.main-columns {
|
||||||
display: flex;
|
|
||||||
flex-direction: row!important;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.layout-columns-aside{
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 80px;
|
|
||||||
height: 100%;
|
|
||||||
background-color: #304156;
|
|
||||||
.el-scrollbar{
|
|
||||||
height: calc(100% - 55px);
|
|
||||||
}
|
|
||||||
.logo {
|
|
||||||
box-sizing: border-box;
|
|
||||||
height: 50px;
|
|
||||||
img {
|
|
||||||
width: 32px;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.menu-wrap{
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row !important;
|
||||||
align-items: center;
|
height: 100%;
|
||||||
justify-content: center;
|
width: 100%;
|
||||||
.item-menu-wrap{
|
}
|
||||||
|
.layout-columns-aside {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 80px;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #304156;
|
||||||
|
.el-scrollbar {
|
||||||
|
height: calc(100% - 55px);
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 50px;
|
||||||
|
img {
|
||||||
|
width: 32px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.menu-wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: 70px;
|
.item-menu-wrap {
|
||||||
width: 70px;
|
display: flex;
|
||||||
cursor: pointer;
|
flex-direction: column;
|
||||||
transition: all .3s ease;
|
align-items: center;
|
||||||
}
|
justify-content: center;
|
||||||
.active-menu{
|
height: 70px;
|
||||||
background: $primaryColor;
|
width: 70px;
|
||||||
border-radius: 5px;
|
cursor: pointer;
|
||||||
}
|
transition: all 0.3s ease;
|
||||||
.title{
|
}
|
||||||
color: #e5eaf3;
|
.active-menu {
|
||||||
}
|
background: $primaryColor;
|
||||||
.el-icon{
|
border-radius: 5px;
|
||||||
color: #e5eaf3;
|
}
|
||||||
|
.title {
|
||||||
|
color: #e5eaf3;
|
||||||
|
}
|
||||||
|
.el-icon {
|
||||||
|
color: #e5eaf3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.layout-columns-sub{
|
.layout-columns-sub {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width:200px;
|
width: 200px;
|
||||||
box-sizing: border-box;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
background: white;
|
|
||||||
border-right: 1px solid #eee;
|
|
||||||
.el-scrollbar{
|
|
||||||
height: calc(100vh - 50px);
|
|
||||||
}
|
|
||||||
.logo {
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 50px;
|
flex-direction: column;
|
||||||
border-bottom: 1px solid #eee;
|
overflow: hidden;
|
||||||
span{
|
transition: all 0.3s ease;
|
||||||
font-weight: bold;
|
background: white;
|
||||||
white-space: nowrap;
|
border-right: 1px solid #eee;
|
||||||
|
.el-scrollbar {
|
||||||
|
height: calc(100vh - 50px);
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 50px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
span {
|
||||||
|
font-weight: bold;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::v-deep(.menu-columns) {
|
||||||
|
border-right: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
::v-deep(.menu-columns){
|
.container {
|
||||||
border-right: none;
|
flex: 1;
|
||||||
}
|
overflow: hidden;
|
||||||
}
|
|
||||||
.container{
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.layout-header{
|
|
||||||
background: white;
|
|
||||||
transition: width 0.28s;
|
|
||||||
flex-shrink: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
|
|
||||||
.header-tool{
|
|
||||||
height: 50px;
|
|
||||||
width: 100%;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
padding: 0 10px 0 0;
|
}
|
||||||
box-sizing: border-box;
|
.layout-header {
|
||||||
justify-content: space-between;
|
background: white;
|
||||||
|
transition: width 0.28s;
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
box-shadow: 0 1px 4px rgb(0 21 41 / 8%);
|
||||||
|
.header-tool {
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -9,29 +9,26 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: 1px solid #eee;
|
border-bottom: 1px solid #eee;
|
||||||
display: flex;
|
display: flex;
|
||||||
background-color:$menuBg;
|
background-color: $menuBg;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 10px 0 0;
|
padding: 0 10px 0 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fixed-header{
|
.fixed-header {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-horizontal{
|
.menu-horizontal {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
:deep(.el-menu-item){
|
:deep(.el-menu-item) {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,69 +1,61 @@
|
||||||
<template>
|
<template>
|
||||||
<!--纵向布局-->
|
<!--纵向布局-->
|
||||||
<Height/>
|
<Height />
|
||||||
<div
|
<div
|
||||||
class="m-layout-header"
|
class="m-layout-header"
|
||||||
:class="{
|
:class="{
|
||||||
'fixed-header':themeConfig.fixedHeader,
|
'fixed-header': themeConfig.fixedHeader,
|
||||||
}">
|
}"
|
||||||
<div class="header-inner">
|
>
|
||||||
<el-menu
|
<div class="header-inner">
|
||||||
mode="horizontal"
|
<el-menu
|
||||||
:default-active="activeMenu"
|
mode="horizontal"
|
||||||
background-color="#304156"
|
:default-active="activeMenu"
|
||||||
text-color="#bfcbd9"
|
background-color="#304156"
|
||||||
:unique-opened="SettingStore.themeConfig.uniqueOpened"
|
text-color="#bfcbd9"
|
||||||
:collapse-transition="false"
|
:unique-opened="SettingStore.themeConfig.uniqueOpened"
|
||||||
class="menu-horizontal"
|
:collapse-transition="false"
|
||||||
>
|
class="menu-horizontal"
|
||||||
<SubItem
|
>
|
||||||
v-for="route in permission_routes"
|
<SubItem v-for="route in permission_routes" :key="route.path" :item="route" />
|
||||||
:key="route.path"
|
</el-menu>
|
||||||
:item="route"
|
<HeaderToolRight />
|
||||||
|
|
||||||
/>
|
|
||||||
</el-menu>
|
|
||||||
<HeaderToolRight/>
|
|
||||||
</div>
|
|
||||||
<TagsView v-if="themeConfig.showTag"/>
|
|
||||||
</div>
|
</div>
|
||||||
|
<TagsView v-if="themeConfig.showTag" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// 引入组件
|
// 引入组件
|
||||||
import Height from '../../components/Header/components/Height.vue'
|
import Height from '../../components/Header/components/Height.vue'
|
||||||
import HeaderToolRight from '../../components/Header/ToolRight.vue'
|
import HeaderToolRight from '../../components/Header/ToolRight.vue'
|
||||||
import TagsView from '../../components/TagsView/index.vue'
|
import TagsView from '../../components/TagsView/index.vue'
|
||||||
import SubItem from '../../components/SubMenu/SubItem.vue'
|
import SubItem from '../../components/SubMenu/SubItem.vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import {usePermissionStore} from "@/store/modules/permission"
|
import { usePermissionStore } from '@/store/modules/permission'
|
||||||
const PermissionStore = usePermissionStore()
|
const PermissionStore = usePermissionStore()
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
// 获取路由
|
// 获取路由
|
||||||
const permission_routes = computed(() => PermissionStore.permission_routes)
|
const permission_routes = computed(() => PermissionStore.permission_routes)
|
||||||
import {computed} from "vue";
|
import { computed } from 'vue'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
|
|
||||||
const activeMenu = computed(() => {
|
const activeMenu = computed(() => {
|
||||||
const { meta, path } = route
|
const { meta, path } = route
|
||||||
if (meta.activeMenu) {
|
if (meta.activeMenu) {
|
||||||
return meta.activeMenu
|
return meta.activeMenu
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 主题配置
|
||||||
// 主题配置
|
const themeConfig = computed(() => SettingStore.themeConfig)
|
||||||
const themeConfig = computed(() =>SettingStore.themeConfig)
|
const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||||
const isCollapse = computed(() =>!SettingStore.isCollapse)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./index.scss";
|
@import './index.scss';
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
<UHeader/>
|
<UHeader />
|
||||||
<Main/>
|
<Main />
|
||||||
<Footer/>
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import Sidebar from '../components/Sidebar/index.vue'
|
import Sidebar from '../components/Sidebar/index.vue'
|
||||||
import UHeader from './HeaderHorizontal/index.vue'
|
import UHeader from './HeaderHorizontal/index.vue'
|
||||||
import Main from '../components/Main/index.vue'
|
import Main from '../components/Main/index.vue'
|
||||||
import Footer from '../components/Footer/index.vue'
|
import Footer from '../components/Footer/index.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.main-container{
|
.main-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
.mobile {
|
.mobile {
|
||||||
.m-layout-header {
|
.m-layout-header {
|
||||||
left: 0 !important;
|
left: 0 !important;
|
||||||
width: 100%!important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.show-tag{
|
.show-tag {
|
||||||
height: 90px;
|
height: 90px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.zb-no-fixed-header {
|
||||||
.zb-no-fixed-header{
|
width: 100% !important;
|
||||||
width: 100%!important;;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.m-layout-header {
|
.m-layout-header {
|
||||||
|
|
@ -32,39 +31,37 @@
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fixed-header{
|
.fixed-header {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 9;
|
z-index: 9;
|
||||||
}
|
}
|
||||||
.collapse{
|
.collapse {
|
||||||
width: calc(100% - 60px);
|
width: calc(100% - 60px);
|
||||||
}
|
}
|
||||||
.no-collapse{
|
.no-collapse {
|
||||||
width: calc(100% - 210px);
|
width: calc(100% - 210px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.el-dropdown {
|
.el-dropdown {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.transverseMenu{
|
.transverseMenu {
|
||||||
display: flex;
|
display: flex;
|
||||||
.el-menu{
|
.el-menu {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
:deep(.el-menu-item){
|
:deep(.el-menu-item) {
|
||||||
height: 100% !important;
|
height: 100% !important;
|
||||||
}
|
}
|
||||||
.tool-bar-right{
|
.tool-bar-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
min-width:300px ;
|
min-width: 300px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,38 @@
|
||||||
<template>
|
<template>
|
||||||
<!--纵向布局-->
|
<!--纵向布局-->
|
||||||
<Height/>
|
<Height />
|
||||||
<div
|
<div
|
||||||
class="m-layout-header"
|
class="m-layout-header"
|
||||||
:class="{
|
:class="{
|
||||||
'fixed-header':themeConfig.fixedHeader,
|
'fixed-header': themeConfig.fixedHeader,
|
||||||
'collapse':themeConfig.fixedHeader&&isCollapse,
|
collapse: themeConfig.fixedHeader && isCollapse,
|
||||||
'no-collapse':themeConfig.fixedHeader&&!isCollapse
|
'no-collapse': themeConfig.fixedHeader && !isCollapse,
|
||||||
}">
|
}"
|
||||||
|
>
|
||||||
<div class="header-inner">
|
<div class="header-inner">
|
||||||
<HeaderToolLeft/>
|
<HeaderToolLeft />
|
||||||
<HeaderToolRight/>
|
<HeaderToolRight />
|
||||||
</div>
|
</div>
|
||||||
<TagsView v-if="themeConfig.showTag"/>
|
<TagsView v-if="themeConfig.showTag" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// 引入组件
|
// 引入组件
|
||||||
import Height from '../../components/Header/components/Height.vue'
|
import Height from '../../components/Header/components/Height.vue'
|
||||||
import HeaderToolRight from '../../components/Header/ToolRight.vue'
|
import HeaderToolRight from '../../components/Header/ToolRight.vue'
|
||||||
import HeaderToolLeft from '../../components/Header/ToolLeft.vue'
|
import HeaderToolLeft from '../../components/Header/ToolLeft.vue'
|
||||||
import TagsView from '../../components/TagsView/index.vue'
|
import TagsView from '../../components/TagsView/index.vue'
|
||||||
|
|
||||||
import {computed} from "vue";
|
import { computed } from 'vue'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
|
|
||||||
// 主题配置
|
// 主题配置
|
||||||
const themeConfig = computed(() =>SettingStore.themeConfig)
|
const themeConfig = computed(() => SettingStore.themeConfig)
|
||||||
const isCollapse = computed(() =>!SettingStore.isCollapse)
|
const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./index.scss";
|
@import './index.scss';
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,46 @@
|
||||||
<template>
|
<template>
|
||||||
<!--纵向布局-->
|
<!--纵向布局-->
|
||||||
<Sidebar/>
|
<Sidebar />
|
||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
<HeaderVertical/>
|
<HeaderVertical />
|
||||||
<Main/>
|
<Main />
|
||||||
<Footer/>
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import Sidebar from '../components/Sidebar/index.vue'
|
import Sidebar from '../components/Sidebar/index.vue'
|
||||||
import HeaderVertical from './HeaderVertical/index.vue'
|
import HeaderVertical from './HeaderVertical/index.vue'
|
||||||
import Main from '../components/Main/index.vue'
|
import Main from '../components/Main/index.vue'
|
||||||
import Footer from '../components/Footer/index.vue'
|
import Footer from '../components/Footer/index.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.g-container-layout {
|
.g-container-layout {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.main-container {
|
.main-container {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
&.mobile.openSidebar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sidebar-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
|
||||||
box-sizing: border-box;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
&.mobile.openSidebar {
|
.drawer-bg {
|
||||||
position: fixed;
|
background: #000;
|
||||||
|
opacity: 0.3;
|
||||||
|
width: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 90;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.sidebar-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.drawer-bg {
|
|
||||||
background: #000;
|
|
||||||
opacity: 0.3;
|
|
||||||
width: 100%;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 90;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="footer-layout">
|
<div class="footer-layout">
|
||||||
<span href="/" target="_blank"> 2022 © VUE-ADMIN-PERFECT By ZB Technology. </span>
|
<span href="/" target="_blank"> 2022 © VUE-ADMIN-PERFECT By ZB Technology. </span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.footer-layout{
|
.footer-layout {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
border-top: 1px solid #e4e7ed;
|
border-top: 1px solid #e4e7ed;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
color: rgba(0, 0, 0, 0.45);
|
color: rgba(0, 0, 0, 0.45);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="m-tool-left">
|
<div class="m-tool-left">
|
||||||
<CollapseIcon/>
|
<CollapseIcon />
|
||||||
<Hamburger />
|
<Hamburger />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import CollapseIcon from './components/CollapseIcon.vue'
|
import CollapseIcon from './components/CollapseIcon.vue'
|
||||||
import Hamburger from './components/Hamburger.vue'
|
import Hamburger from './components/Hamburger.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.m-tool-left{
|
.m-tool-left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="m-tool-right">
|
<div class="m-tool-right">
|
||||||
<GlobalComSize class="item-children"/>
|
<GlobalComSize class="item-children" />
|
||||||
<HeaderSearch class="item-children"/>
|
<HeaderSearch class="item-children" />
|
||||||
<Remind class="item-children"/>
|
<Remind class="item-children" />
|
||||||
<ScreenFull class="item-children"/>
|
<ScreenFull class="item-children" />
|
||||||
<Setting class="item-children"/>
|
<Setting class="item-children" />
|
||||||
<Avatar/>
|
<Avatar />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import GlobalComSize from './components/globalComSize.vue'
|
import GlobalComSize from './components/globalComSize.vue'
|
||||||
import HeaderSearch from './components/HeaderSearch.vue'
|
import HeaderSearch from './components/HeaderSearch.vue'
|
||||||
import Remind from './components/Remind.vue'
|
import Remind from './components/Remind.vue'
|
||||||
import ScreenFull from './components/ScreenFull.vue'
|
import ScreenFull from './components/ScreenFull.vue'
|
||||||
import Setting from './components/Setting.vue'
|
import Setting from './components/Setting.vue'
|
||||||
import Avatar from './components/Avatar.vue'
|
import Avatar from './components/Avatar.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.m-tool-right{
|
.m-tool-right {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
.item-children{
|
.item-children {
|
||||||
margin-right: 22px;
|
margin-right: 22px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,104 +1,104 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dropdown >
|
<el-dropdown>
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
<el-avatar :size="30" class="avatar" :src="AvatarLogo"/>
|
<el-avatar :size="30" class="avatar" :src="AvatarLogo" />
|
||||||
{{userInfo.username}}
|
{{ userInfo.username }}
|
||||||
<el-icon class="header-icon el-icon--right">
|
<el-icon class="header-icon el-icon--right">
|
||||||
<arrow-down />
|
<arrow-down />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</span>
|
</span>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item :command="0" @click="switchRolesAction('admin')">
|
<el-dropdown-item :command="0" @click="switchRolesAction('admin')">
|
||||||
{{currentRoles==='admin'?'当前角色':'切换角色'}}:管理员
|
{{ currentRoles === 'admin' ? '当前角色' : '切换角色' }}:管理员
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item :command="0" divided @click="switchRolesAction('other')">
|
<el-dropdown-item :command="0" divided @click="switchRolesAction('other')">
|
||||||
{{currentRoles==='other'?'当前角色':'切换角色'}}:普通用户
|
{{ currentRoles === 'other' ? '当前角色' : '切换角色' }}:普通用户
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item :command="3" divided @click="modifyPassword">
|
<el-dropdown-item :command="3" divided @click="modifyPassword">
|
||||||
<el-icon><Edit /></el-icon>修改密码
|
<el-icon><Edit /></el-icon>修改密码
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item :command="4" divided @click="logOut" >
|
<el-dropdown-item :command="4" divided @click="logOut">
|
||||||
<el-icon><SwitchButton /></el-icon>退出登录
|
<el-icon><SwitchButton /></el-icon>退出登录
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
|
|
||||||
<PersonalDialog ref="person"/>
|
<PersonalDialog ref="person" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import {ElMessage, ElMessageBox} from "element-plus";
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import {computed, ref} from "vue";
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
import AvatarLogo from '@/assets/image/avatar.png'
|
import AvatarLogo from '@/assets/image/avatar.png'
|
||||||
import {useUserStore} from "@/store/modules/user"
|
import { useUserStore } from '@/store/modules/user'
|
||||||
import {useTagsViewStore} from "@/store/modules/tagsView"
|
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||||
import {usePermissionStore} from "@/store/modules/permission"
|
import { usePermissionStore } from '@/store/modules/permission'
|
||||||
import PersonalDialog from './PersonalDialog.vue'
|
import PersonalDialog from './PersonalDialog.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const UserStore = useUserStore()
|
const UserStore = useUserStore()
|
||||||
const TagsViewStore = useTagsViewStore()
|
const TagsViewStore = useTagsViewStore()
|
||||||
const PermissionStore = usePermissionStore()
|
const PermissionStore = usePermissionStore()
|
||||||
|
|
||||||
const currentRoles = computed({
|
const currentRoles = computed({
|
||||||
get() {
|
get() {
|
||||||
return UserStore.roles[0]
|
return UserStore.roles[0]
|
||||||
},
|
},
|
||||||
set(val) {
|
set(val) {
|
||||||
;(async () => {
|
;(async () => {
|
||||||
await UserStore.getInfo([val])
|
await UserStore.getInfo([val])
|
||||||
router.push({
|
router.push({
|
||||||
path:'/'
|
path: '/',
|
||||||
})
|
})
|
||||||
location.reload()
|
location.reload()
|
||||||
})()
|
})()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const switchRolesAction = (type:string)=>{
|
const switchRolesAction = (type: string) => {
|
||||||
if(type===currentRoles.value) return
|
if (type === currentRoles.value) return
|
||||||
currentRoles.value = currentRoles.value==='admin'?'other':'admin'
|
currentRoles.value = currentRoles.value === 'admin' ? 'other' : 'admin'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户信息
|
// 用户信息
|
||||||
const userInfo = computed(() => UserStore.userInfo)
|
const userInfo = computed(() => UserStore.userInfo)
|
||||||
const person = ref()
|
const person = ref()
|
||||||
|
|
||||||
const logOut = async () => {
|
const logOut = async () => {
|
||||||
ElMessageBox.confirm('您是否确认退出登录?', '温馨提示', {
|
ElMessageBox.confirm('您是否确认退出登录?', '温馨提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
await UserStore.logout()
|
await UserStore.logout()
|
||||||
await router.push({path: '/login'})
|
await router.push({ path: '/login' })
|
||||||
TagsViewStore.clearVisitedView()
|
TagsViewStore.clearVisitedView()
|
||||||
PermissionStore.clearRoutes()
|
PermissionStore.clearRoutes()
|
||||||
ElMessage({
|
ElMessage({
|
||||||
type: "success",
|
type: 'success',
|
||||||
message: "退出登录成功!"
|
message: '退出登录成功!',
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
}
|
}
|
||||||
const modifyPassword = ()=>{
|
const modifyPassword = () => {
|
||||||
person.value.show()
|
person.value.show()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.avatar{
|
.avatar {
|
||||||
margin-right: 6px
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
.el-dropdown-link {
|
.el-dropdown-link {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
//color: var(--el-color-primary);
|
//color: var(--el-color-primary);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,30 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="hamburger-container" @click="handleCollapse">
|
<div class="hamburger-container" @click="handleCollapse">
|
||||||
<el-icon class="icon" v-if="isCollapse" ><expand /></el-icon>
|
<el-icon v-if="isCollapse" class="icon"><expand /></el-icon>
|
||||||
<el-icon class="icon" v-else><fold /></el-icon>
|
<el-icon v-else class="icon"><fold /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
import {computed} from "vue";
|
import { computed } from 'vue'
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
const isCollapse = computed(() =>!SettingStore.isCollapse)
|
const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||||
const handleCollapse = () => {
|
const handleCollapse = () => {
|
||||||
SettingStore.setCollapse(isCollapse.value)
|
SettingStore.setCollapse(isCollapse.value)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.hamburger-container{
|
.hamburger-container {
|
||||||
padding: 0px 15px;
|
padding: 0px 15px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(0, 0, 0, .025)
|
background: rgba(0, 0, 0, 0.025);
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
font-size: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.icon {
|
|
||||||
font-size: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||||
<transition-group name="breadcrumb" >
|
<transition-group name="breadcrumb">
|
||||||
<el-breadcrumb-item :to="{ path: '/' }" key="home" v-if="matched[0].meta.title !== '首页'">
|
<el-breadcrumb-item v-if="matched[0].meta.title !== '首页'" key="home" :to="{ path: '/' }">
|
||||||
<div class="breadcrumb-item">
|
<div class="breadcrumb-item">
|
||||||
<span class="breadcrumb-title">首页</span>
|
<span class="breadcrumb-title">首页</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -15,20 +15,17 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useRoute ,useRouter} from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const handleLink = (item)=>{
|
|
||||||
router.push({
|
|
||||||
path:item.path
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const matched = computed(() => route.matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false));
|
|
||||||
|
|
||||||
|
const handleLink = (item) => {
|
||||||
|
router.push({
|
||||||
|
path: item.path,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const matched = computed(() => route.matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,27 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="m-headerSearch">
|
<div class="m-headerSearch">
|
||||||
<el-tooltip effect="dark" content="菜单搜索" placement="bottom">
|
<el-tooltip effect="dark" content="菜单搜索" placement="bottom">
|
||||||
<el-icon class="bell header-icon" style="font-size: 22px;" @click="handleSearch"><Search /></el-icon>
|
<el-icon class="bell header-icon" style="font-size: 22px" @click="handleSearch"><Search /></el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-dialog v-model="isShowSearch" width="600px" destroy-on-close :show-close="false">
|
<el-dialog v-model="isShowSearch" width="600px" destroy-on-close :show-close="false">
|
||||||
<el-select
|
<el-select
|
||||||
style="width: 100%"
|
ref="headerSearchSelect"
|
||||||
ref="headerSearchSelect"
|
v-model="search"
|
||||||
v-model="search"
|
style="width: 100%"
|
||||||
:remote-method="querySearch"
|
:remote-method="querySearch"
|
||||||
filterable
|
filterable
|
||||||
default-first-option
|
default-first-option
|
||||||
remote
|
remote
|
||||||
placeholder="菜单搜索 :支持菜单名称、路径"
|
placeholder="菜单搜索 :支持菜单名称、路径"
|
||||||
class="header-search-select"
|
class="header-search-select"
|
||||||
@change="change"
|
@change="change"
|
||||||
>
|
>
|
||||||
<el-option v-for="item in options" :key="item.item.path" :value="item.item.path" :label="item&&item.item.title&&item.item.title.length&&item.item.title.join(' > ') " >
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.item.path"
|
||||||
|
:value="item.item.path"
|
||||||
|
:label="item && item.item.title && item.item.title.length && item.item.title.join(' > ')"
|
||||||
|
>
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -25,147 +29,149 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {computed, onMounted, ref, watch} from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
import path from 'path-browserify'
|
import path from 'path-browserify'
|
||||||
import Fuse from 'fuse.js'
|
import Fuse from 'fuse.js'
|
||||||
import { useVueFuse } from 'vue-fuse'
|
import { useVueFuse } from 'vue-fuse'
|
||||||
import {useRouter} from "vue-router";
|
import { useRouter } from 'vue-router'
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const isShowSearch = ref(false);
|
const isShowSearch = ref(false)
|
||||||
const options = ref([]);
|
const options = ref([])
|
||||||
const searchPool = ref([]);
|
const searchPool = ref([])
|
||||||
const search = ref('');
|
const search = ref('')
|
||||||
const fuse = ref(null);
|
const fuse = ref(null)
|
||||||
import {usePermissionStore} from "@/store/modules/permission"
|
import { usePermissionStore } from '@/store/modules/permission'
|
||||||
const PermissionStore = usePermissionStore()
|
const PermissionStore = usePermissionStore()
|
||||||
const routes = computed(() => PermissionStore.routes)
|
const routes = computed(() => PermissionStore.routes)
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
isShowSearch.value = true
|
isShowSearch.value = true
|
||||||
}
|
|
||||||
|
|
||||||
const initFuse = (list)=> {
|
|
||||||
fuse.value = new Fuse(list, {
|
|
||||||
shouldSort: true,
|
|
||||||
threshold: 0.4,
|
|
||||||
location: 0,
|
|
||||||
distance: 100,
|
|
||||||
maxPatternLength: 32,
|
|
||||||
minMatchCharLength: 1,
|
|
||||||
keys: [{
|
|
||||||
name: 'title',
|
|
||||||
weight: 0.7
|
|
||||||
}, {
|
|
||||||
name: 'path',
|
|
||||||
weight: 0.3
|
|
||||||
}]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(searchPool,(list)=>{
|
|
||||||
initFuse(list)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 筛选出可以在侧栏中显示的路线 生成标题
|
|
||||||
const generateRoutes = (routes, basePath = '/', prefixTitle = [])=>{
|
|
||||||
let res = []
|
|
||||||
|
|
||||||
for (const router of routes) {
|
|
||||||
// 忽略隐藏的路由
|
|
||||||
if (router.hidden) { continue }
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
path: path.resolve(basePath, router.path),
|
|
||||||
title: [...prefixTitle]
|
|
||||||
}
|
|
||||||
if (router.meta && router.meta.title) {
|
|
||||||
data.title = [...data.title, router.meta.title]
|
|
||||||
|
|
||||||
if (router.redirect !== 'noRedirect') {
|
|
||||||
// 仅推送带有标题的路由
|
|
||||||
// 特殊情况:需要排除无重定向的父路由器
|
|
||||||
res.push(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 递归子路由
|
|
||||||
if (router.children) {
|
|
||||||
const tempRoutes = generateRoutes(router.children, data.path, data.title)
|
|
||||||
if (tempRoutes.length >= 1) {
|
|
||||||
res = [...res, ...tempRoutes]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
const change=(val)=> {
|
const initFuse = (list) => {
|
||||||
if(val){
|
fuse.value = new Fuse(list, {
|
||||||
router.push({
|
shouldSort: true,
|
||||||
path: val,
|
threshold: 0.4,
|
||||||
|
location: 0,
|
||||||
|
distance: 100,
|
||||||
|
maxPatternLength: 32,
|
||||||
|
minMatchCharLength: 1,
|
||||||
|
keys: [
|
||||||
|
{
|
||||||
|
name: 'title',
|
||||||
|
weight: 0.7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'path',
|
||||||
|
weight: 0.3,
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
options.value = []
|
|
||||||
search.value = ''
|
|
||||||
isShowSearch.value = false
|
|
||||||
}
|
|
||||||
onMounted(()=>{
|
|
||||||
searchPool.value = generateRoutes(JSON.parse(JSON.stringify(routes.value)))
|
|
||||||
})
|
|
||||||
|
|
||||||
const querySearch=(query)=> {
|
watch(searchPool, (list) => {
|
||||||
if (query !== '') {
|
initFuse(list)
|
||||||
options.value = fuse.value.search(query)
|
})
|
||||||
} else {
|
|
||||||
options.value = []
|
// 筛选出可以在侧栏中显示的路线 生成标题
|
||||||
|
const generateRoutes = (routes, basePath = '/', prefixTitle = []) => {
|
||||||
|
let res = []
|
||||||
|
|
||||||
|
for (const router of routes) {
|
||||||
|
// 忽略隐藏的路由
|
||||||
|
if (router.hidden) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
path: path.resolve(basePath, router.path),
|
||||||
|
title: [...prefixTitle],
|
||||||
|
}
|
||||||
|
if (router.meta && router.meta.title) {
|
||||||
|
data.title = [...data.title, router.meta.title]
|
||||||
|
|
||||||
|
if (router.redirect !== 'noRedirect') {
|
||||||
|
// 仅推送带有标题的路由
|
||||||
|
// 特殊情况:需要排除无重定向的父路由器
|
||||||
|
res.push(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 递归子路由
|
||||||
|
if (router.children) {
|
||||||
|
const tempRoutes = generateRoutes(router.children, data.path, data.title)
|
||||||
|
if (tempRoutes.length >= 1) {
|
||||||
|
res = [...res, ...tempRoutes]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
const change = (val) => {
|
||||||
|
if (val) {
|
||||||
|
router.push({
|
||||||
|
path: val,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
options.value = []
|
||||||
|
search.value = ''
|
||||||
|
isShowSearch.value = false
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
searchPool.value = generateRoutes(JSON.parse(JSON.stringify(routes.value)))
|
||||||
|
})
|
||||||
|
|
||||||
|
const querySearch = (query) => {
|
||||||
|
if (query !== '') {
|
||||||
|
options.value = fuse.value.search(query)
|
||||||
|
} else {
|
||||||
|
options.value = []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.m-headerSearch {
|
.m-headerSearch {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s;
|
|
||||||
.item-info-pop {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
justify-content: center;
|
||||||
.bell{
|
cursor: pointer;
|
||||||
color: black;
|
transition: all 0.3s;
|
||||||
}
|
.item-info-pop {
|
||||||
.item-child {
|
display: flex;
|
||||||
display: flex;
|
align-items: center;
|
||||||
align-items: center;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.transverseMenu {
|
|
||||||
.bell {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.header-search-select{
|
|
||||||
|
|
||||||
}
|
|
||||||
/* 菜单搜索样式 */
|
|
||||||
.m-headerSearch {
|
|
||||||
:deep(.el-dialog) {
|
|
||||||
.el-dialog__header {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
.el-dialog__body{
|
.bell {
|
||||||
padding: 0;
|
color: black;
|
||||||
|
}
|
||||||
|
.item-child {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.header-search-select{
|
.transverseMenu {
|
||||||
height: 50px;
|
.bell {
|
||||||
:deep(.el-input__wrapper){
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.header-search-select {
|
||||||
|
}
|
||||||
|
/* 菜单搜索样式 */
|
||||||
|
.m-headerSearch {
|
||||||
|
:deep(.el-dialog) {
|
||||||
|
.el-dialog__header {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.el-dialog__body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.header-search-select {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
:deep(.el-input__wrapper) {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div v-if="themeConfig.fixedHeader" :style="{ height: `${themeConfig.showTag ? 90 : 50}px` }"> </div>
|
||||||
:style="{ height:`${themeConfig.showTag?90:50}px`}"
|
|
||||||
v-if="themeConfig.fixedHeader">
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {computed} from "vue";
|
import { computed } from 'vue'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
const themeConfig = computed(()=>SettingStore.themeConfig)
|
const themeConfig = computed(() => SettingStore.themeConfig)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="dialogVisible" title="修改密码" width="40%">
|
<el-dialog v-model="dialogVisible" title="修改密码" width="40%">
|
||||||
<el-form
|
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="120px" class="demo-ruleForm" :size="formSize">
|
||||||
ref="ruleFormRef"
|
|
||||||
:model="ruleForm"
|
|
||||||
:rules="rules"
|
|
||||||
label-width="120px"
|
|
||||||
class="demo-ruleForm"
|
|
||||||
:size="formSize"
|
|
||||||
>
|
|
||||||
<el-form-item label="姓名">
|
<el-form-item label="姓名">
|
||||||
<el-input v-model="ruleForm.name" disabled></el-input>
|
<el-input v-model="ruleForm.name" disabled></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -31,7 +24,7 @@
|
||||||
import { ref, defineExpose, reactive } from 'vue'
|
import { ref, defineExpose, reactive } from 'vue'
|
||||||
import type { ElForm } from 'element-plus'
|
import type { ElForm } from 'element-plus'
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
import {useUserStore} from "@/store/modules/user"
|
import { useUserStore } from '@/store/modules/user'
|
||||||
const UserStore = useUserStore()
|
const UserStore = useUserStore()
|
||||||
const show = () => {
|
const show = () => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,28 @@
|
||||||
<el-popover width="200px" placement="bottom">
|
<el-popover width="200px" placement="bottom">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-badge :value="3" class="item-info-pop">
|
<el-badge :value="3" class="item-info-pop">
|
||||||
<el-icon class="bell header-icon" style="font-size: 20px;"><Bell /></el-icon>
|
<el-icon class="bell header-icon" style="font-size: 20px"><Bell /></el-icon>
|
||||||
</el-badge>
|
</el-badge>
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<div>
|
||||||
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
|
||||||
<el-tab-pane label="通知" name="first">
|
<el-tab-pane label="通知" name="first">
|
||||||
<div class="item-child">
|
<div class="item-child">
|
||||||
GitHub开源地址:<el-button type="primary" link @click="toGitHub('https://github.com/zouzhibin/vue-admin-perfect')">点我</el-button></div
|
GitHub开源地址:<el-button type="primary" link @click="toGitHub('https://github.com/zouzhibin/vue-admin-perfect')"
|
||||||
|
>点我</el-button
|
||||||
|
></div
|
||||||
>
|
>
|
||||||
<el-divider style="margin-bottom: 15px"/>
|
<el-divider style="margin-bottom: 15px" />
|
||||||
<div class="item-child">
|
<div class="item-child">
|
||||||
Gitee开源地址:<el-button type="primary" link @click="toGitHub('https://gitee.com/yuanzbz/vue-admin-perfect')">点我</el-button></div
|
Gitee开源地址:<el-button type="primary" link @click="toGitHub('https://gitee.com/yuanzbz/vue-admin-perfect')"
|
||||||
|
>点我</el-button
|
||||||
|
></div
|
||||||
>
|
>
|
||||||
<el-divider />
|
<el-divider />
|
||||||
<div class="item-child">
|
<div class="item-child">
|
||||||
github开源地址:<el-button type="primary" link @click="toGitHub('https://github.com/zouzhibin/vue-admin-perfect')">点我</el-button></div
|
github开源地址:<el-button type="primary" link @click="toGitHub('https://github.com/zouzhibin/vue-admin-perfect')"
|
||||||
|
>点我</el-button
|
||||||
|
></div
|
||||||
>
|
>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
|
|
@ -28,45 +34,45 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import type { TabsPaneContext } from 'element-plus'
|
import type { TabsPaneContext } from 'element-plus'
|
||||||
|
|
||||||
const activeName = ref('first')
|
const activeName = ref('first')
|
||||||
const toGitHub = (link) => {
|
const toGitHub = (link) => {
|
||||||
window.open(link)
|
window.open(link)
|
||||||
}
|
}
|
||||||
const handleClick = (tab: TabsPaneContext, event: Event) => {
|
const handleClick = (tab: TabsPaneContext, event: Event) => {
|
||||||
console.log(tab, event)
|
console.log(tab, event)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.m-info {
|
.m-info {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s;
|
|
||||||
.item-info-pop {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
.item-info-pop {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.bell {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.item-child {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.bell{
|
::v-deep(.el-divider--horizontal) {
|
||||||
color: black;
|
margin-bottom: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
.item-child {
|
.transverseMenu {
|
||||||
display: flex;
|
.bell {
|
||||||
align-items: center;
|
color: white;
|
||||||
font-size: 13px;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
::v-deep(.el-divider--horizontal){
|
|
||||||
margin-bottom: 10px;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
.transverseMenu {
|
|
||||||
.bell {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,23 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="m-screenful">
|
<div class="m-screenful">
|
||||||
<el-tooltip effect="dark" content="全屏" placement="bottom">
|
<el-tooltip effect="dark" content="全屏" placement="bottom">
|
||||||
<svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="toggle"
|
<svg-icon :icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'" class-name="header-icon" @click="toggle" />
|
||||||
className="header-icon"
|
|
||||||
/>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useFullscreen } from "@vueuse/core";
|
import { useFullscreen } from '@vueuse/core'
|
||||||
const { toggle, isFullscreen } = useFullscreen();
|
const { toggle, isFullscreen } = useFullscreen()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.m-screenful {
|
.m-screenful {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,42 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="m-setting">
|
<div class="m-setting">
|
||||||
<el-tooltip effect="dark" content="主题设置" placement="bottom">
|
<el-tooltip effect="dark" content="主题设置" placement="bottom">
|
||||||
<el-icon style="font-size: 20px;" class="bell header-icon"><Setting @click="changeSwitch('showSetting',true)"/></el-icon>
|
<el-icon style="font-size: 20px" class="bell header-icon"><Setting @click="changeSwitch('showSetting', true)" /></el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
const changeSwitch = (key,val) => {
|
const changeSwitch = (key, val) => {
|
||||||
SettingStore.setThemeConfig({key, val})
|
SettingStore.setThemeConfig({ key, val })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.m-setting {
|
.m-setting {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s;
|
|
||||||
.item-info-pop {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
.item-info-pop {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.bell {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
.item-child {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.bell{
|
.transverseMenu {
|
||||||
color: black;
|
.bell {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.item-child {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.transverseMenu {
|
|
||||||
.bell {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<el-dropdown trigger="hover" @command="setAssemblySize">
|
<el-dropdown trigger="hover" @command="setAssemblySize">
|
||||||
<svg-icon class-name="size-icon header-icon" icon-class="size" style="font-size: 20px;cursor: pointer"/>
|
<svg-icon class-name="size-icon header-icon" icon-class="size" style="font-size: 20px; cursor: pointer" />
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item v-for="item in assemblySizeList" :key="item" :disabled="globalComSize === item" :command="item">
|
<el-dropdown-item v-for="item in assemblySizeList" :key="item" :disabled="globalComSize === item" :command="item">
|
||||||
|
|
@ -12,30 +12,30 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, computed } from "vue";
|
import { reactive, computed } from 'vue'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
|
|
||||||
const globalComSize = computed(():string=>SettingStore.themeConfig.globalComSize)
|
const globalComSize = computed((): string => SettingStore.themeConfig.globalComSize)
|
||||||
|
|
||||||
const assemblySizeListCh = reactive<{ [key: string]: any }>({
|
const assemblySizeListCh = reactive<{ [key: string]: any }>({
|
||||||
default: "默认",
|
default: '默认',
|
||||||
large: "大型",
|
large: '大型',
|
||||||
small: "小型"
|
small: '小型',
|
||||||
});
|
})
|
||||||
|
|
||||||
const assemblySizeList = reactive<string[]>(["default", "large", "small"]);
|
const assemblySizeList = reactive<string[]>(['default', 'large', 'small'])
|
||||||
|
|
||||||
const setAssemblySize = (item: string) => {
|
const setAssemblySize = (item: string) => {
|
||||||
if (globalComSize.value === item) return;
|
if (globalComSize.value === item) return
|
||||||
SettingStore.setThemeConfig({key:'globalComSize', val:item})
|
SettingStore.setThemeConfig({ key: 'globalComSize', val: item })
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.transverseMenu {
|
.transverseMenu {
|
||||||
.size-icon {
|
.size-icon {
|
||||||
color: white;
|
color: white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<div class="app-main">
|
<div class="app-main">
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<transition name="fade-slide" mode="out-in" appear>
|
<transition name="fade-slide" mode="out-in" appear>
|
||||||
<keep-alive :include="cacheRoutes" v-if="isReload">
|
<keep-alive v-if="isReload" :include="cacheRoutes">
|
||||||
<component :is="useWrapComponents(Component, route)" :key="route.path" />
|
<component :is="useWrapComponents(Component, route)" :key="route.path" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,20 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {computed} from "vue";
|
import { computed } from 'vue'
|
||||||
import { useResizeHandler } from '@/hooks/useResizeHandler'
|
import { useResizeHandler } from '@/hooks/useResizeHandler'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
|
|
||||||
let { device } = useResizeHandler()
|
let { device } = useResizeHandler()
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
|
|
||||||
// 是否折叠
|
// 是否折叠
|
||||||
const isCollapse = computed(() => !SettingStore.isCollapse)
|
const isCollapse = computed(() => !SettingStore.isCollapse)
|
||||||
|
|
||||||
// 移动端点击
|
// 移动端点击
|
||||||
const handleClickOutside = () => {
|
const handleClickOutside = () => {
|
||||||
SettingStore.closeSideBar({ withoutAnimation: false })
|
SettingStore.closeSideBar({ withoutAnimation: false })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
<div class="sidebar-logo-container">
|
<div class="sidebar-logo-container">
|
||||||
<transition name="sidebarLogoFadeCl">
|
<transition name="sidebarLogoFadeCl">
|
||||||
<router-link v-if="isCollapse" key="collapse" class="sidebar-logo-link" to="/">
|
<router-link v-if="isCollapse" key="collapse" class="sidebar-logo-link" to="/">
|
||||||
<img src="@/assets/image/logo.png" class="sidebar-logo">
|
<img src="@/assets/image/logo.png" class="sidebar-logo" />
|
||||||
</router-link>
|
</router-link>
|
||||||
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
||||||
<img src="@/assets/image/logo.png" class="sidebar-logo">
|
<img src="@/assets/image/logo.png" class="sidebar-logo" />
|
||||||
<h1 class="sidebar-title">Vue Admin Perfect</h1>
|
<h1 class="sidebar-title">Vue Admin Perfect</h1>
|
||||||
</router-link>
|
</router-link>
|
||||||
</transition>
|
</transition>
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
defineProps<{ isCollapse: boolean }>();
|
defineProps<{ isCollapse: boolean }>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
@ -41,7 +41,6 @@ defineProps<{ isCollapse: boolean }>();
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
||||||
}
|
}
|
||||||
& .sidebar-title {
|
& .sidebar-title {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="sidebar-container" :class="{ 'has-logo': themeConfig.showLogo }">
|
<div class="sidebar-container" :class="{ 'has-logo': themeConfig.showLogo }">
|
||||||
<Logo :isCollapse="isCollapse" v-if="themeConfig.showLogo" />
|
<Logo v-if="themeConfig.showLogo" :is-collapse="isCollapse" />
|
||||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||||
<el-menu
|
<el-menu
|
||||||
:default-active="activeMenu"
|
:default-active="activeMenu"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<el-menu-item
|
<el-menu-item :index="subItem.path" @click="handleClickMenu(subItem)">
|
||||||
:index="subItem.path"
|
|
||||||
@click="handleClickMenu(subItem)">
|
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<component :is="subItem?.meta?.icon"></component>
|
<component :is="subItem?.meta?.icon"></component>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
|
|
@ -12,24 +10,24 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from 'vue'
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from 'vue-router'
|
||||||
import { isExternal } from "@/utils/validate";
|
import { isExternal } from '@/utils/validate'
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
let props = defineProps({
|
let props = defineProps({
|
||||||
menuList:{
|
menuList: {
|
||||||
type:Array,
|
type: Array,
|
||||||
default:()=>[]
|
default: () => [],
|
||||||
},
|
},
|
||||||
subItem:{
|
subItem: {
|
||||||
type:Object,
|
type: Object,
|
||||||
default:()=>{}
|
default: () => {},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleClickMenu = (subItem) => {
|
const handleClickMenu = (subItem) => {
|
||||||
if (isExternal(subItem.path)) return window.open(subItem.path, "_blank");
|
if (isExternal(subItem.path)) return window.open(subItem.path, '_blank')
|
||||||
router.push(subItem.path);
|
router.push(subItem.path)
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -10,70 +10,65 @@
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</app-link>
|
</app-link>
|
||||||
</template>
|
</template>
|
||||||
<el-sub-menu :index="item.path" v-else teleported >
|
<el-sub-menu v-else :index="item.path" teleported>
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon :size="20"> <component :is="item.meta?.icon"></component></el-icon>
|
<el-icon :size="20"> <component :is="item.meta?.icon"></component></el-icon>
|
||||||
<span>{{ item.meta && item.meta.title }}</span>
|
<span>{{ item.meta && item.meta.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
<sub-item
|
<sub-item v-for="child in item.children" :key="child.path" :item="child" />
|
||||||
v-for="child in item.children"
|
|
||||||
:key="child.path"
|
|
||||||
:item="child"
|
|
||||||
|
|
||||||
/>
|
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { isExternal } from '@/utils/validate.js'
|
import { isExternal } from '@/utils/validate.js'
|
||||||
import AppLink from './Link.vue'
|
import AppLink from './Link.vue'
|
||||||
import path from 'path-browserify'
|
import path from 'path-browserify'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
basePath: {
|
basePath: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
})
|
|
||||||
|
|
||||||
const onlyOneChild = ref(null)
|
|
||||||
const hasOneShowingChild = (children = [], parent) => {
|
|
||||||
const showingChildren = children.filter((item) => {
|
|
||||||
// 过滤掉需要隐藏的菜单
|
|
||||||
if (item.hidden) {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
// 临时设置(如果只有一个显示子项,则将使用)
|
|
||||||
onlyOneChild.value = item
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 当只有一个子路由器时,默认情况下会显示该子路由器
|
const onlyOneChild = ref(null)
|
||||||
if (showingChildren.length === 1) {
|
const hasOneShowingChild = (children = [], parent) => {
|
||||||
return true
|
const showingChildren = children.filter((item) => {
|
||||||
}
|
// 过滤掉需要隐藏的菜单
|
||||||
// 如果没有要显示的子路由器,则显示父路由器
|
if (item.hidden) {
|
||||||
if (showingChildren.length === 0) {
|
return false
|
||||||
onlyOneChild.value = { ...parent, noShowingChildren: true }
|
} else {
|
||||||
return true
|
// 临时设置(如果只有一个显示子项,则将使用)
|
||||||
|
onlyOneChild.value = item
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 当只有一个子路由器时,默认情况下会显示该子路由器
|
||||||
|
if (showingChildren.length === 1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 如果没有要显示的子路由器,则显示父路由器
|
||||||
|
if (showingChildren.length === 0) {
|
||||||
|
onlyOneChild.value = { ...parent, noShowingChildren: true }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
const resolvePath = (routePath) => {
|
||||||
}
|
if (isExternal(routePath)) {
|
||||||
|
return routePath
|
||||||
const resolvePath = (routePath) => {
|
}
|
||||||
if (isExternal(routePath)) {
|
if (isExternal(props.basePath)) {
|
||||||
return routePath
|
return props.basePath
|
||||||
|
}
|
||||||
|
return path.resolve(props.basePath, routePath)
|
||||||
}
|
}
|
||||||
if (isExternal(props.basePath)) {
|
|
||||||
return props.basePath
|
|
||||||
}
|
|
||||||
return path.resolve(props.basePath, routePath)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<template v-for="subItem in menuList" :key="subItem.path">
|
<template v-for="subItem in menuList" :key="subItem.path">
|
||||||
<template v-if="!subItem.hidden">
|
<template v-if="!subItem.hidden">
|
||||||
<template v-if="!subItem.alwaysShow&&hasOneChild(subItem.children, subItem)">
|
<template v-if="!subItem.alwaysShow && hasOneChild(subItem.children, subItem)">
|
||||||
<MenuItem
|
<MenuItem :sub-item="hasOneChild(subItem.children, subItem)" />
|
||||||
:subItem="hasOneChild(subItem.children, subItem)"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<el-sub-menu v-else :index="subItem.path">
|
<el-sub-menu v-else :index="subItem.path">
|
||||||
<template #title>
|
<template #title>
|
||||||
|
|
@ -13,42 +11,41 @@
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<span>{{ subItem?.meta?.title }}</span>
|
<span>{{ subItem?.meta?.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
<SubMenu :menuList="subItem.children" />
|
<SubMenu :menu-list="subItem.children" />
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue";
|
import { ref } from 'vue'
|
||||||
import MenuItem from './MenuItem.vue'
|
import MenuItem from './MenuItem.vue'
|
||||||
|
|
||||||
let props = defineProps({
|
let props = defineProps({
|
||||||
menuList:{
|
menuList: {
|
||||||
type:Array,
|
type: Array,
|
||||||
default:()=>[]
|
default: () => [],
|
||||||
},
|
},
|
||||||
})
|
|
||||||
|
|
||||||
const hasOneChild = (children = [], parent) => {
|
|
||||||
const showingChildren = children.filter((item) => {
|
|
||||||
// 过滤掉需要隐藏的菜单
|
|
||||||
if (item.hidden) {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
// 当只有一个子路由器时,默认情况下会显示该子路由器
|
|
||||||
if (showingChildren.length === 1) {
|
|
||||||
// (如果只有一个显示子项,则将使用)
|
|
||||||
return showingChildren[0]
|
|
||||||
}
|
|
||||||
// 如果没有要显示的子路由器,则显示父路由器
|
|
||||||
if (showingChildren.length === 0) {
|
|
||||||
return parent
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const hasOneChild = (children = [], parent) => {
|
||||||
|
const showingChildren = children.filter((item) => {
|
||||||
|
// 过滤掉需要隐藏的菜单
|
||||||
|
if (item.hidden) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 当只有一个子路由器时,默认情况下会显示该子路由器
|
||||||
|
if (showingChildren.length === 1) {
|
||||||
|
// (如果只有一个显示子项,则将使用)
|
||||||
|
return showingChildren[0]
|
||||||
|
}
|
||||||
|
// 如果没有要显示的子路由器,则显示父路由器
|
||||||
|
if (showingChildren.length === 0) {
|
||||||
|
return parent
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -6,51 +6,58 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item @click="refresh"><el-icon :size="14"><Refresh /></el-icon> 刷新当页</el-dropdown-item>
|
<el-dropdown-item @click="refresh"
|
||||||
<el-dropdown-item @click="closeCurrentTab"><el-icon :size="14"><FolderRemove/></el-icon> 关闭当前</el-dropdown-item>
|
><el-icon :size="14"><Refresh /></el-icon> 刷新当页</el-dropdown-item
|
||||||
<el-dropdown-item @click="closeOtherTab"><el-icon :size="14"><Close /></el-icon>关闭其他</el-dropdown-item>
|
>
|
||||||
<el-dropdown-item @click="closeAllTab"><el-icon :size="14"><FolderDelete /></el-icon>关闭所有</el-dropdown-item>
|
<el-dropdown-item @click="closeCurrentTab"
|
||||||
|
><el-icon :size="14"><FolderRemove /></el-icon> 关闭当前</el-dropdown-item
|
||||||
|
>
|
||||||
|
<el-dropdown-item @click="closeOtherTab"
|
||||||
|
><el-icon :size="14"><Close /></el-icon>关闭其他</el-dropdown-item
|
||||||
|
>
|
||||||
|
<el-dropdown-item @click="closeAllTab"
|
||||||
|
><el-icon :size="14"><FolderDelete /></el-icon>关闭所有</el-dropdown-item
|
||||||
|
>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {computed} from "vue";
|
import { computed } from 'vue'
|
||||||
import {useSettingStore} from "@/store/modules/setting"
|
import { useSettingStore } from '@/store/modules/setting'
|
||||||
import {useTagsViewStore} from "@/store/modules/tagsView"
|
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||||
import { useRouter,useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const SettingStore = useSettingStore()
|
const SettingStore = useSettingStore()
|
||||||
const TagsViewStore = useTagsViewStore()
|
const TagsViewStore = useTagsViewStore()
|
||||||
const visitedViews = computed(() => TagsViewStore.visitedViews)
|
const visitedViews = computed(() => TagsViewStore.visitedViews)
|
||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
SettingStore.setReload()
|
SettingStore.setReload()
|
||||||
}
|
}
|
||||||
// 关闭当前
|
// 关闭当前
|
||||||
const closeCurrentTab = (event)=>{
|
const closeCurrentTab = (event) => {
|
||||||
TagsViewStore.toLastView(route.path)
|
TagsViewStore.toLastView(route.path)
|
||||||
TagsViewStore.delView(route.path)
|
TagsViewStore.delView(route.path)
|
||||||
|
}
|
||||||
|
// 关闭其他
|
||||||
|
const closeOtherTab = async () => {
|
||||||
|
TagsViewStore.delOtherViews(route.path)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
// 关闭所有 去首页
|
||||||
// 关闭其他
|
const closeAllTab = async () => {
|
||||||
const closeOtherTab= async ()=>{
|
await TagsViewStore.delAllViews()
|
||||||
TagsViewStore.delOtherViews(route.path)
|
TagsViewStore.goHome()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭所有 去首页
|
|
||||||
const closeAllTab = async ()=>{
|
|
||||||
await TagsViewStore.delAllViews()
|
|
||||||
TagsViewStore.goHome()
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.more{
|
.more {
|
||||||
background-color: $primaryColor;
|
background-color: $primaryColor;
|
||||||
color: white;
|
color: white;
|
||||||
.tags-view-item{
|
.tags-view-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="m-tags-view">
|
<div class="m-tags-view">
|
||||||
<div class="tags-view">
|
<div class="tags-view">
|
||||||
<el-tabs
|
<el-tabs v-model="activeTabsValue" type="card" @tab-click="tabClick" @tab-remove="removeTab">
|
||||||
v-model="activeTabsValue"
|
|
||||||
type="card"
|
|
||||||
@tab-click="tabClick"
|
|
||||||
@tab-remove="removeTab"
|
|
||||||
>
|
|
||||||
<el-tab-pane
|
<el-tab-pane
|
||||||
v-for="item in visitedViews"
|
v-for="item in visitedViews"
|
||||||
:key="item.path"
|
:key="item.path"
|
||||||
:path="item.path"
|
:path="item.path"
|
||||||
:label="item.title"
|
:label="item.title"
|
||||||
:name="item.path"
|
:name="item.path"
|
||||||
:closable="!(item.meta&&item.meta.affix)"
|
:closable="!(item.meta && item.meta.affix)"
|
||||||
>
|
>
|
||||||
<template #label>
|
<template #label>
|
||||||
<el-icon class="tabs-icon" v-if="item.icon">
|
<el-icon v-if="item.icon" class="tabs-icon">
|
||||||
<component :is="item.icon"></component>
|
<component :is="item.icon"></component>
|
||||||
</el-icon>
|
</el-icon>
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
|
|
@ -25,143 +20,143 @@
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
<div class="right-btn">
|
<div class="right-btn">
|
||||||
<MoreButton/>
|
<MoreButton />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {computed, watch, ref, onMounted} from "vue";
|
import { computed, watch, ref, onMounted } from 'vue'
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { TabsPaneContext } from "element-plus";
|
import { TabsPaneContext } from 'element-plus'
|
||||||
import MoreButton from './components/MoreButton'
|
import MoreButton from './components/MoreButton'
|
||||||
import path from 'path-browserify'
|
import path from 'path-browserify'
|
||||||
import {useTagsViewStore} from "@/store/modules/tagsView"
|
import { useTagsViewStore } from '@/store/modules/tagsView'
|
||||||
import {usePermissionStore} from "@/store/modules/permission"
|
import { usePermissionStore } from '@/store/modules/permission'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const TagsViewStore = useTagsViewStore()
|
const TagsViewStore = useTagsViewStore()
|
||||||
const PermissionStore = usePermissionStore()
|
const PermissionStore = usePermissionStore()
|
||||||
const visitedViews = computed(() => TagsViewStore.visitedViews)
|
const visitedViews = computed(() => TagsViewStore.visitedViews)
|
||||||
const routes = computed(() => PermissionStore.routes)
|
const routes = computed(() => PermissionStore.routes)
|
||||||
|
|
||||||
const addTags = () => {
|
const addTags = () => {
|
||||||
const { name } = route
|
const { name } = route
|
||||||
if (name === 'Login') {
|
if (name === 'Login') {
|
||||||
return
|
return
|
||||||
}
|
|
||||||
if (name) {
|
|
||||||
TagsViewStore.addView(route)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
let affixTags = ref([])
|
|
||||||
function filterAffixTags(routes, basePath = '/') {
|
|
||||||
let tags = []
|
|
||||||
routes.forEach((route) => {
|
|
||||||
if (route.meta && route.meta.affix) {
|
|
||||||
const tagPath = path.resolve(basePath, route.path)
|
|
||||||
tags.push({
|
|
||||||
fullPath: tagPath,
|
|
||||||
path: tagPath,
|
|
||||||
name: route.name,
|
|
||||||
meta: { ...route.meta },
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if (route.children) {
|
if (name) {
|
||||||
const tempTags = filterAffixTags(route.children, route.path)
|
TagsViewStore.addView(route)
|
||||||
if (tempTags.length >= 1) {
|
}
|
||||||
tags = [...tags, ...tempTags]
|
return false
|
||||||
|
}
|
||||||
|
let affixTags = ref([])
|
||||||
|
function filterAffixTags(routes, basePath = '/') {
|
||||||
|
let tags = []
|
||||||
|
routes.forEach((route) => {
|
||||||
|
if (route.meta && route.meta.affix) {
|
||||||
|
const tagPath = path.resolve(basePath, route.path)
|
||||||
|
tags.push({
|
||||||
|
fullPath: tagPath,
|
||||||
|
path: tagPath,
|
||||||
|
name: route.name,
|
||||||
|
meta: { ...route.meta },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (route.children) {
|
||||||
|
const tempTags = filterAffixTags(route.children, route.path)
|
||||||
|
if (tempTags.length >= 1) {
|
||||||
|
tags = [...tags, ...tempTags]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return tags
|
||||||
|
}
|
||||||
|
const initTags = () => {
|
||||||
|
let routesNew = routes.value
|
||||||
|
let affixTag = (affixTags.value = filterAffixTags(routesNew))
|
||||||
|
for (const tag of affixTag) {
|
||||||
|
if (tag.name) {
|
||||||
|
TagsViewStore.addVisitedView(tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
initTags()
|
||||||
|
addTags()
|
||||||
})
|
})
|
||||||
return tags
|
watch(route, () => {
|
||||||
}
|
addTags()
|
||||||
const initTags = () => {
|
})
|
||||||
let routesNew = routes.value
|
let tabIndex = 2
|
||||||
let affixTag = (affixTags.value = filterAffixTags(routesNew))
|
const activeTabsValue = computed({
|
||||||
for (const tag of affixTag) {
|
get: () => {
|
||||||
if (tag.name) {
|
return TagsViewStore.activeTabsValue
|
||||||
TagsViewStore.addVisitedView(tag)
|
},
|
||||||
}
|
set: (val) => {
|
||||||
|
TagsViewStore.setTabsMenuValue(val)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
function toLastView(activeTabPath) {
|
||||||
|
let index = visitedViews.value.findIndex((item) => item.path === activeTabPath)
|
||||||
|
const nextTab = visitedViews.value[index + 1] || visitedViews.value[index - 1]
|
||||||
|
if (!nextTab) return
|
||||||
|
router.push(nextTab.path)
|
||||||
|
TagsViewStore.addVisitedView(nextTab)
|
||||||
}
|
}
|
||||||
}
|
const tabClick = (tabItem: TabsPaneContext) => {
|
||||||
onMounted(()=>{
|
let path = tabItem.props.name as string
|
||||||
initTags()
|
router.push(path)
|
||||||
addTags()
|
|
||||||
})
|
|
||||||
watch(route, () => {
|
|
||||||
addTags()
|
|
||||||
})
|
|
||||||
let tabIndex = 2
|
|
||||||
const activeTabsValue = computed({
|
|
||||||
get: () => {
|
|
||||||
return TagsViewStore.activeTabsValue;
|
|
||||||
},
|
|
||||||
set: val => {
|
|
||||||
TagsViewStore.setTabsMenuValue(val);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
function toLastView(activeTabPath) {
|
|
||||||
let index = visitedViews.value.findIndex(item=>item.path===activeTabPath)
|
|
||||||
const nextTab = visitedViews.value[index + 1] || visitedViews.value[index - 1];
|
|
||||||
if (!nextTab) return;
|
|
||||||
router.push(nextTab.path);
|
|
||||||
TagsViewStore.addVisitedView(nextTab)
|
|
||||||
}
|
|
||||||
const tabClick = (tabItem: TabsPaneContext) => {
|
|
||||||
let path = tabItem.props.name as string;
|
|
||||||
router.push(path);
|
|
||||||
};
|
|
||||||
|
|
||||||
const isActive = (path) => {
|
const isActive = (path) => {
|
||||||
return path === route.path
|
return path === route.path
|
||||||
}
|
}
|
||||||
const removeTab = async (activeTabPath: string) => {
|
const removeTab = async (activeTabPath: string) => {
|
||||||
if (isActive(activeTabPath)) {
|
if (isActive(activeTabPath)) {
|
||||||
toLastView(activeTabPath)
|
toLastView(activeTabPath)
|
||||||
|
}
|
||||||
|
await TagsViewStore.delView(activeTabPath)
|
||||||
}
|
}
|
||||||
await TagsViewStore.delView(activeTabPath)
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.m-tags-view{
|
.m-tags-view {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
background: white;
|
background: white;
|
||||||
.right-btn{
|
.right-btn {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
.tags-view {
|
||||||
.tags-view {
|
flex: 1;
|
||||||
flex: 1;
|
overflow: hidden;
|
||||||
overflow: hidden;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tags-view{
|
|
||||||
.el-tabs--card :deep(.el-tabs__header){
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 40px;
|
|
||||||
padding: 0 10px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
:deep(.el-tabs){
|
|
||||||
.el-tabs__nav {
|
.tags-view {
|
||||||
border: none;
|
.el-tabs--card :deep(.el-tabs__header) {
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
.el-tabs__header .el-tabs__item {
|
:deep(.el-tabs) {
|
||||||
border: none;
|
.el-tabs__nav {
|
||||||
color: #cccccc;
|
border: none;
|
||||||
}
|
}
|
||||||
.el-tabs__header .el-tabs__item.is-active {
|
.el-tabs__header .el-tabs__item {
|
||||||
color: $primaryColor;
|
border: none;
|
||||||
border-bottom:2px solid $primaryColor;
|
color: #cccccc;
|
||||||
|
}
|
||||||
|
.el-tabs__header .el-tabs__item.is-active {
|
||||||
|
color: $primaryColor;
|
||||||
|
border-bottom: 2px solid $primaryColor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
16
src/main.ts
16
src/main.ts
|
|
@ -1,32 +1,32 @@
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './routers'
|
import router from './routers'
|
||||||
import pinia from "./store";
|
import pinia from './store'
|
||||||
|
|
||||||
import {registerElIcons} from "@/plugins/ElIcons"
|
import { registerElIcons } from '@/plugins/ElIcons'
|
||||||
// 引入全局组件布局
|
// 引入全局组件布局
|
||||||
import PageWrapLayout from '@/components/PageWrapLayout/index.vue'
|
import PageWrapLayout from '@/components/PageWrapLayout/index.vue'
|
||||||
// 权限路由
|
// 权限路由
|
||||||
import './permission'
|
import './permission'
|
||||||
// svg-icons注册导入
|
// svg-icons注册导入
|
||||||
import 'virtual:svg-icons-register'
|
import 'virtual:svg-icons-register'
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue'// svg component
|
import SvgIcon from '@/components/SvgIcon/index.vue' // svg component
|
||||||
// UI框架 element-plus
|
// UI框架 element-plus
|
||||||
import ElementPlus from 'element-plus'
|
import ElementPlus from 'element-plus'
|
||||||
import 'element-plus/dist/index.css'
|
import 'element-plus/dist/index.css'
|
||||||
// 引入暗黑模式 element-plus 2.2 内置暗黑模式
|
// 引入暗黑模式 element-plus 2.2 内置暗黑模式
|
||||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||||
// 自定义暗黑模式
|
// 自定义暗黑模式
|
||||||
import "@/styles/element-dark.scss";
|
import '@/styles/element-dark.scss'
|
||||||
// 引入阿里图标库
|
// 引入阿里图标库
|
||||||
import "@/assets/iconfont/iconfont.css";
|
import '@/assets/iconfont/iconfont.css'
|
||||||
import "@/assets/iconfont/iconfont.js";
|
import '@/assets/iconfont/iconfont.js'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
registerElIcons(app)
|
registerElIcons(app)
|
||||||
|
|
||||||
app.component('svg-icon',SvgIcon)
|
app.component('SvgIcon', SvgIcon)
|
||||||
app.component('PageWrapLayout',PageWrapLayout)
|
app.component('PageWrapLayout', PageWrapLayout)
|
||||||
|
|
||||||
app.use(pinia)
|
app.use(pinia)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
|
|
||||||
|
|
@ -1,476 +1,487 @@
|
||||||
export const userData =[
|
export const userData = [
|
||||||
{
|
{
|
||||||
username:'zzb',
|
username: 'zzb',
|
||||||
nickname:'林峰',
|
nickname: '林峰',
|
||||||
sex:'男',
|
sex: '男',
|
||||||
role:'超级管理员',
|
role: '超级管理员',
|
||||||
status:true,
|
status: true,
|
||||||
photo:'15333333333',
|
photo: '15333333333',
|
||||||
describe:'超级管理员不可删除',
|
describe: '超级管理员不可删除',
|
||||||
createTime:'2022-09-02 15:30:20',
|
createTime: '2022-09-02 15:30:20',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
username:'zhangsan',
|
username: 'zhangsan',
|
||||||
nickname:'张三',
|
nickname: '张三',
|
||||||
sex:'女',
|
sex: '女',
|
||||||
role:'管理员',
|
role: '管理员',
|
||||||
status:true,
|
status: true,
|
||||||
photo:'15311111111',
|
photo: '15311111111',
|
||||||
describe:'管理员不可删除',
|
describe: '管理员不可删除',
|
||||||
createTime:'2022-09-02 15:30:20',
|
createTime: '2022-09-02 15:30:20',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
username:'lisi',
|
username: 'lisi',
|
||||||
nickname:'李四',
|
nickname: '李四',
|
||||||
sex:'男',
|
sex: '男',
|
||||||
role:'管理员',
|
role: '管理员',
|
||||||
status:true,
|
status: true,
|
||||||
photo:'13823456789',
|
photo: '13823456789',
|
||||||
describe:'测试账户',
|
describe: '测试账户',
|
||||||
createTime:'2022-09-02 15:30:20',
|
createTime: '2022-09-02 15:30:20',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
username:'wangwu',
|
username: 'wangwu',
|
||||||
nickname:'王五',
|
nickname: '王五',
|
||||||
sex:'男',
|
sex: '男',
|
||||||
role:'超级管理员',
|
role: '超级管理员',
|
||||||
status:false,
|
status: false,
|
||||||
photo:'13923456789',
|
photo: '13923456789',
|
||||||
describe:'超级管理员不可删除',
|
describe: '超级管理员不可删除',
|
||||||
createTime:'2022-09-02 15:30:20',
|
createTime: '2022-09-02 15:30:20',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
username:'zhaoliu',
|
username: 'zhaoliu',
|
||||||
nickname:'赵柳',
|
nickname: '赵柳',
|
||||||
sex:'男',
|
sex: '男',
|
||||||
role:'普通用户',
|
role: '普通用户',
|
||||||
status:false,
|
status: false,
|
||||||
photo:'14523456789',
|
photo: '14523456789',
|
||||||
describe:'普通测试用户',
|
describe: '普通测试用户',
|
||||||
createTime:'2022-09-02 15:30:20',
|
createTime: '2022-09-02 15:30:20',
|
||||||
},
|
},
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const deptData = [
|
||||||
export const deptData =[
|
{
|
||||||
{
|
id: '0',
|
||||||
"id": "0",
|
deptName: '华东分部',
|
||||||
"deptName": "华东分部",
|
orderNo: 1,
|
||||||
"orderNo": 1,
|
createTime: '2011-02-25 18:37:39',
|
||||||
"createTime": "2011-02-25 18:37:39",
|
remark: '世上无难事,只要肯登攀',
|
||||||
"remark": "世上无难事,只要肯登攀",
|
status: false,
|
||||||
"status": false,
|
children: [
|
||||||
"children": [{
|
{
|
||||||
"id": "0-0",
|
id: '0-0',
|
||||||
"deptName": "研发部",
|
deptName: '研发部',
|
||||||
"orderNo": 1,
|
orderNo: 1,
|
||||||
"createTime": "1995-10-07 03:22:40",
|
createTime: '1995-10-07 03:22:40',
|
||||||
"remark": "不曾扬帆,何以至远方",
|
remark: '不曾扬帆,何以至远方',
|
||||||
"status": true,
|
status: true,
|
||||||
"parentDept": "0"
|
parentDept: '0',
|
||||||
}, {
|
},
|
||||||
"id": "0-1",
|
{
|
||||||
"deptName": "市场部",
|
id: '0-1',
|
||||||
"orderNo": 2,
|
deptName: '市场部',
|
||||||
"createTime": "1972-06-20 09:33:40",
|
orderNo: 2,
|
||||||
"remark": "努力到无能为力,拼搏到感动自己",
|
createTime: '1972-06-20 09:33:40',
|
||||||
"status": false,
|
remark: '努力到无能为力,拼搏到感动自己',
|
||||||
"parentDept": "0"
|
status: false,
|
||||||
}, {
|
parentDept: '0',
|
||||||
"id": "0-2",
|
},
|
||||||
"deptName": "商务部",
|
{
|
||||||
"orderNo": 3,
|
id: '0-2',
|
||||||
"createTime": "1992-10-31 02:54:45",
|
deptName: '商务部',
|
||||||
"remark": "没有过不了的坎,就怕自己不奋斗",
|
orderNo: 3,
|
||||||
"status": false,
|
createTime: '1992-10-31 02:54:45',
|
||||||
"parentDept": "0"
|
remark: '没有过不了的坎,就怕自己不奋斗',
|
||||||
}, {
|
status: false,
|
||||||
"id": "0-3",
|
parentDept: '0',
|
||||||
"deptName": "财务部",
|
},
|
||||||
"orderNo": 4,
|
{
|
||||||
"createTime": "1971-07-06 13:01:49",
|
id: '0-3',
|
||||||
"remark": "没有口水与汗水,就没有成功的泪水。",
|
deptName: '财务部',
|
||||||
"status": true,
|
orderNo: 4,
|
||||||
"parentDept": "0"
|
createTime: '1971-07-06 13:01:49',
|
||||||
}]
|
remark: '没有口水与汗水,就没有成功的泪水。',
|
||||||
}, {
|
status: true,
|
||||||
"id": "1",
|
parentDept: '0',
|
||||||
"deptName": "华南分部",
|
},
|
||||||
"orderNo": 2,
|
],
|
||||||
"createTime": "1995-12-24 06:36:26",
|
},
|
||||||
"remark": "这个世界从来不缺乏机遇,而是缺少抓住机遇的手。",
|
{
|
||||||
"status": false,
|
id: '1',
|
||||||
"children": [{
|
deptName: '华南分部',
|
||||||
"id": "1-0",
|
orderNo: 2,
|
||||||
"deptName": "研发部",
|
createTime: '1995-12-24 06:36:26',
|
||||||
"orderNo": 1,
|
remark: '这个世界从来不缺乏机遇,而是缺少抓住机遇的手。',
|
||||||
"createTime": "2022-05-10 12:44:05",
|
status: false,
|
||||||
"remark": "奋斗令我们的生活充满生机,责任让我们的生命充满意义!",
|
children: [
|
||||||
"status": true,
|
{
|
||||||
"parentDept": "1"
|
id: '1-0',
|
||||||
}, {
|
deptName: '研发部',
|
||||||
"id": "1-1",
|
orderNo: 1,
|
||||||
"deptName": "市场部",
|
createTime: '2022-05-10 12:44:05',
|
||||||
"orderNo": 2,
|
remark: '奋斗令我们的生活充满生机,责任让我们的生命充满意义!',
|
||||||
"createTime": "2022-07-15 02:53:29",
|
status: true,
|
||||||
"remark": "学习之心不可无,懒惰之心不可有。",
|
parentDept: '1',
|
||||||
"status": true,
|
},
|
||||||
"parentDept": "1"
|
{
|
||||||
},
|
id: '1-1',
|
||||||
{
|
deptName: '市场部',
|
||||||
"id": "1-2",
|
orderNo: 2,
|
||||||
"deptName": "商务部",
|
createTime: '2022-07-15 02:53:29',
|
||||||
"orderNo": 3,
|
remark: '学习之心不可无,懒惰之心不可有。',
|
||||||
"createTime": "2022-08-11 22:44:55",
|
status: true,
|
||||||
"remark": "学会等待,学会坚持,成功是一个循序渐进的过程。",
|
parentDept: '1',
|
||||||
"status": true,
|
},
|
||||||
"parentDept": "1"
|
{
|
||||||
}, {
|
id: '1-2',
|
||||||
"id": "1-3",
|
deptName: '商务部',
|
||||||
"deptName": "财务部",
|
orderNo: 3,
|
||||||
"orderNo": 4,
|
createTime: '2022-08-11 22:44:55',
|
||||||
"createTime": "2022-10-26 19:38:29",
|
remark: '学会等待,学会坚持,成功是一个循序渐进的过程。',
|
||||||
"remark": "能克服困难的人,可使困难化为良机",
|
status: true,
|
||||||
"status": false,
|
parentDept: '1',
|
||||||
"parentDept": "1"
|
},
|
||||||
}
|
{
|
||||||
]
|
id: '1-3',
|
||||||
}, {
|
deptName: '财务部',
|
||||||
"id": "2",
|
orderNo: 4,
|
||||||
"deptName": "西北分部",
|
createTime: '2022-10-26 19:38:29',
|
||||||
"orderNo": 3,
|
remark: '能克服困难的人,可使困难化为良机',
|
||||||
"createTime": "2022-08-27 16:49:21",
|
status: false,
|
||||||
"remark": "行为决定性格,性格决定命运",
|
parentDept: '1',
|
||||||
"status": false,
|
},
|
||||||
"children": [{
|
],
|
||||||
"id": "2-0",
|
},
|
||||||
"deptName": "研发部",
|
{
|
||||||
"orderNo": 1,
|
id: '2',
|
||||||
"createTime": "2022-12-11 03:49:33",
|
deptName: '西北分部',
|
||||||
"remark": "带着自己的梦,以一种骄傲的姿态走下去",
|
orderNo: 3,
|
||||||
"status": false,
|
createTime: '2022-08-27 16:49:21',
|
||||||
"parentDept": "2"
|
remark: '行为决定性格,性格决定命运',
|
||||||
}, {
|
status: false,
|
||||||
"id": "2-1",
|
children: [
|
||||||
"deptName": "市场部",
|
{
|
||||||
"orderNo": 2,
|
id: '2-0',
|
||||||
"createTime": "2022-06-18 20:15:34",
|
deptName: '研发部',
|
||||||
"remark": "当世界都在说放弃的时候,轻轻的告诉自己:再试一次",
|
orderNo: 1,
|
||||||
"status": true,
|
createTime: '2022-12-11 03:49:33',
|
||||||
"parentDept": "2"
|
remark: '带着自己的梦,以一种骄傲的姿态走下去',
|
||||||
}, {
|
status: false,
|
||||||
"id": "2-2",
|
parentDept: '2',
|
||||||
"deptName": "商务部",
|
},
|
||||||
"orderNo": 3,
|
{
|
||||||
"createTime": "2022-07-17 09:37:41",
|
id: '2-1',
|
||||||
"remark": "不怕万人阻挡在前方,只怕自己先行投降",
|
deptName: '市场部',
|
||||||
"status": true,
|
orderNo: 2,
|
||||||
"parentDept": "2"
|
createTime: '2022-06-18 20:15:34',
|
||||||
}, {
|
remark: '当世界都在说放弃的时候,轻轻的告诉自己:再试一次',
|
||||||
"id": "2-3",
|
status: true,
|
||||||
"deptName": "财务部",
|
parentDept: '2',
|
||||||
"orderNo": 4,
|
},
|
||||||
"createTime": "2022-11-23 04:34:33",
|
{
|
||||||
"remark": "胸怀临云志,莫负少年时",
|
id: '2-2',
|
||||||
"status": false,
|
deptName: '商务部',
|
||||||
"parentDept": "2"
|
orderNo: 3,
|
||||||
}]
|
createTime: '2022-07-17 09:37:41',
|
||||||
}]
|
remark: '不怕万人阻挡在前方,只怕自己先行投降',
|
||||||
|
status: true,
|
||||||
|
parentDept: '2',
|
||||||
export const roleData =[
|
},
|
||||||
{
|
{
|
||||||
roleName:'超级管理员',
|
id: '2-3',
|
||||||
roleId:'admin',
|
deptName: '财务部',
|
||||||
roleIdentification:'admin',
|
orderNo: 4,
|
||||||
describe:'这是超级管理员,拥有一切权限',
|
createTime: '2022-11-23 04:34:33',
|
||||||
createTime:'2022-09-02 15:30:20',
|
remark: '胸怀临云志,莫负少年时',
|
||||||
},
|
status: false,
|
||||||
{
|
parentDept: '2',
|
||||||
roleName:'管理员',
|
},
|
||||||
roleId:'role',
|
],
|
||||||
roleIdentification:'admin',
|
},
|
||||||
describe:'普通管理员',
|
|
||||||
createTime:'2022-09-02 15:30:20',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
roleName:'普通用户',
|
|
||||||
roleId:'other',
|
|
||||||
describe:'测试用户',
|
|
||||||
roleIdentification:'other',
|
|
||||||
createTime:'2022-09-02 15:30:20',
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const roleData = [
|
||||||
|
{
|
||||||
|
roleName: '超级管理员',
|
||||||
|
roleId: 'admin',
|
||||||
|
roleIdentification: 'admin',
|
||||||
|
describe: '这是超级管理员,拥有一切权限',
|
||||||
|
createTime: '2022-09-02 15:30:20',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
roleName: '管理员',
|
||||||
|
roleId: 'role',
|
||||||
|
roleIdentification: 'admin',
|
||||||
|
describe: '普通管理员',
|
||||||
|
createTime: '2022-09-02 15:30:20',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
roleName: '普通用户',
|
||||||
|
roleId: 'other',
|
||||||
|
describe: '测试用户',
|
||||||
|
roleIdentification: 'other',
|
||||||
|
createTime: '2022-09-02 15:30:20',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
export const menuData =[
|
export const menuData = [
|
||||||
{
|
{
|
||||||
menuName:'首页',
|
menuName: '首页',
|
||||||
menuType:'菜单',
|
menuType: '菜单',
|
||||||
menuRouter:'/home',
|
menuRouter: '/home',
|
||||||
identification:'menu:home',
|
identification: 'menu:home',
|
||||||
parentId:0,
|
parentId: 0,
|
||||||
level:1,
|
level: 1,
|
||||||
id:0,
|
id: 0,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
menuName:'表格',
|
menuName: '表格',
|
||||||
menuType:'目录',
|
menuType: '目录',
|
||||||
menuRouter:'/table',
|
menuRouter: '/table',
|
||||||
identification:'menu:table',
|
identification: 'menu:table',
|
||||||
parentId:0,
|
parentId: 0,
|
||||||
level:1,
|
level: 1,
|
||||||
id:1,
|
id: 1,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
children:[
|
children: [
|
||||||
{
|
{
|
||||||
menuName:'菜单1',
|
menuName: '菜单1',
|
||||||
menuType:'菜单',
|
menuType: '菜单',
|
||||||
menuRouter:'/table',
|
menuRouter: '/table',
|
||||||
identification:'menu1:view',
|
identification: 'menu1:view',
|
||||||
parentId:1,
|
parentId: 1,
|
||||||
level:2,
|
level: 2,
|
||||||
id:10,
|
id: 10,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
children:[
|
children: [
|
||||||
{
|
{
|
||||||
menuName:'按钮1',
|
menuName: '按钮1',
|
||||||
menuType:'按钮',
|
menuType: '按钮',
|
||||||
menuRouter:'/table',
|
menuRouter: '/table',
|
||||||
identification:'menu1:view:btn1',
|
identification: 'menu1:view:btn1',
|
||||||
parentId:10,
|
parentId: 10,
|
||||||
id:20,
|
id: 20,
|
||||||
level:3,
|
level: 3,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
menuName:'按钮2',
|
menuName: '按钮2',
|
||||||
menuType:'按钮',
|
menuType: '按钮',
|
||||||
menuRouter:'/table',
|
menuRouter: '/table',
|
||||||
identification:'menu1:view:btn2',
|
identification: 'menu1:view:btn2',
|
||||||
parentId:10,
|
parentId: 10,
|
||||||
id:21,
|
id: 21,
|
||||||
level:3,
|
level: 3,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
menuName:'按钮3',
|
menuName: '按钮3',
|
||||||
menuType:'按钮',
|
menuType: '按钮',
|
||||||
menuRouter:'/table',
|
menuRouter: '/table',
|
||||||
identification:'menu1:view:btn2',
|
identification: 'menu1:view:btn2',
|
||||||
parentId:10,
|
parentId: 10,
|
||||||
id:22,
|
id: 22,
|
||||||
level:3,
|
level: 3,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
menuName:'可视化图表',
|
menuName: '可视化图表',
|
||||||
menuType:'目录',
|
menuType: '目录',
|
||||||
menuRouter:'/charts',
|
menuRouter: '/charts',
|
||||||
identification:'menu:charts',
|
identification: 'menu:charts',
|
||||||
parentId:0,
|
parentId: 0,
|
||||||
level:1,
|
level: 1,
|
||||||
id:1,
|
id: 1,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
children:[
|
children: [
|
||||||
{
|
{
|
||||||
menuName:'菜单1',
|
menuName: '菜单1',
|
||||||
menuType:'菜单',
|
menuType: '菜单',
|
||||||
menuRouter:'/charts',
|
menuRouter: '/charts',
|
||||||
identification:'menu1:view',
|
identification: 'menu1:view',
|
||||||
parentId:1,
|
parentId: 1,
|
||||||
level:2,
|
level: 2,
|
||||||
id:10,
|
id: 10,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
children:[
|
children: [
|
||||||
{
|
{
|
||||||
menuName:'按钮1',
|
menuName: '按钮1',
|
||||||
menuType:'按钮',
|
menuType: '按钮',
|
||||||
menuRouter:'/charts',
|
menuRouter: '/charts',
|
||||||
identification:'menu1:view:btn1',
|
identification: 'menu1:view:btn1',
|
||||||
parentId:10,
|
parentId: 10,
|
||||||
id:20,
|
id: 20,
|
||||||
level:3,
|
level: 3,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
menuName:'按钮2',
|
menuName: '按钮2',
|
||||||
menuType:'按钮',
|
menuType: '按钮',
|
||||||
menuRouter:'/charts',
|
menuRouter: '/charts',
|
||||||
identification:'menu1:view:btn2',
|
identification: 'menu1:view:btn2',
|
||||||
parentId:10,
|
parentId: 10,
|
||||||
id:21,
|
id: 21,
|
||||||
level:3,
|
level: 3,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
menuName:'按钮3',
|
menuName: '按钮3',
|
||||||
menuType:'按钮',
|
menuType: '按钮',
|
||||||
menuRouter:'/charts',
|
menuRouter: '/charts',
|
||||||
identification:'menu1:view:btn2',
|
identification: 'menu1:view:btn2',
|
||||||
parentId:10,
|
parentId: 10,
|
||||||
id:22,
|
id: 22,
|
||||||
level:3,
|
level: 3,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
menuName:'基础组件',
|
menuName: '基础组件',
|
||||||
menuType:'目录',
|
menuType: '目录',
|
||||||
menuRouter:'/components',
|
menuRouter: '/components',
|
||||||
identification:'menu:components',
|
identification: 'menu:components',
|
||||||
parentId:0,
|
parentId: 0,
|
||||||
level:1,
|
level: 1,
|
||||||
id:1,
|
id: 1,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
children:[
|
children: [
|
||||||
{
|
{
|
||||||
menuName:'菜单1',
|
menuName: '菜单1',
|
||||||
menuType:'菜单',
|
menuType: '菜单',
|
||||||
menuRouter:'/components',
|
menuRouter: '/components',
|
||||||
identification:'menu1:view',
|
identification: 'menu1:view',
|
||||||
parentId:1,
|
parentId: 1,
|
||||||
level:2,
|
level: 2,
|
||||||
id:10,
|
id: 10,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
children:[
|
children: [
|
||||||
{
|
{
|
||||||
menuName:'按钮1',
|
menuName: '按钮1',
|
||||||
menuType:'按钮',
|
menuType: '按钮',
|
||||||
menuRouter:'/components',
|
menuRouter: '/components',
|
||||||
identification:'menu1:view:btn1',
|
identification: 'menu1:view:btn1',
|
||||||
parentId:10,
|
parentId: 10,
|
||||||
id:20,
|
id: 20,
|
||||||
level:3,
|
level: 3,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
menuName:'按钮2',
|
menuName: '按钮2',
|
||||||
menuType:'按钮',
|
menuType: '按钮',
|
||||||
menuRouter:'/components',
|
menuRouter: '/components',
|
||||||
identification:'menu1:view:btn2',
|
identification: 'menu1:view:btn2',
|
||||||
parentId:10,
|
parentId: 10,
|
||||||
id:21,
|
id: 21,
|
||||||
level:3,
|
level: 3,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
menuName:'按钮3',
|
menuName: '按钮3',
|
||||||
menuType:'按钮',
|
menuType: '按钮',
|
||||||
menuRouter:'/components',
|
menuRouter: '/components',
|
||||||
identification:'menu1:view:btn2',
|
identification: 'menu1:view:btn2',
|
||||||
parentId:10,
|
parentId: 10,
|
||||||
id:22,
|
id: 22,
|
||||||
level:3,
|
level: 3,
|
||||||
createTime:'2022-09-02',
|
createTime: '2022-09-02',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const dictionaryData = [
|
export const dictionaryData = [
|
||||||
{
|
{
|
||||||
"id": 1,
|
id: 1,
|
||||||
"name": "性别",
|
name: '性别',
|
||||||
"keyCode":'sex',
|
keyCode: 'sex',
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "性别",
|
remark: '性别',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
id: 2,
|
||||||
"name": "证件类型",
|
name: '证件类型',
|
||||||
"keyCode":'idType',
|
keyCode: 'idType',
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "证件类型",
|
remark: '证件类型',
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const dictionaryDetailData = [
|
export const dictionaryDetailData = [
|
||||||
{
|
{
|
||||||
"id": 1,
|
id: 1,
|
||||||
"keyCode":'sex',
|
keyCode: 'sex',
|
||||||
"name": "性别",
|
name: '性别',
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "性别",
|
remark: '性别',
|
||||||
"children":[
|
children: [
|
||||||
{
|
{
|
||||||
"id": 11,
|
id: 11,
|
||||||
"name": "男",
|
name: '男',
|
||||||
"key":1,
|
key: 1,
|
||||||
"pid":1,
|
pid: 1,
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "男",
|
remark: '男',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 12,
|
id: 12,
|
||||||
"name": "女",
|
name: '女',
|
||||||
"key":0,
|
key: 0,
|
||||||
"pid":1,
|
pid: 1,
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "女",
|
remark: '女',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
id: 2,
|
||||||
"keyCode":'idType',
|
keyCode: 'idType',
|
||||||
"name": "证件类型",
|
name: '证件类型',
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "证件类型",
|
remark: '证件类型',
|
||||||
"children":[
|
children: [
|
||||||
{
|
{
|
||||||
"id": 21,
|
id: 21,
|
||||||
"name": "身份证",
|
name: '身份证',
|
||||||
"key":1,
|
key: 1,
|
||||||
"pid":2,
|
pid: 2,
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "身份证",
|
remark: '身份证',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 22,
|
id: 22,
|
||||||
"name": "社保卡",
|
name: '社保卡',
|
||||||
"key":2,
|
key: 2,
|
||||||
"pid":2,
|
pid: 2,
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "社保卡",
|
remark: '社保卡',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 23,
|
id: 23,
|
||||||
"name": "驾驶证",
|
name: '驾驶证',
|
||||||
"key":3,
|
key: 3,
|
||||||
"pid":2,
|
pid: 2,
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "驾驶证",
|
remark: '驾驶证',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 24,
|
id: 24,
|
||||||
"name": "护照",
|
name: '护照',
|
||||||
"key":4,
|
key: 4,
|
||||||
"pid":2,
|
pid: 2,
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "护照",
|
remark: '护照',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 25,
|
id: 25,
|
||||||
"name": "工作证",
|
name: '工作证',
|
||||||
"key":5,
|
key: 5,
|
||||||
"pid":2,
|
pid: 2,
|
||||||
"createTime": "2011-02-25 18:37:39",
|
createTime: '2011-02-25 18:37:39',
|
||||||
"remark": "工作证",
|
remark: '工作证',
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,132 +1,132 @@
|
||||||
export const tableList = [
|
export const tableList = [
|
||||||
{
|
{
|
||||||
date: '2016-05-02',
|
date: '2016-05-02',
|
||||||
name: '王五',
|
name: '王五',
|
||||||
price: 20,
|
price: 20,
|
||||||
province: '上海',
|
province: '上海',
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
sex: 1,
|
sex: 1,
|
||||||
id: 1,
|
id: 1,
|
||||||
age: 18,
|
age: 18,
|
||||||
city: '普陀区',
|
city: '普陀区',
|
||||||
address: '上海市普陀区金沙江路 1518 弄',
|
address: '上海市普陀区金沙江路 1518 弄',
|
||||||
zip: 200333,
|
zip: 200333,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2018-06-11',
|
date: '2018-06-11',
|
||||||
name: '梦琪',
|
name: '梦琪',
|
||||||
price: 20,
|
price: 20,
|
||||||
province: '上海',
|
province: '上海',
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
sex: 1,
|
sex: 1,
|
||||||
id: 2,
|
id: 2,
|
||||||
age: 22,
|
age: 22,
|
||||||
city: '普陀区',
|
city: '普陀区',
|
||||||
address: '上海市普陀区金沙江路 1519 弄',
|
address: '上海市普陀区金沙江路 1519 弄',
|
||||||
zip: 200333,
|
zip: 200333,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2022-05-23',
|
date: '2022-05-23',
|
||||||
name: '忆柳',
|
name: '忆柳',
|
||||||
price: 22,
|
price: 22,
|
||||||
province: '上海',
|
province: '上海',
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
sex: 0,
|
sex: 0,
|
||||||
id: 3,
|
id: 3,
|
||||||
age: 23,
|
age: 23,
|
||||||
city: '普陀区',
|
city: '普陀区',
|
||||||
address: '上海市普陀区金沙江路 1520 弄',
|
address: '上海市普陀区金沙江路 1520 弄',
|
||||||
zip: 200333,
|
zip: 200333,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2022-01-24',
|
date: '2022-01-24',
|
||||||
name: '之桃',
|
name: '之桃',
|
||||||
price: 33,
|
price: 33,
|
||||||
province: '上海',
|
province: '上海',
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
sex: 1,
|
sex: 1,
|
||||||
id: 4,
|
id: 4,
|
||||||
age: 24,
|
age: 24,
|
||||||
city: '普陀区',
|
city: '普陀区',
|
||||||
address: '上海市普陀区金沙江路 2222 弄',
|
address: '上海市普陀区金沙江路 2222 弄',
|
||||||
zip: 200333,
|
zip: 200333,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2022-07-22',
|
date: '2022-07-22',
|
||||||
name: '慕青',
|
name: '慕青',
|
||||||
price: 45,
|
price: 45,
|
||||||
province: '上海',
|
province: '上海',
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
sex: 0,
|
sex: 0,
|
||||||
id: 5,
|
id: 5,
|
||||||
age: 25,
|
age: 25,
|
||||||
city: '普陀区',
|
city: '普陀区',
|
||||||
address: '上海市普陀区金沙江路 2223 弄',
|
address: '上海市普陀区金沙江路 2223 弄',
|
||||||
zip: 200333,
|
zip: 200333,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2016-05-02',
|
date: '2016-05-02',
|
||||||
name: '问兰',
|
name: '问兰',
|
||||||
price: 47,
|
price: 47,
|
||||||
province: '上海',
|
province: '上海',
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
sex: 1,
|
sex: 1,
|
||||||
id: 6,
|
id: 6,
|
||||||
age: 26,
|
age: 26,
|
||||||
city: '普陀区',
|
city: '普陀区',
|
||||||
address: '上海市普陀区金沙江路 2224 弄',
|
address: '上海市普陀区金沙江路 2224 弄',
|
||||||
zip: 200333,
|
zip: 200333,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2016-08-02',
|
date: '2016-08-02',
|
||||||
name: '元香',
|
name: '元香',
|
||||||
price: 45,
|
price: 45,
|
||||||
province: '上海',
|
province: '上海',
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
sex: 0,
|
sex: 0,
|
||||||
id: 7,
|
id: 7,
|
||||||
age: 27,
|
age: 27,
|
||||||
city: '普陀区',
|
city: '普陀区',
|
||||||
address: '上海市普陀区金沙江路 2225 弄',
|
address: '上海市普陀区金沙江路 2225 弄',
|
||||||
zip: 200333,
|
zip: 200333,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2019-11-11',
|
date: '2019-11-11',
|
||||||
name: '初夏',
|
name: '初夏',
|
||||||
price: 23,
|
price: 23,
|
||||||
province: '上海',
|
province: '上海',
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
sex: 1,
|
sex: 1,
|
||||||
id: 8,
|
id: 8,
|
||||||
age: 28,
|
age: 28,
|
||||||
city: '普陀区',
|
city: '普陀区',
|
||||||
address: '上海市普陀区金沙江路 2226 弄',
|
address: '上海市普陀区金沙江路 2226 弄',
|
||||||
zip: 200333,
|
zip: 200333,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2018-08-02',
|
date: '2018-08-02',
|
||||||
name: '沛菡',
|
name: '沛菡',
|
||||||
price: 33,
|
price: 33,
|
||||||
province: '上海',
|
province: '上海',
|
||||||
admin: 'other',
|
admin: 'other',
|
||||||
sex: 0,
|
sex: 0,
|
||||||
id: 9,
|
id: 9,
|
||||||
age: 29,
|
age: 29,
|
||||||
city: '普陀区',
|
city: '普陀区',
|
||||||
address: '上海市普陀区金沙江路 2227 弄',
|
address: '上海市普陀区金沙江路 2227 弄',
|
||||||
zip: 200339,
|
zip: 200339,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2022-11-03',
|
date: '2022-11-03',
|
||||||
name: '傲珊',
|
name: '傲珊',
|
||||||
price: 222,
|
price: 222,
|
||||||
province: '浙江',
|
province: '浙江',
|
||||||
admin: 'admin',
|
admin: 'admin',
|
||||||
sex: 1,
|
sex: 1,
|
||||||
id: 10,
|
id: 10,
|
||||||
age: 30,
|
age: 30,
|
||||||
city: '杭州',
|
city: '杭州',
|
||||||
address: '杭州市滨江区建业路228号',
|
address: '杭州市滨江区建业路228号',
|
||||||
zip: 200433,
|
zip: 200433,
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import router from '@/routers/index'
|
import router from '@/routers/index'
|
||||||
import NProgress from 'nprogress'
|
import NProgress from 'nprogress'
|
||||||
import 'nprogress/nprogress.css'
|
import 'nprogress/nprogress.css'
|
||||||
import {useUserStore} from "@/store/modules/user"
|
import { useUserStore } from '@/store/modules/user'
|
||||||
import {usePermissionStore} from "@/store/modules/permission"
|
import { usePermissionStore } from '@/store/modules/permission'
|
||||||
|
|
||||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||||
|
|
||||||
|
|
@ -10,51 +10,48 @@ const whiteList = ['/login', '/auth-redirect'] // 设置白名单
|
||||||
// 记录路由
|
// 记录路由
|
||||||
let hasRoles = true
|
let hasRoles = true
|
||||||
|
|
||||||
router.beforeEach(async(to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
// 开启进度条
|
// 开启进度条
|
||||||
NProgress.start()
|
NProgress.start()
|
||||||
// 设置标题
|
// 设置标题
|
||||||
if(typeof(to.meta.title) === 'string'){
|
if (typeof to.meta.title === 'string') {
|
||||||
document.title = to.meta.title ||'vue-admin-perfect'
|
document.title = to.meta.title || 'vue-admin-perfect'
|
||||||
}
|
}
|
||||||
|
|
||||||
const UserStore = useUserStore();
|
const UserStore = useUserStore()
|
||||||
// 确定用户是否已登录过,存在Token
|
// 确定用户是否已登录过,存在Token
|
||||||
const hasToken = UserStore.token
|
const hasToken = UserStore.token
|
||||||
|
|
||||||
|
|
||||||
if (hasToken) {
|
if (hasToken) {
|
||||||
if (to.path === '/login') {
|
if (to.path === '/login') {
|
||||||
// 如果已登录,请重定向到主页
|
// 如果已登录,请重定向到主页
|
||||||
next({ path: '/' })
|
next({ path: '/' })
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const PermissionStore = usePermissionStore()
|
const PermissionStore = usePermissionStore()
|
||||||
// 路由添加进去了没有及时更新 需要重新进去一次拦截
|
// 路由添加进去了没有及时更新 需要重新进去一次拦截
|
||||||
if(!PermissionStore.routes.length){
|
if (!PermissionStore.routes.length) {
|
||||||
// 获取权限列表进行接口访问 因为这里页面要切换权限
|
// 获取权限列表进行接口访问 因为这里页面要切换权限
|
||||||
const accessRoutes = await PermissionStore.generateRoutes(UserStore.roles)
|
const accessRoutes = await PermissionStore.generateRoutes(UserStore.roles)
|
||||||
hasRoles = false
|
hasRoles = false
|
||||||
accessRoutes.forEach(item => router.addRoute(item)) // 动态添加访问路由表
|
accessRoutes.forEach((item) => router.addRoute(item)) // 动态添加访问路由表
|
||||||
next({ ...to, replace: true }) // // 这里相当于push到一个页面 不在进入路由拦截
|
next({ ...to, replace: true }) // // 这里相当于push到一个页面 不在进入路由拦截
|
||||||
}else {
|
} else {
|
||||||
next() // // 如果不传参数就会重新执行路由拦截,重新进到这里
|
next() // // 如果不传参数就会重新执行路由拦截,重新进到这里
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
next(`/login?redirect=${to.path}`)
|
|
||||||
}
|
}
|
||||||
}
|
} catch (error) {
|
||||||
}else{
|
next(`/login?redirect=${to.path}`)
|
||||||
if (whiteList.indexOf(to.path) !== -1) {
|
|
||||||
next()
|
|
||||||
} else {
|
|
||||||
next(`/login?redirect=${to.path}`)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (whiteList.indexOf(to.path) !== -1) {
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
next(`/login?redirect=${to.path}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.afterEach(() => {
|
router.afterEach(() => {
|
||||||
NProgress.done();
|
NProgress.done()
|
||||||
});
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
|
|
||||||
// 注册icon组件
|
// 注册icon组件
|
||||||
import * as ElIconsModules from '@element-plus/icons-vue'
|
import * as ElIconsModules from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
export const registerElIcons = (app) => {
|
||||||
export const registerElIcons = (app)=>{
|
// 全局注册element-plus icon图标组件
|
||||||
// 全局注册element-plus icon图标组件
|
Object.keys(ElIconsModules).forEach((key) => {
|
||||||
Object.keys(ElIconsModules).forEach((key) => {//循环遍历组件名称
|
//循环遍历组件名称
|
||||||
if ("Menu" !== key) {//如果不是图标组件不是Menu,就跳过,否则加上ICon的后缀
|
if ('Menu' !== key) {
|
||||||
app.component(key, ElIconsModules[key]);
|
//如果不是图标组件不是Menu,就跳过,否则加上ICon的后缀
|
||||||
} else {
|
app.component(key, ElIconsModules[key])
|
||||||
app.component(key + "Icon", ElIconsModules[key]);
|
} else {
|
||||||
}
|
app.component(key + 'Icon', ElIconsModules[key])
|
||||||
});
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,4 @@
|
||||||
import {
|
import { createRouter, createWebHistory, RouteRecordRaw, createWebHashHistory, Router } from 'vue-router'
|
||||||
createRouter,
|
|
||||||
createWebHistory,
|
|
||||||
RouteRecordRaw,
|
|
||||||
createWebHashHistory,
|
|
||||||
Router,
|
|
||||||
} from 'vue-router'
|
|
||||||
import Layout from '@/layout/index.vue'
|
import Layout from '@/layout/index.vue'
|
||||||
// 扩展继承属性
|
// 扩展继承属性
|
||||||
interface extendRoute {
|
interface extendRoute {
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,26 @@
|
||||||
/** When your routing table is too long, you can split it into small modules**/
|
/** When your routing table is too long, you can split it into small modules**/
|
||||||
|
|
||||||
import Layout from "@/layout/index.vue";
|
import Layout from '@/layout/index.vue'
|
||||||
|
|
||||||
const chartsRouter = [{
|
const chartsRouter = [
|
||||||
|
{
|
||||||
path: '/chat',
|
path: '/chat',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/chat/index',
|
redirect: '/chat/index',
|
||||||
name: 'chat',
|
name: 'chat',
|
||||||
meta: {
|
meta: {
|
||||||
title: '聊天框',
|
title: '聊天框',
|
||||||
icon: 'chat-square'
|
icon: 'chat-square',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/chat/index',
|
path: '/chat/index',
|
||||||
component: () => import('@/views/chat/index.vue'),
|
component: () => import('@/views/chat/index.vue'),
|
||||||
name: 'chatBox',
|
name: 'chatBox',
|
||||||
meta: { title: '聊天框', icon: 'chat-square' }
|
meta: { title: '聊天框', icon: 'chat-square' },
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}]
|
},
|
||||||
|
]
|
||||||
|
|
||||||
export default chartsRouter
|
export default chartsRouter
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
const dataScreenRouter= [{
|
const dataScreenRouter = [
|
||||||
path: "/dataScreen",
|
{
|
||||||
name: "dataScreen",
|
path: '/dataScreen',
|
||||||
meta: {
|
name: 'dataScreen',
|
||||||
title: "可视化大屏",
|
meta: {
|
||||||
icon:'Histogram'
|
title: '可视化大屏',
|
||||||
},
|
icon: 'Histogram',
|
||||||
component: () => import("@/views/dataScreen/index.vue")
|
},
|
||||||
}]
|
component: () => import('@/views/dataScreen/index.vue'),
|
||||||
;
|
},
|
||||||
|
]
|
||||||
export default dataScreenRouter;
|
export default dataScreenRouter
|
||||||
|
|
|
||||||
|
|
@ -1,52 +1,53 @@
|
||||||
/** When your routing table is too long, you can split it into small modules**/
|
/** When your routing table is too long, you can split it into small modules**/
|
||||||
|
|
||||||
import Layout from "@/layout/index.vue";
|
import Layout from '@/layout/index.vue'
|
||||||
|
|
||||||
const echartsRouter = [{
|
const echartsRouter = [
|
||||||
|
{
|
||||||
path: '/echarts',
|
path: '/echarts',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/echarts/migration',
|
redirect: '/echarts/migration',
|
||||||
name: 'echarts',
|
name: 'echarts',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Echarts',
|
title: 'Echarts',
|
||||||
icon: 'trend-charts',
|
icon: 'trend-charts',
|
||||||
roles:['other']
|
roles: ['other'],
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/echarts/migration',
|
path: '/echarts/migration',
|
||||||
component: () => import('@/views/echarts/migrationMap/index.vue'),
|
component: () => import('@/views/echarts/migrationMap/index.vue'),
|
||||||
name: 'migration',
|
name: 'migration',
|
||||||
meta: { title: '迁徙图', roles:['other'] , icon: 'MenuIcon' }
|
meta: { title: '迁徙图', roles: ['other'], icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/echarts/bar',
|
path: '/echarts/bar',
|
||||||
component: () => import('@/views/echarts/barEcharts/index.vue'),
|
component: () => import('@/views/echarts/barEcharts/index.vue'),
|
||||||
name: 'bar',
|
name: 'bar',
|
||||||
meta: { title: '柱状图', roles:['other'] , icon: 'MenuIcon'}
|
meta: { title: '柱状图', roles: ['other'], icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/echarts/graph',
|
path: '/echarts/graph',
|
||||||
component: () => import('@/views/echarts/graphEcharts/index.vue'),
|
component: () => import('@/views/echarts/graphEcharts/index.vue'),
|
||||||
name: 'graph',
|
name: 'graph',
|
||||||
meta: { title: '雷达图', roles:['other'] , icon: 'MenuIcon'}
|
meta: { title: '雷达图', roles: ['other'], icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/echarts/pie',
|
path: '/echarts/pie',
|
||||||
component: () => import('@/views/echarts/pieEcharts/index.vue'),
|
component: () => import('@/views/echarts/pieEcharts/index.vue'),
|
||||||
name: 'pie',
|
name: 'pie',
|
||||||
meta: { title: '饼图', roles:['other'] , icon: 'MenuIcon'}
|
meta: { title: '饼图', roles: ['other'], icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/echarts/simple',
|
path: '/echarts/simple',
|
||||||
component: () => import('@/views/echarts/simple/index.vue'),
|
component: () => import('@/views/echarts/simple/index.vue'),
|
||||||
name: 'echarts-simple',
|
name: 'echarts-simple',
|
||||||
meta: { title: '简单图表', roles:['other'] , icon: 'MenuIcon'}
|
meta: { title: '简单图表', roles: ['other'], icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
|
],
|
||||||
]
|
},
|
||||||
}]
|
]
|
||||||
|
|
||||||
export default echartsRouter
|
export default echartsRouter
|
||||||
|
|
|
||||||
|
|
@ -1,48 +1,48 @@
|
||||||
|
import Layout from '@/layout/index.vue'
|
||||||
|
|
||||||
|
const excelRouter = [
|
||||||
import Layout from "@/layout/index.vue";
|
{
|
||||||
|
|
||||||
const excelRouter = [{
|
|
||||||
path: '/excel',
|
path: '/excel',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/excel/export-excel',
|
redirect: '/excel/export-excel',
|
||||||
name: 'excel',
|
name: 'excel',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'Excel&Zip',
|
title: 'Excel&Zip',
|
||||||
icon: 'School'
|
icon: 'School',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/excel/export-excel',
|
path: '/excel/export-excel',
|
||||||
component: () => import('@/views/excel/exportExcel/index.vue'),
|
component: () => import('@/views/excel/exportExcel/index.vue'),
|
||||||
name: 'export-excel',
|
name: 'export-excel',
|
||||||
meta: { title: '导出 Excel', icon: 'MenuIcon'}
|
meta: { title: '导出 Excel', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/excel/export-merge-header',
|
path: '/excel/export-merge-header',
|
||||||
component: () => import('@/views/excel/exportMergeHeader/index.vue'),
|
component: () => import('@/views/excel/exportMergeHeader/index.vue'),
|
||||||
name: 'export-merge-header',
|
name: 'export-merge-header',
|
||||||
meta: { title: '导出 多级表头', icon: 'MenuIcon' }
|
meta: { title: '导出 多级表头', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/excel/upload-style-excel',
|
path: '/excel/upload-style-excel',
|
||||||
component: () => import('@/views/excel/exportStyleExcel/index.vue'),
|
component: () => import('@/views/excel/exportStyleExcel/index.vue'),
|
||||||
name: 'upload-style-excel',
|
name: 'upload-style-excel',
|
||||||
meta: { title: '自定义样式导出 Excel', icon: 'MenuIcon' }
|
meta: { title: '自定义样式导出 Excel', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/excel/upload-excel',
|
path: '/excel/upload-excel',
|
||||||
component: () => import('@/views/excel/uploadExcel/index.vue'),
|
component: () => import('@/views/excel/uploadExcel/index.vue'),
|
||||||
name: 'upload-excel',
|
name: 'upload-excel',
|
||||||
meta: { title: '上传 Excel', icon: 'MenuIcon' }
|
meta: { title: '上传 Excel', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/excel/zip',
|
path: '/excel/zip',
|
||||||
component: () => import('@/views/excel/zip/index.vue'),
|
component: () => import('@/views/excel/zip/index.vue'),
|
||||||
name: 'Zip',
|
name: 'Zip',
|
||||||
meta: { title: '导出 Zip', roles:['other'] ,icon: 'MenuIcon',}
|
meta: { title: '导出 Zip', roles: ['other'], icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}]
|
},
|
||||||
|
]
|
||||||
|
|
||||||
export default excelRouter
|
export default excelRouter
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,46 @@
|
||||||
|
import Layout from '@/layout/index.vue'
|
||||||
|
|
||||||
|
const externalLink = [
|
||||||
import Layout from "@/layout/index.vue";
|
{
|
||||||
|
|
||||||
const externalLink = [{
|
|
||||||
path: '/external-link',
|
path: '/external-link',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/external-link/wechat',
|
redirect: '/external-link/wechat',
|
||||||
name: 'external-link',
|
name: 'external-link',
|
||||||
meta: {
|
meta: {
|
||||||
title: '外部链接',
|
title: '外部链接',
|
||||||
icon: 'link'
|
icon: 'link',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
// {
|
// {
|
||||||
// path: '/external-link/wechat',
|
// path: '/external-link/wechat',
|
||||||
// name: 'wechat',
|
// name: 'wechat',
|
||||||
// component: () => import('@/views/externalLinks/wechat/index.vue'),
|
// component: () => import('@/views/externalLinks/wechat/index.vue'),
|
||||||
// meta: { title: '加微信群', icon: 'MenuIcon' }
|
// meta: { title: '加微信群', icon: 'MenuIcon' }
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
path: 'https://github.com/zouzhibin/vue-admin-perfect',
|
path: 'https://github.com/zouzhibin/vue-admin-perfect',
|
||||||
name: 'github',
|
name: 'github',
|
||||||
meta: { title: 'Github 地址', icon: 'MenuIcon' }
|
meta: { title: 'Github 地址', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'https://gitee.com/yuanzbz/vue-admin-perfect?_from=gitee_search',
|
path: 'https://gitee.com/yuanzbz/vue-admin-perfect?_from=gitee_search',
|
||||||
name: 'github',
|
name: 'github',
|
||||||
meta: { title: 'Gitee 地址', icon: 'MenuIcon' }
|
meta: { title: 'Gitee 地址', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'https://yuanzbz.gitee.io/vue-admin-simple',
|
path: 'https://yuanzbz.gitee.io/vue-admin-simple',
|
||||||
name: 'simple',
|
name: 'simple',
|
||||||
meta: { title: '简易版本', icon: 'MenuIcon' },
|
meta: { title: '简易版本', icon: 'MenuIcon' },
|
||||||
component: () => import('@/views/externalLinks/simple/index.vue'),
|
component: () => import('@/views/externalLinks/simple/index.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/external-link/iframe',
|
path: '/external-link/iframe',
|
||||||
component: () => import('@/views/externalLinks/iframe/index.vue'),
|
component: () => import('@/views/externalLinks/iframe/index.vue'),
|
||||||
name: 'iframe',
|
name: 'iframe',
|
||||||
meta: { title: '内嵌 iframe', icon: 'MenuIcon' }
|
meta: { title: '内嵌 iframe', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}]
|
},
|
||||||
|
]
|
||||||
|
|
||||||
export default externalLink
|
export default externalLink
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,50 @@
|
||||||
|
|
||||||
/** When your routing table is too long, you can split it into small modules**/
|
/** When your routing table is too long, you can split it into small modules**/
|
||||||
|
|
||||||
import Layout from "@/layout/index.vue";
|
import Layout from '@/layout/index.vue'
|
||||||
|
|
||||||
const functionPageRouter = [{
|
const functionPageRouter = [
|
||||||
|
{
|
||||||
path: '/function-page',
|
path: '/function-page',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/function-page/404',
|
redirect: '/function-page/404',
|
||||||
name: 'function-page',
|
name: 'function-page',
|
||||||
meta: {
|
meta: {
|
||||||
title: '功能页面',
|
title: '功能页面',
|
||||||
icon: 'ElementPlus'
|
icon: 'ElementPlus',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/function-page/tools',
|
path: '/function-page/tools',
|
||||||
component: () => import('@/views/functionPage/tools/index.vue'),
|
component: () => import('@/views/functionPage/tools/index.vue'),
|
||||||
name: 'tools',
|
name: 'tools',
|
||||||
meta: { title: '工具链集合', keepAlive: true , icon: 'MenuIcon'}
|
meta: { title: '工具链集合', keepAlive: true, icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/function-page/404',
|
path: '/function-page/404',
|
||||||
component: () => import('@/views/errorPages/404.vue'),
|
component: () => import('@/views/errorPages/404.vue'),
|
||||||
name: 'function-404',
|
name: 'function-404',
|
||||||
meta: { title: '404 页面', keepAlive: true , icon: 'MenuIcon'}
|
meta: { title: '404 页面', keepAlive: true, icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/function-page/403',
|
path: '/function-page/403',
|
||||||
component: () => import('@/views/errorPages/403.vue'),
|
component: () => import('@/views/errorPages/403.vue'),
|
||||||
name: 'function-403',
|
name: 'function-403',
|
||||||
meta: { title: '403 页面', keepAlive: true , icon: 'MenuIcon'}
|
meta: { title: '403 页面', keepAlive: true, icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/function-page/fullscreen',
|
path: '/function-page/fullscreen',
|
||||||
component: () => import('@/views/functionPage/fullscreen/index.vue'),
|
component: () => import('@/views/functionPage/fullscreen/index.vue'),
|
||||||
name: 'fullscreen',
|
name: 'fullscreen',
|
||||||
meta: { title: '元素 全屏', keepAlive: true , icon: 'MenuIcon'}
|
meta: { title: '元素 全屏', keepAlive: true, icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/function-page/information-list',
|
path: '/function-page/information-list',
|
||||||
component: () => import('@/views/functionPage/informationList/index.vue'),
|
component: () => import('@/views/functionPage/informationList/index.vue'),
|
||||||
name: 'informationList',
|
name: 'informationList',
|
||||||
meta: { title: '信息列表', keepAlive: true , icon: 'MenuIcon'}
|
meta: { title: '信息列表', keepAlive: true, icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}]
|
},
|
||||||
|
]
|
||||||
|
|
||||||
export default functionPageRouter
|
export default functionPageRouter
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
|
|
||||||
|
|
||||||
/** When your routing table is too long, you can split it into small modules**/
|
/** When your routing table is too long, you can split it into small modules**/
|
||||||
|
|
||||||
import Layout from "@/layout/index.vue";
|
import Layout from '@/layout/index.vue'
|
||||||
|
|
||||||
const nestedRouter = [{
|
const nestedRouter = [
|
||||||
|
{
|
||||||
path: '/nested',
|
path: '/nested',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/nested/menu1',
|
redirect: '/nested/menu1',
|
||||||
name: 'nested',
|
name: 'nested',
|
||||||
meta: {
|
meta: {
|
||||||
title: '路由嵌套',
|
title: '路由嵌套',
|
||||||
icon: 'HelpFilled'
|
icon: 'HelpFilled',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
|
|
@ -19,52 +18,52 @@ const nestedRouter = [{
|
||||||
component: () => import('@/views/nested/menu1/index.vue'),
|
component: () => import('@/views/nested/menu1/index.vue'),
|
||||||
name: 'menu1',
|
name: 'menu1',
|
||||||
meta: { title: '菜单1', icon: 'MenuIcon' },
|
meta: { title: '菜单1', icon: 'MenuIcon' },
|
||||||
alwaysShow:true,
|
alwaysShow: true,
|
||||||
redirect: '/nested/menu1/menu1-1',
|
redirect: '/nested/menu1/menu1-1',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/nested/menu1/menu1-1',
|
path: '/nested/menu1/menu1-1',
|
||||||
component: () => import('@/views/nested/menu1/menu1-1/index.vue'),
|
component: () => import('@/views/nested/menu1/menu1-1/index.vue'),
|
||||||
name: 'menu1-1',
|
name: 'menu1-1',
|
||||||
meta: { title: '菜单 1-1' , icon: 'MenuIcon'}
|
meta: { title: '菜单 1-1', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/nested/menu1/menu1-2',
|
path: '/nested/menu1/menu1-2',
|
||||||
component: () => import('@/views/nested/menu1/menu1-2/index.vue'),
|
component: () => import('@/views/nested/menu1/menu1-2/index.vue'),
|
||||||
name: 'menu1-2',
|
name: 'menu1-2',
|
||||||
redirect: '/nested/menu1/menu1-2/menu1-2-1',
|
redirect: '/nested/menu1/menu1-2/menu1-2-1',
|
||||||
meta: { title: '菜单 1-2' , icon: 'MenuIcon'},
|
meta: { title: '菜单 1-2', icon: 'MenuIcon' },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/nested/menu1/menu1-2/menu1-2-1',
|
path: '/nested/menu1/menu1-2/menu1-2-1',
|
||||||
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1/index.vue'),
|
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1/index.vue'),
|
||||||
name: 'menu1-2-1',
|
name: 'menu1-2-1',
|
||||||
meta: { title: '菜单 1-2-1' , icon: 'MenuIcon'}
|
meta: { title: '菜单 1-2-1', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/nested/menu1/menu1-2/menu1-2-2',
|
path: '/nested/menu1/menu1-2/menu1-2-2',
|
||||||
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2/index.vue'),
|
component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2/index.vue'),
|
||||||
name: 'menu1-2-2',
|
name: 'menu1-2-2',
|
||||||
meta: { title: '菜单 1-2-2' , icon: 'MenuIcon'}
|
meta: { title: '菜单 1-2-2', icon: 'MenuIcon' },
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/nested/menu1/menu1-3',
|
path: '/nested/menu1/menu1-3',
|
||||||
component: () => import('@/views/nested/menu1/menu1-3/index.vue'),
|
component: () => import('@/views/nested/menu1/menu1-3/index.vue'),
|
||||||
name: 'menu1-3',
|
name: 'menu1-3',
|
||||||
meta: { title: '菜单 1-3' , icon: 'MenuIcon'}
|
meta: { title: '菜单 1-3', icon: 'MenuIcon' },
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/nested/menu2',
|
path: '/nested/menu2',
|
||||||
component: () => import('@/views/nested/menu2/index.vue'),
|
component: () => import('@/views/nested/menu2/index.vue'),
|
||||||
name: 'nested-menu2',
|
name: 'nested-menu2',
|
||||||
meta: { title: '菜单2', icon: 'MenuIcon'}
|
meta: { title: '菜单2', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
|
],
|
||||||
]
|
},
|
||||||
}]
|
]
|
||||||
|
|
||||||
export default nestedRouter
|
export default nestedRouter
|
||||||
|
|
|
||||||
|
|
@ -2,47 +2,49 @@
|
||||||
|
|
||||||
import Layout from '@/layout/index.vue'
|
import Layout from '@/layout/index.vue'
|
||||||
|
|
||||||
const systemRouter = [{
|
const systemRouter = [
|
||||||
|
{
|
||||||
path: '/system',
|
path: '/system',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
redirect: '/system/user',
|
redirect: '/system/user',
|
||||||
name: 'system',
|
name: 'system',
|
||||||
meta: {
|
meta: {
|
||||||
title: '系统管理',
|
title: '系统管理',
|
||||||
icon: 'Setting',
|
icon: 'Setting',
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/system/user',
|
path: '/system/user',
|
||||||
component: () => import('@/views/system/user/index.vue'),
|
component: () => import('@/views/system/user/index.vue'),
|
||||||
name: 'user',
|
name: 'user',
|
||||||
meta: { title: '用户管理' , icon: 'MenuIcon'}
|
meta: { title: '用户管理', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/system/dept',
|
path: '/system/dept',
|
||||||
component: () => import('@/views/system/dept/index.vue'),
|
component: () => import('@/views/system/dept/index.vue'),
|
||||||
name: 'dept',
|
name: 'dept',
|
||||||
meta: { title: '部门管理' , icon: 'MenuIcon'}
|
meta: { title: '部门管理', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/system/role',
|
path: '/system/role',
|
||||||
component: () => import('@/views/system/role/index.vue'),
|
component: () => import('@/views/system/role/index.vue'),
|
||||||
name: 'role',
|
name: 'role',
|
||||||
meta: { title: '角色管理', icon: 'MenuIcon' }
|
meta: { title: '角色管理', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/system/menu',
|
path: '/system/menu',
|
||||||
component: () => import('@/views/system/menu/index.vue'),
|
component: () => import('@/views/system/menu/index.vue'),
|
||||||
name: 'menu',
|
name: 'menu',
|
||||||
meta: { title: '菜单管理', icon: 'MenuIcon'}
|
meta: { title: '菜单管理', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/system/dictionary',
|
path: '/system/dictionary',
|
||||||
component: () => import('@/views/system/dictionary/index.vue'),
|
component: () => import('@/views/system/dictionary/index.vue'),
|
||||||
name: 'dictionary',
|
name: 'dictionary',
|
||||||
meta: { title: '字典管理', icon: 'MenuIcon'}
|
meta: { title: '字典管理', icon: 'MenuIcon' },
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
}]
|
},
|
||||||
|
]
|
||||||
|
|
||||||
export default systemRouter
|
export default systemRouter
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,23 @@
|
||||||
import {defineStore,createPinia} from 'pinia'
|
import { defineStore, createPinia } from 'pinia'
|
||||||
// 引入持久化插件
|
// 引入持久化插件
|
||||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||||
|
|
||||||
export const Store = defineStore({
|
export const Store = defineStore({
|
||||||
// id: 必须的,在所有 Store 中唯一
|
// id: 必须的,在所有 Store 中唯一
|
||||||
id:'globalState',
|
id: 'globalState',
|
||||||
// state: 返回对象的函数
|
// state: 返回对象的函数
|
||||||
state: ()=>({
|
state: () => ({}),
|
||||||
|
getters: {},
|
||||||
}),
|
actions: {},
|
||||||
getters: {},
|
persist: {
|
||||||
actions:{},
|
// 本地存储的名称
|
||||||
persist: {
|
key: 'globalState',
|
||||||
// 本地存储的名称
|
//保存的位置
|
||||||
key: "globalState",
|
storage: window.sessionStorage, //localstorage
|
||||||
//保存的位置
|
},
|
||||||
storage: window.sessionStorage,//localstorage
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const pinia = createPinia()
|
||||||
const pinia = createPinia();
|
|
||||||
//pinia使用
|
//pinia使用
|
||||||
pinia.use(piniaPluginPersistedstate);
|
pinia.use(piniaPluginPersistedstate)
|
||||||
export default pinia
|
export default pinia
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,54 @@
|
||||||
import {defineStore} from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { asyncRoutes, constantRoutes,routerArray,notFoundRouter } from '@/routers/index'
|
import { asyncRoutes, constantRoutes, routerArray, notFoundRouter } from '@/routers/index'
|
||||||
import {hasPermission,filterAsyncRoutes} from "@/utils/routers"
|
import { hasPermission, filterAsyncRoutes } from '@/utils/routers'
|
||||||
import {filterKeepAlive,filterRoutes} from "@/utils/routers";
|
import { filterKeepAlive, filterRoutes } from '@/utils/routers'
|
||||||
export const usePermissionStore = defineStore({
|
export const usePermissionStore = defineStore({
|
||||||
// id: 必须的,在所有 Store 中唯一
|
// id: 必须的,在所有 Store 中唯一
|
||||||
id:'permissionState',
|
id: 'permissionState',
|
||||||
// state: 返回对象的函数
|
// state: 返回对象的函数
|
||||||
state: ()=>({
|
state: () => ({
|
||||||
// 路由
|
// 路由
|
||||||
routes:[],
|
routes: [],
|
||||||
// 动态路由
|
// 动态路由
|
||||||
addRoutes:[],
|
addRoutes: [],
|
||||||
// 缓存路由
|
// 缓存路由
|
||||||
cacheRoutes:{},
|
cacheRoutes: {},
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
permission_routes:state=> {
|
permission_routes: (state) => {
|
||||||
return state.routes
|
return state.routes
|
||||||
},
|
|
||||||
keepAliveRoutes: state=>{
|
|
||||||
return filterKeepAlive(asyncRoutes)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
// 可以同步 也可以异步
|
keepAliveRoutes: (state) => {
|
||||||
actions:{
|
return filterKeepAlive(asyncRoutes)
|
||||||
// 生成路由
|
|
||||||
generateRoutes(roles){
|
|
||||||
return new Promise(resolve => {
|
|
||||||
// 在这判断是否有权限,哪些角色拥有哪些权限
|
|
||||||
let accessedRoutes
|
|
||||||
if (roles&&roles.length&&!roles.includes('admin')) {
|
|
||||||
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
|
|
||||||
} else {
|
|
||||||
accessedRoutes = asyncRoutes || []
|
|
||||||
}
|
|
||||||
accessedRoutes = accessedRoutes.concat(notFoundRouter)
|
|
||||||
this.routes = constantRoutes.concat(accessedRoutes)
|
|
||||||
this.addRoutes = accessedRoutes
|
|
||||||
resolve(accessedRoutes)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// 清楚路由
|
|
||||||
clearRoutes(){
|
|
||||||
this.routes = []
|
|
||||||
this.addRoutes = []
|
|
||||||
this.cacheRoutes = []
|
|
||||||
},
|
|
||||||
getCacheRoutes(){
|
|
||||||
this.cacheRoutes = filterKeepAlive(asyncRoutes)
|
|
||||||
return this.cacheRoutes
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
// 可以同步 也可以异步
|
||||||
|
actions: {
|
||||||
|
// 生成路由
|
||||||
|
generateRoutes(roles) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// 在这判断是否有权限,哪些角色拥有哪些权限
|
||||||
|
let accessedRoutes
|
||||||
|
if (roles && roles.length && !roles.includes('admin')) {
|
||||||
|
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
|
||||||
|
} else {
|
||||||
|
accessedRoutes = asyncRoutes || []
|
||||||
|
}
|
||||||
|
accessedRoutes = accessedRoutes.concat(notFoundRouter)
|
||||||
|
this.routes = constantRoutes.concat(accessedRoutes)
|
||||||
|
this.addRoutes = accessedRoutes
|
||||||
|
resolve(accessedRoutes)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 清楚路由
|
||||||
|
clearRoutes() {
|
||||||
|
this.routes = []
|
||||||
|
this.addRoutes = []
|
||||||
|
this.cacheRoutes = []
|
||||||
|
},
|
||||||
|
getCacheRoutes() {
|
||||||
|
this.cacheRoutes = filterKeepAlive(asyncRoutes)
|
||||||
|
return this.cacheRoutes
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,81 +1,79 @@
|
||||||
import {defineStore} from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import {PRIMARY_COLOR} from "../../config";
|
import { PRIMARY_COLOR } from '../../config'
|
||||||
|
|
||||||
|
|
||||||
export const useSettingStore = defineStore({
|
export const useSettingStore = defineStore({
|
||||||
// id: 必须的,在所有 Store 中唯一
|
// id: 必须的,在所有 Store 中唯一
|
||||||
id:'settingState',
|
id: 'settingState',
|
||||||
// state: 返回对象的函数
|
// state: 返回对象的函数
|
||||||
state: ()=>({
|
state: () => ({
|
||||||
// menu 是否收缩
|
// menu 是否收缩
|
||||||
isCollapse:true,
|
isCollapse: true,
|
||||||
//
|
//
|
||||||
withoutAnimation:false,
|
withoutAnimation: false,
|
||||||
device: 'desktop',
|
device: 'desktop',
|
||||||
// 刷新当前页
|
// 刷新当前页
|
||||||
isReload:true,
|
isReload: true,
|
||||||
// 主题设置
|
// 主题设置
|
||||||
themeConfig:{
|
themeConfig: {
|
||||||
// 显示设置
|
// 显示设置
|
||||||
showSetting:false,
|
showSetting: false,
|
||||||
// 菜单展示模式 默认 vertical horizontal / vertical /columns
|
// 菜单展示模式 默认 vertical horizontal / vertical /columns
|
||||||
mode: 'vertical',
|
mode: 'vertical',
|
||||||
// tagsView 是否展示 默认展示
|
// tagsView 是否展示 默认展示
|
||||||
showTag:true,
|
showTag: true,
|
||||||
// 页脚
|
// 页脚
|
||||||
footer: true,
|
footer: true,
|
||||||
// 深色模式 切换暗黑模式
|
// 深色模式 切换暗黑模式
|
||||||
isDark: false,
|
isDark: false,
|
||||||
// 显示侧边栏Logo
|
// 显示侧边栏Logo
|
||||||
showLogo:true,
|
showLogo: true,
|
||||||
// 主题颜色
|
// 主题颜色
|
||||||
primary:PRIMARY_COLOR,
|
primary: PRIMARY_COLOR,
|
||||||
// element组件大小
|
// element组件大小
|
||||||
globalComSize:'default',
|
globalComSize: 'default',
|
||||||
// 是否只保持一个子菜单的展开
|
// 是否只保持一个子菜单的展开
|
||||||
uniqueOpened:true,
|
uniqueOpened: true,
|
||||||
// 固定header
|
// 固定header
|
||||||
fixedHeader:true,
|
fixedHeader: true,
|
||||||
// 灰色模式
|
// 灰色模式
|
||||||
gray:false,
|
gray: false,
|
||||||
// 色弱模式
|
// 色弱模式
|
||||||
weak:false
|
weak: false,
|
||||||
},
|
|
||||||
}),
|
|
||||||
getters: {},
|
|
||||||
// 可以同步 也可以异步
|
|
||||||
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: {
|
getters: {},
|
||||||
// // 本地存储的名称
|
// 可以同步 也可以异步
|
||||||
// key: "settingState",
|
actions: {
|
||||||
// //保存的位置
|
// 设置主题
|
||||||
// storage: window.localStorage,//localstorage
|
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
|
||||||
|
// },
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,113 +1,107 @@
|
||||||
import {defineStore} from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import router from "@/routers/index";
|
import router from '@/routers/index'
|
||||||
|
|
||||||
export const useTagsViewStore = defineStore({
|
export const useTagsViewStore = defineStore({
|
||||||
// id: 必须的,在所有 Store 中唯一
|
// id: 必须的,在所有 Store 中唯一
|
||||||
id:'tagsViewState',
|
id: 'tagsViewState',
|
||||||
// state: 返回对象的函数
|
// state: 返回对象的函数
|
||||||
state: ()=>({
|
state: () => ({
|
||||||
activeTabsValue:'/home',
|
activeTabsValue: '/home',
|
||||||
visitedViews:[],
|
visitedViews: [],
|
||||||
cachedViews:[],
|
cachedViews: [],
|
||||||
|
}),
|
||||||
}),
|
getters: {},
|
||||||
getters: {},
|
// 可以同步 也可以异步
|
||||||
// 可以同步 也可以异步
|
actions: {
|
||||||
actions:{
|
setTabsMenuValue(val) {
|
||||||
setTabsMenuValue(val){
|
this.activeTabsValue = 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
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) {
|
||||||
|
const 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,61 @@
|
||||||
import {defineStore} from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
|
||||||
export const useUserStore = defineStore({
|
export const useUserStore = defineStore({
|
||||||
// id: 必须的,在所有 Store 中唯一
|
// id: 必须的,在所有 Store 中唯一
|
||||||
id:'userState',
|
id: 'userState',
|
||||||
// state: 返回对象的函数
|
// state: 返回对象的函数
|
||||||
state: ()=>({
|
state: () => ({
|
||||||
// 登录token
|
// 登录token
|
||||||
token:null,
|
token: null,
|
||||||
// 登录用户信息
|
// 登录用户信息
|
||||||
userInfo:{},
|
userInfo: {},
|
||||||
// 角色
|
// 角色
|
||||||
roles:localStorage.roles?JSON.parse(localStorage.roles):[]
|
roles: localStorage.roles ? JSON.parse(localStorage.roles) : [],
|
||||||
|
}),
|
||||||
}),
|
getters: {},
|
||||||
getters: {},
|
// 可以同步 也可以异步
|
||||||
// 可以同步 也可以异步
|
actions: {
|
||||||
actions:{
|
// 登录
|
||||||
// 登录
|
login(userInfo) {
|
||||||
login(userInfo){
|
const { username, password } = userInfo
|
||||||
const { username, password } = userInfo
|
return new Promise(async (resolve, reject) => {
|
||||||
return new Promise(async (resolve, reject) => {
|
this.token = username
|
||||||
this.token = username
|
this.userInfo = userInfo
|
||||||
this.userInfo = userInfo
|
await this.getRoles()
|
||||||
await this.getRoles()
|
resolve(username)
|
||||||
resolve(username)
|
})
|
||||||
})
|
|
||||||
},
|
|
||||||
// 获取用户授权角色信息,实际应用中 可以通过token通过请求接口在这里获取用户信息
|
|
||||||
getRoles(){
|
|
||||||
return new Promise((resolve, reject) =>{
|
|
||||||
// 获取权限列表 默认就是超级管理员,因为没有进行接口请求 写死
|
|
||||||
this.roles = ['admin']
|
|
||||||
localStorage.roles = JSON.stringify(this.roles)
|
|
||||||
resolve(this.roles)
|
|
||||||
} )
|
|
||||||
},
|
|
||||||
// 获取用户信息 ,如实际应用中 可以通过token通过请求接口在这里获取用户信息
|
|
||||||
getInfo(roles) {
|
|
||||||
return new Promise((resolve, reject) =>{
|
|
||||||
this.roles = roles
|
|
||||||
resolve(roles)
|
|
||||||
} )
|
|
||||||
},
|
|
||||||
// 退出
|
|
||||||
logout() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.token = null
|
|
||||||
this.userInfo = {}
|
|
||||||
this.roles = []
|
|
||||||
resolve(null)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
},
|
||||||
// 进行持久化存储
|
// 获取用户授权角色信息,实际应用中 可以通过token通过请求接口在这里获取用户信息
|
||||||
persist: {
|
getRoles() {
|
||||||
// 本地存储的名称
|
return new Promise((resolve, reject) => {
|
||||||
key: "userState",
|
// 获取权限列表 默认就是超级管理员,因为没有进行接口请求 写死
|
||||||
//保存的位置
|
this.roles = ['admin']
|
||||||
storage: window.localStorage,//localstorage
|
localStorage.roles = JSON.stringify(this.roles)
|
||||||
|
resolve(this.roles)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
// 获取用户信息 ,如实际应用中 可以通过token通过请求接口在这里获取用户信息
|
||||||
|
getInfo(roles) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.roles = roles
|
||||||
|
resolve(roles)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 退出
|
||||||
|
logout() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.token = null
|
||||||
|
this.userInfo = {}
|
||||||
|
this.roles = []
|
||||||
|
resolve(null)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 进行持久化存储
|
||||||
|
persist: {
|
||||||
|
// 本地存储的名称
|
||||||
|
key: 'userState',
|
||||||
|
//保存的位置
|
||||||
|
storage: window.localStorage, //localstorage
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,10 @@ body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
body{
|
body {
|
||||||
background: #f0f2f5;
|
background: #f0f2f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 常用 flex */
|
/* 常用 flex */
|
||||||
.flex-center {
|
.flex-center {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -30,20 +29,18 @@ body{
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 移动端的时候由于屏幕变小隐藏头部导航栏 */
|
/* 移动端的时候由于屏幕变小隐藏头部导航栏 */
|
||||||
@media screen and ( max-width: 540px ) {
|
@media screen and (max-width: 540px) {
|
||||||
.app-breadcrumb{
|
.app-breadcrumb {
|
||||||
display: none!important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** 设置滚动条 **/
|
/** 设置滚动条 **/
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 7px;
|
width: 7px;
|
||||||
height: 8px;
|
height: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
::-webkit-scrollbar-track {
|
||||||
background-color: rgb(0 0 0 / 5%);
|
background-color: rgb(0 0 0 / 5%);
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +53,6 @@ body{
|
||||||
box-shadow: inset 0 0 6px rgb(0 0 0 / 20%);
|
box-shadow: inset 0 0 6px rgb(0 0 0 / 20%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* nprogress样式 */
|
/* nprogress样式 */
|
||||||
#nprogress .bar {
|
#nprogress .bar {
|
||||||
background: $primaryColor !important;
|
background: $primaryColor !important;
|
||||||
|
|
@ -77,7 +73,7 @@ body{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.app-container-inner{
|
.app-container-inner {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
|
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
|
||||||
|
|
@ -86,12 +82,12 @@ body{
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout-horizontal{
|
.layout-horizontal {
|
||||||
.header-icon{
|
.header-icon {
|
||||||
color:#bfcbd9!important;
|
color: #bfcbd9 !important;
|
||||||
}
|
}
|
||||||
.el-dropdown-link{
|
.el-dropdown-link {
|
||||||
color:#bfcbd9!important;
|
color: #bfcbd9 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,9 +96,9 @@ body{
|
||||||
}
|
}
|
||||||
.el-dropdown:focus {
|
.el-dropdown:focus {
|
||||||
border: none;
|
border: none;
|
||||||
outline: none!important;
|
outline: none !important;
|
||||||
}
|
}
|
||||||
.svg-icon:focus {
|
.svg-icon:focus {
|
||||||
border: none!important;
|
border: none !important;
|
||||||
outline: none!important;
|
outline: none !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,24 +7,24 @@ html.dark {
|
||||||
|
|
||||||
--zb-border-light: 1px solid #4c4d4f;
|
--zb-border-light: 1px solid #4c4d4f;
|
||||||
|
|
||||||
|
body {
|
||||||
body{
|
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 编辑器
|
// 编辑器
|
||||||
.w-e-toolbar, .w-e-text-container, .w-e-menu-panel{
|
.w-e-toolbar,
|
||||||
background: none!important;
|
.w-e-text-container,
|
||||||
|
.w-e-menu-panel {
|
||||||
|
background: none !important;
|
||||||
}
|
}
|
||||||
// 富文本
|
// 富文本
|
||||||
.md{
|
.md {
|
||||||
background: none!important;
|
background: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app{
|
#app {
|
||||||
.sidebar-container{
|
.sidebar-container {
|
||||||
background: var(--el-bg-color)!important;
|
background: var(--el-bg-color) !important;
|
||||||
& .el-menu .el-sub-menu > .el-sub-menu__title,
|
& .el-menu .el-sub-menu > .el-sub-menu__title,
|
||||||
& .el-sub-menu .el-menu-item {
|
& .el-sub-menu .el-menu-item {
|
||||||
background-color: var(--el-bg-color) !important;
|
background-color: var(--el-bg-color) !important;
|
||||||
|
|
@ -32,8 +32,8 @@ html.dark {
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--el-bg-color) !important;
|
background-color: var(--el-bg-color) !important;
|
||||||
}
|
}
|
||||||
&.is-active{
|
&.is-active {
|
||||||
background-color: #060708!important;
|
background-color: #060708 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.el-sub-menu__title {
|
.el-sub-menu__title {
|
||||||
|
|
@ -44,114 +44,106 @@ html.dark {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-logo-container {
|
||||||
|
|
||||||
.sidebar-logo-container{
|
|
||||||
background: none;
|
background: none;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border:var(--zb-border-light);
|
border: var(--zb-border-light);
|
||||||
}
|
}
|
||||||
.el-drawer__header {
|
.el-drawer__header {
|
||||||
span {
|
span {
|
||||||
color: var(--el-text-color-primary) !important;
|
color: var(--el-text-color-primary) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.theme-item{
|
.theme-item {
|
||||||
color: var(--el-text-color-primary) !important;
|
color: var(--el-text-color-primary) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.el-table__header th {
|
.el-table__header th {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
.footer-layout{
|
.footer-layout {
|
||||||
background: none;
|
background: none;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.zb-pro-table {
|
||||||
.zb-pro-table{
|
.header {
|
||||||
.header{
|
background: none !important;
|
||||||
background: none!important;
|
|
||||||
border: var(--zb-border-light);
|
border: var(--zb-border-light);
|
||||||
}
|
}
|
||||||
.footer{
|
.footer {
|
||||||
background: none!important;
|
background: none !important;
|
||||||
border: var(--zb-border-light);
|
border: var(--zb-border-light);
|
||||||
}
|
}
|
||||||
.el-table__header th{
|
.el-table__header th {
|
||||||
color: white!important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// header
|
// header
|
||||||
.m-layout-header{
|
.m-layout-header {
|
||||||
color: var(--el-text-color-primary) !important;
|
color: var(--el-text-color-primary) !important;
|
||||||
.header-inner{
|
.header-inner {
|
||||||
background-color: var(--el-bg-color)!important;
|
background-color: var(--el-bg-color) !important;
|
||||||
border-bottom:var(--zb-border-light);
|
border-bottom: var(--zb-border-light);
|
||||||
.header-icon{
|
.header-icon {
|
||||||
color:#bfcbd9!important;
|
color: #bfcbd9 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// tagviews
|
// tagviews
|
||||||
.m-tags-view{
|
.m-tags-view {
|
||||||
background: var(--el-bg-color)!important;
|
background: var(--el-bg-color) !important;
|
||||||
border: var(--zb-border-light);
|
border: var(--zb-border-light);
|
||||||
border-top:none ;
|
border-top: none;
|
||||||
border-left: none;
|
border-left: none;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
.el-tabs--card>.el-tabs__header{
|
.el-tabs--card > .el-tabs__header {
|
||||||
border-bottom: none!important;
|
border-bottom: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 内容区
|
// 内容区
|
||||||
.app-main{
|
.app-main {
|
||||||
.echarts-map{
|
.echarts-map {
|
||||||
background: var(--el-bg-color)!important;
|
background: var(--el-bg-color) !important;
|
||||||
}
|
}
|
||||||
.app-echarts{
|
.app-echarts {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-container{
|
.app-container {
|
||||||
.header{
|
.header {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
.footer{
|
.footer {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.m-container-layout{
|
.m-container-layout {
|
||||||
.m-container-layout-inner{
|
.m-container-layout-inner {
|
||||||
background: none;
|
background: none;
|
||||||
color: var(--el-text-color-primary) !important;
|
color: var(--el-text-color-primary) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-group-item{
|
.item-group-item {
|
||||||
background: none!important;
|
background: none !important;
|
||||||
border: var(--zb-border-light);
|
border: var(--zb-border-light);
|
||||||
color: #cccccc;
|
color: #cccccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-container-inner{
|
.app-container-inner {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 底部
|
// 底部
|
||||||
.footer-layout{
|
.footer-layout {
|
||||||
border-top:var(--zb-border-light);
|
border-top: var(--zb-border-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 登录
|
// 登录
|
||||||
.login-container {
|
.login-container {
|
||||||
background-color: #191919 !important;
|
background-color: #191919 !important;
|
||||||
|
|
@ -164,13 +156,13 @@ html.dark {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.info-qrcode{
|
.info-qrcode {
|
||||||
background: white;
|
background: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-scrollbar{
|
.el-scrollbar {
|
||||||
border:var(--zb-border-light);
|
border: var(--zb-border-light);
|
||||||
border-top:none ;
|
border-top: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,5 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-table .el-table__header th {
|
.el-table .el-table__header th {
|
||||||
background: var(--el-fill-color-light)!important;
|
background: var(--el-fill-color-light) !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
@import './variables.scss';
|
@import './variables.scss';
|
||||||
@import './sidebar.scss';
|
@import './sidebar.scss';
|
||||||
@import './transition.scss';
|
@import './transition.scss';
|
||||||
@import "./common.scss";
|
@import './common.scss';
|
||||||
@import "./element.scss";
|
@import './element.scss';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
.layout-vertical{
|
.layout-vertical {
|
||||||
.main-container {
|
.main-container {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
transition: margin-left 0.28s;
|
transition: margin-left 0.28s;
|
||||||
|
|
@ -57,7 +57,6 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.sub-el-icon {
|
.sub-el-icon {
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
margin-left: -2px;
|
margin-left: -2px;
|
||||||
|
|
@ -225,4 +224,3 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,15 +31,13 @@
|
||||||
.sidebarLogoFade-enter-active {
|
.sidebarLogoFade-enter-active {
|
||||||
transition: opacity 1.5s;
|
transition: opacity 1.5s;
|
||||||
}
|
}
|
||||||
.sidebarLogoFade-enter-from{
|
.sidebarLogoFade-enter-from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
.sidebarLogoFade-leave-to {
|
.sidebarLogoFade-leave-to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 面包屑动画 方案1
|
// 面包屑动画 方案1
|
||||||
.breadcrumb-enter-active {
|
.breadcrumb-enter-active {
|
||||||
transition: all 0.25s;
|
transition: all 0.25s;
|
||||||
|
|
|
||||||
|
|
@ -2,60 +2,63 @@
|
||||||
* DH (http://denghao.me)
|
* DH (http://denghao.me)
|
||||||
* 2017-7-14
|
* 2017-7-14
|
||||||
*/
|
*/
|
||||||
(function (window, document) {
|
;(function (window, document) {
|
||||||
var Print = function (dom, options) {
|
var Print = function (dom, options) {
|
||||||
if (!(this instanceof Print)) return new Print(dom, options);
|
if (!(this instanceof Print)) return new Print(dom, options)
|
||||||
|
|
||||||
this.options = this.extend({
|
this.options = this.extend(
|
||||||
noPrint: '.no-print',
|
{
|
||||||
onStart: function () { },
|
noPrint: '.no-print',
|
||||||
onEnd: function () { }
|
onStart: function () {},
|
||||||
}, options);
|
onEnd: function () {},
|
||||||
|
},
|
||||||
|
options,
|
||||||
|
)
|
||||||
|
|
||||||
if ((typeof dom) === "string") {
|
if (typeof dom === 'string') {
|
||||||
this.dom = document.querySelector(dom);
|
this.dom = document.querySelector(dom)
|
||||||
} else {
|
} else {
|
||||||
this.dom = dom;
|
this.dom = dom
|
||||||
}
|
}
|
||||||
|
|
||||||
this.init();
|
this.init()
|
||||||
};
|
}
|
||||||
Print.prototype = {
|
Print.prototype = {
|
||||||
init: function () {
|
init: function () {
|
||||||
var content = this.getStyle() + this.getHtml();
|
var content = this.getStyle() + this.getHtml()
|
||||||
this.writeIframe(content);
|
this.writeIframe(content)
|
||||||
},
|
},
|
||||||
extend: function (obj, obj2) {
|
extend: function (obj, obj2) {
|
||||||
for (var k in obj2) {
|
for (var k in obj2) {
|
||||||
obj[k] = obj2[k];
|
obj[k] = obj2[k]
|
||||||
}
|
}
|
||||||
return obj;
|
return obj
|
||||||
},
|
},
|
||||||
|
|
||||||
getStyle: function () {
|
getStyle: function () {
|
||||||
var str = "",
|
var str = '',
|
||||||
styles = document.querySelectorAll('style,link');
|
styles = document.querySelectorAll('style,link')
|
||||||
for (var i = 0; i < styles.length; i++) {
|
for (var i = 0; i < styles.length; i++) {
|
||||||
str += styles[i].outerHTML;
|
str += styles[i].outerHTML
|
||||||
}
|
}
|
||||||
str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";
|
str += '<style>' + (this.options.noPrint ? this.options.noPrint : '.no-print') + '{display:none;}</style>'
|
||||||
|
|
||||||
return str;
|
return str
|
||||||
},
|
},
|
||||||
|
|
||||||
getHtml: function () {
|
getHtml: function () {
|
||||||
var inputs = document.querySelectorAll('input');
|
var inputs = document.querySelectorAll('input')
|
||||||
var textareas = document.querySelectorAll('textarea');
|
var textareas = document.querySelectorAll('textarea')
|
||||||
var selects = document.querySelectorAll('select');
|
var selects = document.querySelectorAll('select')
|
||||||
|
|
||||||
for (var k in inputs) {
|
for (var k in inputs) {
|
||||||
if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
|
if (inputs[k].type == 'checkbox' || inputs[k].type == 'radio') {
|
||||||
if (inputs[k].checked == true) {
|
if (inputs[k].checked == true) {
|
||||||
inputs[k].setAttribute('checked', "checked")
|
inputs[k].setAttribute('checked', 'checked')
|
||||||
} else {
|
} else {
|
||||||
inputs[k].removeAttribute('checked')
|
inputs[k].removeAttribute('checked')
|
||||||
}
|
}
|
||||||
} else if (inputs[k].type == "text") {
|
} else if (inputs[k].type == 'text') {
|
||||||
inputs[k].setAttribute('value', inputs[k].value)
|
inputs[k].setAttribute('value', inputs[k].value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -68,11 +71,11 @@
|
||||||
|
|
||||||
for (var k3 in selects) {
|
for (var k3 in selects) {
|
||||||
if (selects[k3].type == 'select-one') {
|
if (selects[k3].type == 'select-one') {
|
||||||
var child = selects[k3].children;
|
var child = selects[k3].children
|
||||||
for (var i in child) {
|
for (var i in child) {
|
||||||
if (child[i].tagName == 'OPTION') {
|
if (child[i].tagName == 'OPTION') {
|
||||||
if (child[i].selected == true) {
|
if (child[i].selected == true) {
|
||||||
child[i].setAttribute('selected', "selected")
|
child[i].setAttribute('selected', 'selected')
|
||||||
} else {
|
} else {
|
||||||
child[i].removeAttribute('selected')
|
child[i].removeAttribute('selected')
|
||||||
}
|
}
|
||||||
|
|
@ -81,44 +84,46 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.dom.outerHTML;
|
return this.dom.outerHTML
|
||||||
},
|
},
|
||||||
|
|
||||||
writeIframe: function (content) {
|
writeIframe: function (content) {
|
||||||
var w, doc, iframe = document.createElement('iframe'),
|
var w,
|
||||||
f = document.body.appendChild(iframe);
|
doc,
|
||||||
iframe.id = "myIframe";
|
iframe = document.createElement('iframe'),
|
||||||
iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
|
f = document.body.appendChild(iframe)
|
||||||
|
iframe.id = 'myIframe'
|
||||||
|
iframe.style = 'position:absolute;width:0;height:0;top:-10px;left:-10px;'
|
||||||
|
|
||||||
w = f.contentWindow || f.contentDocument;
|
w = f.contentWindow || f.contentDocument
|
||||||
doc = f.contentDocument || f.contentWindow.document;
|
doc = f.contentDocument || f.contentWindow.document
|
||||||
doc.open();
|
doc.open()
|
||||||
doc.write(content);
|
doc.write(content)
|
||||||
doc.close();
|
doc.close()
|
||||||
this.toPrint(w, function () {
|
this.toPrint(w, function () {
|
||||||
document.body.removeChild(iframe)
|
document.body.removeChild(iframe)
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
toPrint: function (w, cb) {
|
toPrint: function (w, cb) {
|
||||||
var _this = this;
|
var _this = this
|
||||||
w.onload = function () {
|
w.onload = function () {
|
||||||
try {
|
try {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
w.focus();
|
w.focus()
|
||||||
typeof _this.options.onStart === 'function' && _this.options.onStart();
|
typeof _this.options.onStart === 'function' && _this.options.onStart()
|
||||||
if (!w.document.execCommand('print', false, null)) {
|
if (!w.document.execCommand('print', false, null)) {
|
||||||
w.print();
|
w.print()
|
||||||
}
|
}
|
||||||
typeof _this.options.onEnd === 'function' && _this.options.onEnd();
|
typeof _this.options.onEnd === 'function' && _this.options.onEnd()
|
||||||
w.close();
|
w.close()
|
||||||
cb && cb()
|
cb && cb()
|
||||||
});
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err', err);
|
console.log('err', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
}
|
||||||
window.Print = Print;
|
window.Print = Print
|
||||||
}(window, document));
|
})(window, document)
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,32 @@
|
||||||
import Clipboard from 'clipboard'
|
import Clipboard from 'clipboard'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
|
||||||
function clipboardSuccess() {
|
function clipboardSuccess() {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '复制成功',
|
message: '复制成功',
|
||||||
type: 'success',
|
type: 'success',
|
||||||
duration: 1500
|
duration: 1500,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function clipboardError() {
|
function clipboardError() {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: '复制失败',
|
message: '复制失败',
|
||||||
type: 'error'
|
type: 'error',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function handleClipboard(text, event) {
|
export default function handleClipboard(text, event) {
|
||||||
const clipboard:any = new Clipboard(event.target, {
|
const clipboard: any = new Clipboard(event.target, {
|
||||||
text: () => text
|
text: () => text,
|
||||||
})
|
})
|
||||||
clipboard.on('success', () => {
|
clipboard.on('success', () => {
|
||||||
clipboardSuccess()
|
clipboardSuccess()
|
||||||
clipboard.destroy()
|
clipboard.destroy()
|
||||||
})
|
})
|
||||||
clipboard.on('error', () => {
|
clipboard.on('error', () => {
|
||||||
clipboardError()
|
clipboardError()
|
||||||
clipboard.destroy()
|
clipboard.destroy()
|
||||||
})
|
})
|
||||||
clipboard.onClick(event)
|
clipboard.onClick(event)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,76 +1,73 @@
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import {saveAs} from 'file-saver';
|
import { saveAs } from 'file-saver'
|
||||||
import * as ExcelJs from 'exceljs';
|
import * as ExcelJs from 'exceljs'
|
||||||
import {Workbook, Worksheet, Row, Cell} from 'exceljs';
|
import { Workbook, Worksheet, Row, Cell } from 'exceljs'
|
||||||
import JsZip from 'jszip'
|
import JsZip from 'jszip'
|
||||||
|
|
||||||
export interface IDownloadFiles2Zip {
|
export interface IDownloadFiles2Zip {
|
||||||
// 压缩包的文件名
|
// 压缩包的文件名
|
||||||
zipName: string;
|
zipName: string
|
||||||
files: IDownloadExcel[];
|
files: IDownloadExcel[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDownloadFiles2ZipWithFolder {
|
export interface IDownloadFiles2ZipWithFolder {
|
||||||
zipName: string;
|
zipName: string
|
||||||
folders: IFolder[];
|
folders: IFolder[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFolder {
|
export interface IFolder {
|
||||||
folderName: string;
|
folderName: string
|
||||||
files: IDownloadExcel[];
|
files: IDownloadExcel[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDownloadExcel {
|
export interface IDownloadExcel {
|
||||||
filename: string;
|
filename: string
|
||||||
sheets: ISheet[];
|
sheets: ISheet[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISheet {
|
export interface ISheet {
|
||||||
// sheet 的名字
|
// sheet 的名字
|
||||||
sheetName: string;
|
sheetName: string
|
||||||
// 这个 sheet 中表格的 column,类型同 antd 的 column
|
// 这个 sheet 中表格的 column,类型同 antd 的 column
|
||||||
columns: any[];
|
columns: any[]
|
||||||
// 表格的数据
|
// 表格的数据
|
||||||
dataSource: any[];
|
dataSource: any[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITableHeader {
|
export interface ITableHeader {
|
||||||
header: string;
|
header: string
|
||||||
// 用于数据匹配的 key
|
// 用于数据匹配的 key
|
||||||
key: string;
|
key: string
|
||||||
// 列宽
|
// 列宽
|
||||||
width: number;
|
width: number
|
||||||
// 父级的 key
|
// 父级的 key
|
||||||
parentKey?: string;
|
parentKey?: string
|
||||||
children?: ITableHeader[];
|
children?: ITableHeader[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IStyleAttr {
|
export interface IStyleAttr {
|
||||||
color?: string;
|
color?: string
|
||||||
fontSize?: number;
|
fontSize?: number
|
||||||
horizontal?: 'fill' | 'distributed' | 'justify' | 'center' | 'left' | 'right' | 'centerContinuous' | undefined;
|
horizontal?: 'fill' | 'distributed' | 'justify' | 'center' | 'left' | 'right' | 'centerContinuous' | undefined
|
||||||
bold?: boolean;
|
bold?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认的列宽
|
// 默认的列宽
|
||||||
export const DEFAULT_COLUMN_WIDTH = 20;
|
export const DEFAULT_COLUMN_WIDTH = 20
|
||||||
// 默认行高
|
// 默认行高
|
||||||
export const DEFAULT_ROW_HEIGHT = 20;
|
export const DEFAULT_ROW_HEIGHT = 20
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出多个文件为zip压缩包
|
* 导出多个文件为zip压缩包
|
||||||
*/
|
*/
|
||||||
export async function downloadFiles2Zip(params: IDownloadFiles2Zip) {
|
export async function downloadFiles2Zip(params: IDownloadFiles2Zip) {
|
||||||
const zip = new JsZip();
|
const zip = new JsZip()
|
||||||
// 待每个文件都写入完之后再生成 zip 文件
|
// 待每个文件都写入完之后再生成 zip 文件
|
||||||
const promises = params?.files?.map(async param => await handleEachFile(param, zip, ''))
|
const promises = params?.files?.map(async (param) => await handleEachFile(param, zip, ''))
|
||||||
await Promise.all(promises);
|
await Promise.all(promises)
|
||||||
zip.generateAsync({type: "blob"}).then(blob => {
|
zip.generateAsync({ type: 'blob' }).then((blob) => {
|
||||||
saveAs(blob, `${params.zipName}.zip`)
|
saveAs(blob, `${params.zipName}.zip`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -78,61 +75,61 @@ export async function downloadFiles2Zip(params: IDownloadFiles2Zip) {
|
||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
export async function downloadFiles2ZipWithFolder(params: IDownloadFiles2ZipWithFolder) {
|
export async function downloadFiles2ZipWithFolder(params: IDownloadFiles2ZipWithFolder) {
|
||||||
const zip = new JsZip();
|
const zip = new JsZip()
|
||||||
const outPromises = params?.folders?.map(async folder => await handleFolder(zip, folder))
|
const outPromises = params?.folders?.map(async (folder) => await handleFolder(zip, folder))
|
||||||
await Promise.all(outPromises);
|
await Promise.all(outPromises)
|
||||||
zip.generateAsync({type: "blob"}).then(blob => {
|
zip.generateAsync({ type: 'blob' }).then((blob) => {
|
||||||
saveAs(blob, `${params.zipName}.zip`)
|
saveAs(blob, `${params.zipName}.zip`)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleFolder(zip: JsZip, folder: IFolder) {
|
async function handleFolder(zip: JsZip, folder: IFolder) {
|
||||||
console.log({folder})
|
console.log({ folder })
|
||||||
const folderPromises: Promise<any>[] = [];
|
const folderPromises: Promise<any>[] = []
|
||||||
const promises = folder?.files?.map(async param => await handleEachFile(param, zip, folder.folderName));
|
const promises = folder?.files?.map(async (param) => await handleEachFile(param, zip, folder.folderName))
|
||||||
await Promise.all([...promises, ...folderPromises]);
|
await Promise.all([...promises, ...folderPromises])
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleEachFile(param: IDownloadExcel, zip: JsZip, folderName: string) {
|
async function handleEachFile(param: IDownloadExcel, zip: JsZip, folderName: string) {
|
||||||
// 创建工作簿
|
// 创建工作簿
|
||||||
const workbook = new ExcelJs.Workbook();
|
const workbook = new ExcelJs.Workbook()
|
||||||
param?.sheets?.forEach((sheet) => handleEachSheet(workbook, sheet));
|
param?.sheets?.forEach((sheet) => handleEachSheet(workbook, sheet))
|
||||||
// 生成 blob
|
// 生成 blob
|
||||||
const data = await workbook.xlsx.writeBuffer();
|
const data = await workbook.xlsx.writeBuffer()
|
||||||
const blob = new Blob([data], {type: ''});
|
const blob = new Blob([data], { type: '' })
|
||||||
if (folderName) {
|
if (folderName) {
|
||||||
zip.folder(folderName)?.file(`${param.filename}.xlsx`, blob)
|
zip.folder(folderName)?.file(`${param.filename}.xlsx`, blob)
|
||||||
} else {
|
} else {
|
||||||
// 写入 zip 中一个文件
|
// 写入 zip 中一个文件
|
||||||
zip.file(`${param.filename}.xlsx`, blob);
|
zip.file(`${param.filename}.xlsx`, blob)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEachSheet(workbook: Workbook, sheet: ISheet) {
|
function handleEachSheet(workbook: Workbook, sheet: ISheet) {
|
||||||
// 添加sheet
|
// 添加sheet
|
||||||
const worksheet = workbook.addWorksheet(sheet.sheetName);
|
const worksheet = workbook.addWorksheet(sheet.sheetName)
|
||||||
// 设置 sheet 的默认行高。设置默认行高跟自动撑开单元格冲突
|
// 设置 sheet 的默认行高。设置默认行高跟自动撑开单元格冲突
|
||||||
// worksheet.properties.defaultRowHeight = 20;
|
// worksheet.properties.defaultRowHeight = 20;
|
||||||
// 设置列
|
// 设置列
|
||||||
worksheet.columns = generateHeaders(sheet.columns);
|
worksheet.columns = generateHeaders(sheet.columns)
|
||||||
// handleHeader(worksheet);
|
// handleHeader(worksheet);
|
||||||
// handleData(worksheet, sheet);
|
// handleData(worksheet, sheet);
|
||||||
handleDataWithRender(worksheet, sheet);
|
handleDataWithRender(worksheet, sheet)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleHeader(worksheet: Worksheet) {
|
export function handleHeader(worksheet: Worksheet) {
|
||||||
// 给表头添加背景色。因为表头是第一行,可以通过 getRow(1) 来获取表头这一行
|
// 给表头添加背景色。因为表头是第一行,可以通过 getRow(1) 来获取表头这一行
|
||||||
const headerRow = worksheet.getRow(1);
|
const headerRow = worksheet.getRow(1)
|
||||||
headerRow.height = 22;
|
headerRow.height = 22
|
||||||
// 通过 cell 设置样式,更精准
|
// 通过 cell 设置样式,更精准
|
||||||
headerRow.eachCell((cell) => addCellStyle(cell, {color: 'dff8ff', fontSize: 12, horizontal: 'left'}));
|
headerRow.eachCell((cell) => addCellStyle(cell, { color: 'dff8ff', fontSize: 12, horizontal: 'left' }))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleData(worksheet: Worksheet, sheet: ISheet) {
|
export function handleData(worksheet: Worksheet, sheet: ISheet) {
|
||||||
// 添加行
|
// 添加行
|
||||||
const rows = worksheet.addRows(sheet?.dataSource);
|
const rows = worksheet.addRows(sheet?.dataSource)
|
||||||
// 设置每行的样式
|
// 设置每行的样式
|
||||||
addStyleToData(rows);
|
addStyleToData(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -141,120 +138,119 @@ export function handleData(worksheet: Worksheet, sheet: ISheet) {
|
||||||
* @param sheet
|
* @param sheet
|
||||||
*/
|
*/
|
||||||
function handleDataWithRender(worksheet: Worksheet, sheet: ISheet) {
|
function handleDataWithRender(worksheet: Worksheet, sheet: ISheet) {
|
||||||
const {dataSource, columns} = sheet;
|
const { dataSource, columns } = sheet
|
||||||
const rowsData = dataSource?.map(data => {
|
const rowsData = dataSource?.map((data) => {
|
||||||
return columns?.map(column => {
|
return columns?.map((column) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const renderResult = column?.render?.(data[column.name], data);
|
const renderResult = column?.render?.(data[column.name], data)
|
||||||
if (renderResult) {
|
if (renderResult) {
|
||||||
// 如果不是 object 说明没包裹标签,是基本类型直接返回
|
// 如果不是 object 说明没包裹标签,是基本类型直接返回
|
||||||
if (typeof renderResult !== "object") {
|
if (typeof renderResult !== 'object') {
|
||||||
return renderResult;
|
return renderResult
|
||||||
}
|
}
|
||||||
// 如果是 object 说明包裹了标签,逐级取出值
|
// 如果是 object 说明包裹了标签,逐级取出值
|
||||||
return getValueFromRender(renderResult);
|
return getValueFromRender(renderResult)
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return data[column.name];
|
return data[column.name]
|
||||||
})
|
|
||||||
})
|
})
|
||||||
console.log({rowsData})
|
})
|
||||||
// 添加行
|
console.log({ rowsData })
|
||||||
const rows = worksheet.addRows(rowsData);
|
// 添加行
|
||||||
// 设置每行的样式
|
const rows = worksheet.addRows(rowsData)
|
||||||
addStyleToData(rows);
|
// 设置每行的样式
|
||||||
|
addStyleToData(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归取出 render 里的值
|
// 递归取出 render 里的值
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
function getValueFromRender(renderResult: any) {
|
function getValueFromRender(renderResult: any) {
|
||||||
if (renderResult?.type) {
|
if (renderResult?.type) {
|
||||||
const children = renderResult?.props?.children;
|
const children = renderResult?.props?.children
|
||||||
if (children?.type) {
|
if (children?.type) {
|
||||||
return getValueFromRender(children);
|
return getValueFromRender(children)
|
||||||
} else {
|
} else {
|
||||||
return children;
|
return children
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ''
|
}
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
function addStyleToData(rows: Row[]) {
|
function addStyleToData(rows: Row[]) {
|
||||||
// 设置每行的样式
|
// 设置每行的样式
|
||||||
rows?.forEach((row) => {
|
rows?.forEach((row) => {
|
||||||
// 设置字体
|
// 设置字体
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
row.font = {
|
row.font = {
|
||||||
size: 11,
|
size: 11,
|
||||||
name: '微软雅黑',
|
name: '微软雅黑',
|
||||||
};
|
}
|
||||||
// 设置对齐方式
|
// 设置对齐方式
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
row.alignment = {
|
row.alignment = {
|
||||||
vertical: 'middle',
|
vertical: 'middle',
|
||||||
horizontal: 'left',
|
horizontal: 'left',
|
||||||
wrapText: true,
|
wrapText: true,
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveWorkbook(workbook: Workbook, fileName: string) {
|
export function saveWorkbook(workbook: Workbook, fileName: string) {
|
||||||
// 导出文件
|
// 导出文件
|
||||||
workbook.xlsx.writeBuffer().then((data: any) => {
|
workbook.xlsx.writeBuffer().then((data: any) => {
|
||||||
const blob = new Blob([data], {type: ''});
|
const blob = new Blob([data], { type: '' })
|
||||||
saveAs(blob, fileName);
|
saveAs(blob, fileName)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据 antd 的 column 生成 exceljs 的 column
|
// 根据 antd 的 column 生成 exceljs 的 column
|
||||||
export function generateHeaders(columns: any[]) {
|
export function generateHeaders(columns: any[]) {
|
||||||
return columns?.map((col) => {
|
return columns?.map((col) => {
|
||||||
const obj: ITableHeader = {
|
const obj: ITableHeader = {
|
||||||
// 显示的 name
|
// 显示的 name
|
||||||
header: col.label,
|
header: col.label,
|
||||||
// 用于数据匹配的 key
|
// 用于数据匹配的 key
|
||||||
key: col.name,
|
key: col.name,
|
||||||
// 列宽
|
// 列宽
|
||||||
width: col.width / 5 > DEFAULT_COLUMN_WIDTH ? col.width / 5 : DEFAULT_COLUMN_WIDTH,
|
width: col.width / 5 > DEFAULT_COLUMN_WIDTH ? col.width / 5 : DEFAULT_COLUMN_WIDTH,
|
||||||
};
|
}
|
||||||
if (col.children) {
|
if (col.children) {
|
||||||
obj.children = col.children?.map((item: any) => ({
|
obj.children = col.children?.map((item: any) => ({
|
||||||
key: item.name,
|
key: item.name,
|
||||||
header: item.label,
|
header: item.label,
|
||||||
width: item.width,
|
width: item.width,
|
||||||
parentKey: col.name,
|
parentKey: col.name,
|
||||||
}));
|
}))
|
||||||
}
|
}
|
||||||
return obj;
|
return obj
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getColumnNumber(width: number) {
|
export function getColumnNumber(width: number) {
|
||||||
// 需要的列数,向上取整
|
// 需要的列数,向上取整
|
||||||
return Math.ceil(width / DEFAULT_COLUMN_WIDTH);
|
return Math.ceil(width / DEFAULT_COLUMN_WIDTH)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addCellStyle(cell: Cell, attr?: IStyleAttr) {
|
export function addCellStyle(cell: Cell, attr?: IStyleAttr) {
|
||||||
const {color, fontSize, horizontal, bold} = attr || {};
|
const { color, fontSize, horizontal, bold } = attr || {}
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
cell.fill = {
|
cell.fill = {
|
||||||
type: 'pattern',
|
type: 'pattern',
|
||||||
pattern: 'solid',
|
pattern: 'solid',
|
||||||
fgColor: {argb: color},
|
fgColor: { argb: color },
|
||||||
};
|
}
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
cell.font = {
|
cell.font = {
|
||||||
bold: bold ?? true,
|
bold: bold ?? true,
|
||||||
size: fontSize ?? 11,
|
size: fontSize ?? 11,
|
||||||
name: '微软雅黑',
|
name: '微软雅黑',
|
||||||
};
|
}
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
cell.alignment = {vertical: 'middle', wrapText: true, horizontal: horizontal ?? 'left'};
|
cell.alignment = { vertical: 'middle', wrapText: true, horizontal: horizontal ?? 'left' }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addHeaderStyle(row: Row, attr?: IStyleAttr) {
|
export function addHeaderStyle(row: Row, attr?: IStyleAttr) {
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
row.height = DEFAULT_ROW_HEIGHT;
|
row.height = DEFAULT_ROW_HEIGHT
|
||||||
row.eachCell((cell) => addCellStyle(cell, attr));
|
row.eachCell((cell) => addCellStyle(cell, attr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
import { ElLoading } from 'element-plus'
|
import { ElLoading } from 'element-plus'
|
||||||
import {
|
import { Loading } from '@element-plus/icons-vue'
|
||||||
Loading
|
|
||||||
} from '@element-plus/icons-vue'
|
|
||||||
let loading = null
|
let loading = null
|
||||||
|
|
||||||
export const openLoading = (options={})=>{
|
export const openLoading = (options = {}) => {
|
||||||
const text = options.text||'加载中'
|
const text = options.text || '加载中'
|
||||||
loading = ElLoading.service({
|
loading = ElLoading.service({
|
||||||
lock: true,
|
lock: true,
|
||||||
text: text,
|
text: text,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export const closeLoading = () => {
|
export const closeLoading = () => {
|
||||||
loading&&loading.close()
|
loading && loading.close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
export default {
|
export default {
|
||||||
imgs: [
|
imgs: [
|
||||||
'爱你',
|
'爱你',
|
||||||
'爱情',
|
'爱情',
|
||||||
'爱心',
|
'爱心',
|
||||||
'傲慢',
|
'傲慢',
|
||||||
'白眼',
|
'白眼',
|
||||||
'抱拳',
|
'抱拳',
|
||||||
'鄙视',
|
'鄙视',
|
||||||
'闭嘴',
|
'闭嘴',
|
||||||
'便便',
|
'便便',
|
||||||
'擦汗',
|
'擦汗',
|
||||||
'菜刀',
|
'菜刀',
|
||||||
'差劲',
|
'差劲',
|
||||||
'呲牙',
|
'呲牙',
|
||||||
'大哭',
|
'大哭',
|
||||||
'蛋糕',
|
'蛋糕',
|
||||||
'刀',
|
'刀',
|
||||||
'得意',
|
'得意',
|
||||||
'凋谢',
|
'凋谢',
|
||||||
'发呆',
|
'发呆',
|
||||||
'NO',
|
'NO',
|
||||||
'OK',
|
'OK',
|
||||||
'发抖',
|
'发抖',
|
||||||
'发怒',
|
'发怒',
|
||||||
'饭',
|
'饭',
|
||||||
'飞吻',
|
'飞吻',
|
||||||
'奋斗',
|
'奋斗',
|
||||||
'疯了',
|
'疯了',
|
||||||
'尴尬',
|
'尴尬',
|
||||||
'勾引',
|
'勾引',
|
||||||
'鼓掌',
|
'鼓掌',
|
||||||
'哈欠',
|
'哈欠',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,279 +1,252 @@
|
||||||
import ExcelJS from 'exceljs'
|
import ExcelJS from 'exceljs'
|
||||||
const autoWidthAction = (val,width=10)=>{
|
const autoWidthAction = (val, width = 10) => {
|
||||||
if (val == null) {
|
if (val == null) {
|
||||||
width = 10;
|
width = 10
|
||||||
} else if (val.toString().charCodeAt(0) > 255) {
|
} else if (val.toString().charCodeAt(0) > 255) {
|
||||||
/*if chinese*/
|
/*if chinese*/
|
||||||
width = val.toString().length * 2;
|
width = val.toString().length * 2
|
||||||
} else {
|
} else {
|
||||||
width = val.toString().length;
|
width = val.toString().length
|
||||||
|
}
|
||||||
|
return width
|
||||||
|
}
|
||||||
|
export const exportExcel = async ({ column, data, filename, autoWidth, format }) => {
|
||||||
|
// 创建excel
|
||||||
|
const workbook = new ExcelJS.Workbook()
|
||||||
|
// 设置信息
|
||||||
|
workbook.creator = 'Me'
|
||||||
|
workbook.title = filename
|
||||||
|
workbook.created = new Date()
|
||||||
|
workbook.modified = new Date()
|
||||||
|
// 创建工作表
|
||||||
|
const worksheet = workbook.addWorksheet(filename)
|
||||||
|
// 设置列名
|
||||||
|
const columnsName = []
|
||||||
|
column.forEach((item, index) => {
|
||||||
|
const obj = {
|
||||||
|
header: item.label,
|
||||||
|
key: item.name,
|
||||||
|
width: null,
|
||||||
}
|
}
|
||||||
return width
|
if (autoWidth) {
|
||||||
}
|
const maxArr = [autoWidthAction(item.label)]
|
||||||
export const exportExcel = async ({column,data,filename,autoWidth,format})=>{
|
data.forEach((ite) => {
|
||||||
// 创建excel
|
const str = ite[item.name] || ''
|
||||||
const workbook = new ExcelJS.Workbook();
|
if (str) {
|
||||||
// 设置信息
|
maxArr.push(autoWidthAction(str))
|
||||||
workbook.creator = "Me";
|
|
||||||
workbook.title = filename;
|
|
||||||
workbook.created = new Date();
|
|
||||||
workbook.modified = new Date();
|
|
||||||
// 创建工作表
|
|
||||||
const worksheet = workbook.addWorksheet(filename);
|
|
||||||
// 设置列名
|
|
||||||
const columnsName = [];
|
|
||||||
column.forEach((item,index)=>{
|
|
||||||
const obj = {
|
|
||||||
header: item.label, key:item.name, width: null
|
|
||||||
}
|
}
|
||||||
if(autoWidth){
|
})
|
||||||
const maxArr = [autoWidthAction(item.label)]
|
obj.width = Math.max(...maxArr) + 5
|
||||||
data.forEach(ite=>{
|
|
||||||
const str = ite[item.name] ||''
|
|
||||||
if(str){
|
|
||||||
maxArr.push(autoWidthAction(str))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
obj.width = Math.max(...maxArr)+5
|
|
||||||
}
|
|
||||||
// 设置列名、键和宽度
|
|
||||||
columnsName.push(obj);
|
|
||||||
})
|
|
||||||
worksheet.columns = columnsName;
|
|
||||||
// 添加行
|
|
||||||
worksheet.addRows(data);
|
|
||||||
// 写入文件
|
|
||||||
|
|
||||||
const uint8Array =
|
|
||||||
format === "xlsx"
|
|
||||||
? await workbook.xlsx.writeBuffer()
|
|
||||||
: await workbook.csv.writeBuffer();
|
|
||||||
|
|
||||||
const blob = new Blob([uint8Array], { type: "application/octet-binary" });
|
|
||||||
if (window.navigator.msSaveOrOpenBlob) {
|
|
||||||
// msSaveOrOpenBlob方法返回boolean值
|
|
||||||
navigator.msSaveBlob(blob, filename + `.${format}`);
|
|
||||||
// 本地保存
|
|
||||||
} else {
|
|
||||||
const link = document.createElement("a"); // a标签下载
|
|
||||||
link.href = window.URL.createObjectURL(blob); // href属性指定下载链接
|
|
||||||
link.download = filename + `.${format}`; // dowload属性指定文件名
|
|
||||||
link.click(); // click()事件触发下载
|
|
||||||
window.URL.revokeObjectURL(link.href); // 释放内存
|
|
||||||
}
|
}
|
||||||
|
// 设置列名、键和宽度
|
||||||
|
columnsName.push(obj)
|
||||||
|
})
|
||||||
|
worksheet.columns = columnsName
|
||||||
|
// 添加行
|
||||||
|
worksheet.addRows(data)
|
||||||
|
// 写入文件
|
||||||
|
|
||||||
|
const uint8Array = format === 'xlsx' ? await workbook.xlsx.writeBuffer() : await workbook.csv.writeBuffer()
|
||||||
|
|
||||||
|
const blob = new Blob([uint8Array], { type: 'application/octet-binary' })
|
||||||
|
if (window.navigator.msSaveOrOpenBlob) {
|
||||||
|
// msSaveOrOpenBlob方法返回boolean值
|
||||||
|
navigator.msSaveBlob(blob, filename + `.${format}`)
|
||||||
|
// 本地保存
|
||||||
|
} else {
|
||||||
|
const link = document.createElement('a') // a标签下载
|
||||||
|
link.href = window.URL.createObjectURL(blob) // href属性指定下载链接
|
||||||
|
link.download = filename + `.${format}` // dowload属性指定文件名
|
||||||
|
link.click() // click()事件触发下载
|
||||||
|
window.URL.revokeObjectURL(link.href) // 释放内存
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export function addCellStyle(cell, attr) {
|
export function addCellStyle(cell, attr) {
|
||||||
const {color, fontSize, horizontal, bold} = attr || {};
|
const { color, fontSize, horizontal, bold } = attr || {}
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
cell.fill = {
|
cell.fill = {
|
||||||
type: 'pattern',
|
type: 'pattern',
|
||||||
pattern: 'solid',
|
pattern: 'solid',
|
||||||
fgColor: {argb: color},
|
fgColor: { argb: color },
|
||||||
};
|
}
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
cell.font = {
|
cell.font = {
|
||||||
bold: bold ?? true,
|
bold: bold ?? true,
|
||||||
size: fontSize ?? 11,
|
size: fontSize ?? 11,
|
||||||
// italic: true,
|
// italic: true,
|
||||||
// name: '微软雅黑',
|
// name: '微软雅黑',
|
||||||
color: {argb: 'ff0000'},
|
color: { argb: 'ff0000' },
|
||||||
};
|
}
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
cell.alignment = {vertical: 'middle', wrapText: true, horizontal: horizontal ?? 'left'};
|
cell.alignment = { vertical: 'middle', wrapText: true, horizontal: horizontal ?? 'left' }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const exportStyleExcel =async ({column,data,filename,autoWidth,format})=>{
|
export const exportStyleExcel = async ({ column, data, filename, autoWidth, format }) => {
|
||||||
// 创建excel
|
// 创建excel
|
||||||
const workbook = new ExcelJS.Workbook();
|
const workbook = new ExcelJS.Workbook()
|
||||||
// 设置信息
|
// 设置信息
|
||||||
workbook.creator = "Me";
|
workbook.creator = 'Me'
|
||||||
workbook.title = filename;
|
workbook.title = filename
|
||||||
workbook.created = new Date();
|
workbook.created = new Date()
|
||||||
workbook.modified = new Date();
|
workbook.modified = new Date()
|
||||||
// 创建工作表
|
// 创建工作表
|
||||||
const worksheet = workbook.addWorksheet(filename);
|
const worksheet = workbook.addWorksheet(filename)
|
||||||
// 设置列名
|
// 设置列名
|
||||||
const columnsName = [];
|
const columnsName = []
|
||||||
column.forEach((item,index)=>{
|
column.forEach((item, index) => {
|
||||||
const obj = {
|
const obj = {
|
||||||
header: item.label, key:item.name, width: null
|
header: item.label,
|
||||||
}
|
key: item.name,
|
||||||
if(autoWidth){
|
width: null,
|
||||||
const maxArr = [autoWidthAction(item.label)]
|
|
||||||
data.forEach(ite=>{
|
|
||||||
const str = ite[item.name] ||''
|
|
||||||
if(str){
|
|
||||||
maxArr.push(autoWidthAction(str))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
obj.width = Math.max(...maxArr)+5
|
|
||||||
}
|
|
||||||
// 设置列名、键和宽度
|
|
||||||
columnsName.push(obj);
|
|
||||||
})
|
|
||||||
worksheet.columns = columnsName;
|
|
||||||
// 添加行
|
|
||||||
worksheet.addRows(data);
|
|
||||||
// 写入文件
|
|
||||||
|
|
||||||
// 设置表头颜色
|
|
||||||
// 给表头添加背景色。因为表头是第一行,可以通过 getRow(1) 来获取表头这一行
|
|
||||||
const headerRow = worksheet.getRow(1);
|
|
||||||
// 通过 cell 设置样式,更精准
|
|
||||||
headerRow.eachCell((cell) => addCellStyle(cell, {color: 'dff8ff', fontSize: 12, horizontal: 'left'}));
|
|
||||||
|
|
||||||
const uint8Array =
|
|
||||||
format === "xlsx"
|
|
||||||
? await workbook.xlsx.writeBuffer()
|
|
||||||
: await workbook.csv.writeBuffer();
|
|
||||||
|
|
||||||
const blob = new Blob([uint8Array], { type: "application/octet-binary" });
|
|
||||||
if (window.navigator.msSaveOrOpenBlob) {
|
|
||||||
// msSaveOrOpenBlob方法返回boolean值
|
|
||||||
navigator.msSaveBlob(blob, filename + `.${format}`);
|
|
||||||
// 本地保存
|
|
||||||
} else {
|
|
||||||
const link = document.createElement("a"); // a标签下载
|
|
||||||
link.href = window.URL.createObjectURL(blob); // href属性指定下载链接
|
|
||||||
link.download = filename + `.${format}`; // dowload属性指定文件名
|
|
||||||
link.click(); // click()事件触发下载
|
|
||||||
window.URL.revokeObjectURL(link.href); // 释放内存
|
|
||||||
}
|
}
|
||||||
|
if (autoWidth) {
|
||||||
|
const maxArr = [autoWidthAction(item.label)]
|
||||||
|
data.forEach((ite) => {
|
||||||
|
const str = ite[item.name] || ''
|
||||||
|
if (str) {
|
||||||
|
maxArr.push(autoWidthAction(str))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
obj.width = Math.max(...maxArr) + 5
|
||||||
|
}
|
||||||
|
// 设置列名、键和宽度
|
||||||
|
columnsName.push(obj)
|
||||||
|
})
|
||||||
|
worksheet.columns = columnsName
|
||||||
|
// 添加行
|
||||||
|
worksheet.addRows(data)
|
||||||
|
// 写入文件
|
||||||
|
|
||||||
|
// 设置表头颜色
|
||||||
|
// 给表头添加背景色。因为表头是第一行,可以通过 getRow(1) 来获取表头这一行
|
||||||
|
const headerRow = worksheet.getRow(1)
|
||||||
|
// 通过 cell 设置样式,更精准
|
||||||
|
headerRow.eachCell((cell) => addCellStyle(cell, { color: 'dff8ff', fontSize: 12, horizontal: 'left' }))
|
||||||
|
|
||||||
|
const uint8Array = format === 'xlsx' ? await workbook.xlsx.writeBuffer() : await workbook.csv.writeBuffer()
|
||||||
|
|
||||||
|
const blob = new Blob([uint8Array], { type: 'application/octet-binary' })
|
||||||
|
if (window.navigator.msSaveOrOpenBlob) {
|
||||||
|
// msSaveOrOpenBlob方法返回boolean值
|
||||||
|
navigator.msSaveBlob(blob, filename + `.${format}`)
|
||||||
|
// 本地保存
|
||||||
|
} else {
|
||||||
|
const link = document.createElement('a') // a标签下载
|
||||||
|
link.href = window.URL.createObjectURL(blob) // href属性指定下载链接
|
||||||
|
link.download = filename + `.${format}` // dowload属性指定文件名
|
||||||
|
link.click() // click()事件触发下载
|
||||||
|
window.URL.revokeObjectURL(link.href) // 释放内存
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 默认的列宽
|
// 默认的列宽
|
||||||
export const DEFAULT_COLUMN_WIDTH = 20;
|
export const DEFAULT_COLUMN_WIDTH = 20
|
||||||
|
|
||||||
function getColumnNumber(width: number) {
|
function getColumnNumber(width: number) {
|
||||||
// 需要的列数,四舍五入
|
// 需要的列数,四舍五入
|
||||||
return Math.round(width / DEFAULT_COLUMN_WIDTH);
|
return Math.round(width / DEFAULT_COLUMN_WIDTH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addData(worksheet, headerKeys, headers, data) {}
|
||||||
|
|
||||||
function addData(worksheet,headerKeys,headers,data){
|
export const exportMultiHeaderExcel = ({ column, data, filename, autoWidth }) => {
|
||||||
|
// 创建excel
|
||||||
|
const workbook = new ExcelJS.Workbook()
|
||||||
|
// 创建工作表
|
||||||
|
const sheet = workbook.addWorksheet('sheet1')
|
||||||
|
|
||||||
}
|
// 添加表头
|
||||||
|
sheet.getRow(1).values = ['序号', '日期', '地址', '配送消息', , ,]
|
||||||
export const exportMultiHeaderExcel = ({column,data,filename,autoWidth})=>{
|
sheet.getRow(2).values = ['序号', '日期', '地址', '省份', '城市', '邮编']
|
||||||
// 创建excel
|
const headers = []
|
||||||
const workbook = new ExcelJS.Workbook();
|
column.forEach((item, index) => {
|
||||||
// 创建工作表
|
if (item.children) {
|
||||||
const sheet = workbook.addWorksheet("sheet1");
|
item.children.forEach((itemChild) => {
|
||||||
|
const obj = {
|
||||||
// 添加表头
|
key: itemChild.name,
|
||||||
sheet.getRow(1).values = ["序号", "日期","地址" ,"配送消息" ,,, ];
|
width: null,
|
||||||
sheet.getRow(2).values = [
|
|
||||||
"序号",
|
|
||||||
"日期",
|
|
||||||
"地址",
|
|
||||||
"省份",
|
|
||||||
"城市",
|
|
||||||
"邮编"
|
|
||||||
];
|
|
||||||
const headers = [];
|
|
||||||
column.forEach((item,index)=>{
|
|
||||||
if(item.children){
|
|
||||||
item.children.forEach(itemChild=>{
|
|
||||||
const obj = {
|
|
||||||
key:itemChild.name, width: null
|
|
||||||
}
|
|
||||||
const maxArr = [autoWidthAction(itemChild.label)]
|
|
||||||
data.forEach(ite=>{
|
|
||||||
const str = ite[itemChild.name] ||''
|
|
||||||
if(str){
|
|
||||||
maxArr.push(autoWidthAction(str))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
obj.width = Math.max(...maxArr)+5
|
|
||||||
// 设置列名、键和宽度
|
|
||||||
headers.push(obj);
|
|
||||||
})
|
|
||||||
|
|
||||||
}else {
|
|
||||||
const obj = {
|
|
||||||
key:item.name, width: null
|
|
||||||
}
|
|
||||||
const maxArr = [autoWidthAction(item.label)]
|
|
||||||
data.forEach(ite=>{
|
|
||||||
const str = ite[item.name] ||''
|
|
||||||
if(str){
|
|
||||||
maxArr.push(autoWidthAction(str))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
obj.width = Math.max(...maxArr)+5
|
|
||||||
// 设置列名、键和宽度
|
|
||||||
headers.push(obj);
|
|
||||||
}
|
}
|
||||||
})
|
const maxArr = [autoWidthAction(itemChild.label)]
|
||||||
sheet.columns = headers;
|
data.forEach((ite) => {
|
||||||
sheet.addRows(data);
|
const str = ite[itemChild.name] || ''
|
||||||
|
if (str) {
|
||||||
// 合并单元格
|
maxArr.push(autoWidthAction(str))
|
||||||
sheet.mergeCells(`D1:F1`);
|
}
|
||||||
sheet.mergeCells("A1:A2");
|
})
|
||||||
sheet.mergeCells("B1:B2");
|
obj.width = Math.max(...maxArr) + 5
|
||||||
sheet.mergeCells("C1:C2");
|
// 设置列名、键和宽度
|
||||||
// 写入文件
|
headers.push(obj)
|
||||||
workbook.xlsx.writeBuffer().then((data) => {
|
})
|
||||||
const blob = new Blob([data, { type: "application/vnd.ms-excel" }]);
|
} else {
|
||||||
if (window.navigator.msSaveOrOpenBlob) {
|
const obj = {
|
||||||
// msSaveOrOpenBlob方法返回boolean值
|
key: item.name,
|
||||||
navigator.msSaveBlob(blob, filename + ".xlsx");
|
width: null,
|
||||||
// 本地保存
|
}
|
||||||
} else {
|
const maxArr = [autoWidthAction(item.label)]
|
||||||
const link = document.createElement("a"); // a标签下载
|
data.forEach((ite) => {
|
||||||
link.href = window.URL.createObjectURL(blob); // href属性指定下载链接
|
const str = ite[item.name] || ''
|
||||||
link.download = filename + ".xlsx"; // dowload属性指定文件名
|
if (str) {
|
||||||
link.click(); // click()事件触发下载
|
maxArr.push(autoWidthAction(str))
|
||||||
window.URL.revokeObjectURL(link.href); // 释放内存
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
obj.width = Math.max(...maxArr) + 5
|
||||||
|
// 设置列名、键和宽度
|
||||||
|
headers.push(obj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
sheet.columns = headers
|
||||||
|
sheet.addRows(data)
|
||||||
|
|
||||||
|
// 合并单元格
|
||||||
|
sheet.mergeCells(`D1:F1`)
|
||||||
|
sheet.mergeCells('A1:A2')
|
||||||
|
sheet.mergeCells('B1:B2')
|
||||||
|
sheet.mergeCells('C1:C2')
|
||||||
|
// 写入文件
|
||||||
|
workbook.xlsx.writeBuffer().then((data) => {
|
||||||
|
const blob = new Blob([data, { type: 'application/vnd.ms-excel' }])
|
||||||
|
if (window.navigator.msSaveOrOpenBlob) {
|
||||||
|
// msSaveOrOpenBlob方法返回boolean值
|
||||||
|
navigator.msSaveBlob(blob, filename + '.xlsx')
|
||||||
|
// 本地保存
|
||||||
|
} else {
|
||||||
|
const link = document.createElement('a') // a标签下载
|
||||||
|
link.href = window.URL.createObjectURL(blob) // href属性指定下载链接
|
||||||
|
link.download = filename + '.xlsx' // dowload属性指定文件名
|
||||||
|
link.click() // click()事件触发下载
|
||||||
|
window.URL.revokeObjectURL(link.href) // 释放内存
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mergeColumnCell(headers, rowHeader1, rowHeader2, nameRow1, nameRow2, worksheet) {
|
||||||
|
// 当前 index 的指针
|
||||||
|
let pointer = -1
|
||||||
|
nameRow1.forEach((name, index) => {
|
||||||
|
// 当 index 小于指针时,说明这一列已经被合并过了,不能再合并
|
||||||
|
if (index <= pointer) return
|
||||||
|
// 是否应该列合并
|
||||||
|
const shouldVerticalMerge = name === nameRow2[index]
|
||||||
|
|
||||||
function mergeColumnCell(headers, rowHeader1, rowHeader2, nameRow1, nameRow2, worksheet){
|
// 是否应该行合并
|
||||||
// 当前 index 的指针
|
const shouldHorizontalMerge = index !== nameRow1.lastIndexOf(name)
|
||||||
let pointer = -1;
|
|
||||||
nameRow1.forEach((name, index) => {
|
|
||||||
// 当 index 小于指针时,说明这一列已经被合并过了,不能再合并
|
|
||||||
if (index <= pointer) return;
|
|
||||||
// 是否应该列合并
|
|
||||||
const shouldVerticalMerge = name === nameRow2[index];
|
|
||||||
|
|
||||||
|
console.log('==', name, nameRow2[index], index, nameRow1.lastIndexOf(name), shouldVerticalMerge, shouldHorizontalMerge)
|
||||||
|
|
||||||
// 是否应该行合并
|
pointer = nameRow1.lastIndexOf(name)
|
||||||
const shouldHorizontalMerge = index !== nameRow1.lastIndexOf(name);
|
if (shouldVerticalMerge && shouldHorizontalMerge) {
|
||||||
|
// 两个方向都合并
|
||||||
console.log('==',name,nameRow2[index],index,nameRow1.lastIndexOf(name),shouldVerticalMerge,shouldHorizontalMerge)
|
worksheet.mergeCells(Number(rowHeader1.number), index + 1, Number(rowHeader2.number), nameRow1.lastIndexOf(name) + 1)
|
||||||
|
console.log('==')
|
||||||
pointer = nameRow1.lastIndexOf(name);
|
} else if (shouldVerticalMerge && !shouldHorizontalMerge) {
|
||||||
if (shouldVerticalMerge && shouldHorizontalMerge) {
|
// 只在垂直方向上同一列的两行合并
|
||||||
// 两个方向都合并
|
worksheet.mergeCells(Number(rowHeader1.number), index + 1, Number(rowHeader2.number), index + 1)
|
||||||
worksheet.mergeCells(
|
} else if (!shouldVerticalMerge && shouldHorizontalMerge) {
|
||||||
Number(rowHeader1.number),
|
// 只有水平方向同一行的多列合并
|
||||||
index + 1,
|
worksheet.mergeCells(Number(rowHeader1.number), index + 1, Number(rowHeader1.number), nameRow1.lastIndexOf(name) + 1)
|
||||||
Number(rowHeader2.number),
|
// eslint-disable-next-line no-param-reassign
|
||||||
nameRow1.lastIndexOf(name) + 1,
|
const cell = rowHeader1.getCell(index + 1)
|
||||||
);
|
cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }
|
||||||
console.log('==')
|
}
|
||||||
} else if (shouldVerticalMerge && !shouldHorizontalMerge) {
|
})
|
||||||
// 只在垂直方向上同一列的两行合并
|
|
||||||
worksheet.mergeCells(Number(rowHeader1.number), index + 1, Number(rowHeader2.number), index + 1);
|
|
||||||
} else if (!shouldVerticalMerge && shouldHorizontalMerge) {
|
|
||||||
// 只有水平方向同一行的多列合并
|
|
||||||
worksheet.mergeCells(
|
|
||||||
Number(rowHeader1.number),
|
|
||||||
index + 1,
|
|
||||||
Number(rowHeader1.number),
|
|
||||||
nameRow1.lastIndexOf(name) + 1,
|
|
||||||
);
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
const cell = rowHeader1.getCell(index + 1);
|
|
||||||
cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the time to string
|
* Parse the time to string
|
||||||
* @param {(Object|string|number)} time
|
* @param {(Object|string|number)} time
|
||||||
|
|
@ -79,9 +78,7 @@ export function formatTime(time, option) {
|
||||||
if (option) {
|
if (option) {
|
||||||
return parseTime(time, option)
|
return parseTime(time, option)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
|
||||||
d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,7 +108,7 @@ export function getQueryObject(url) {
|
||||||
export function byteLength(str) {
|
export function byteLength(str) {
|
||||||
// returns the byte length of an utf8 string
|
// returns the byte length of an utf8 string
|
||||||
let s = str.length
|
let s = str.length
|
||||||
for (var i = str.length - 1; i >= 0; i--) {
|
for (let i = str.length - 1; i >= 0; i--) {
|
||||||
const code = str.charCodeAt(i)
|
const code = str.charCodeAt(i)
|
||||||
if (code > 0x7f && code <= 0x7ff) s++
|
if (code > 0x7f && code <= 0x7ff) s++
|
||||||
else if (code > 0x7ff && code <= 0xffff) s += 2
|
else if (code > 0x7ff && code <= 0xffff) s += 2
|
||||||
|
|
@ -217,8 +214,7 @@ export function toggleClass(element, className) {
|
||||||
if (nameIndex === -1) {
|
if (nameIndex === -1) {
|
||||||
classString += '' + className
|
classString += '' + className
|
||||||
} else {
|
} else {
|
||||||
classString =
|
classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length)
|
||||||
classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length)
|
|
||||||
}
|
}
|
||||||
element.className = classString
|
element.className = classString
|
||||||
}
|
}
|
||||||
|
|
@ -347,10 +343,10 @@ export function removeClass(ele, cls) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getColor() {
|
export function getColor() {
|
||||||
var str = '#'
|
let str = '#'
|
||||||
var arr = ['1', '2', '3', '4', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
|
const arr = ['1', '2', '3', '4', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
|
||||||
for (var i = 0; i < 6; i++) {
|
for (let i = 0; i < 6; i++) {
|
||||||
var num = parseInt(Math.random() * 16)
|
const num = parseInt(Math.random() * 16)
|
||||||
str += arr[num]
|
str += arr[num]
|
||||||
}
|
}
|
||||||
return str
|
return str
|
||||||
|
|
@ -360,14 +356,14 @@ export const isArray = function (value) {
|
||||||
return objToString.call(value) === '[object Array]'
|
return objToString.call(value) === '[object Array]'
|
||||||
}
|
}
|
||||||
|
|
||||||
let funProto = Function.prototype
|
const funProto = Function.prototype
|
||||||
let objProto = Object.prototype
|
const objProto = Object.prototype
|
||||||
|
|
||||||
let getPrototypeOf = Object.getPrototypeOf
|
const getPrototypeOf = Object.getPrototypeOf
|
||||||
|
|
||||||
let objToString = objProto.toString
|
const objToString = objProto.toString
|
||||||
let hasOwnProperty = objProto.hasOwnProperty
|
const hasOwnProperty = objProto.hasOwnProperty
|
||||||
let funToString = funProto.toString
|
const funToString = funProto.toString
|
||||||
// 检查给定的值是否是字符串
|
// 检查给定的值是否是字符串
|
||||||
export const isString = function (value) {
|
export const isString = function (value) {
|
||||||
return objToString.call(value) === '[object String]'
|
return objToString.call(value) === '[object String]'
|
||||||
|
|
@ -378,22 +374,20 @@ export const isPlainObject = function (value) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
let prototype = getPrototypeOf(value)
|
const prototype = getPrototypeOf(value)
|
||||||
|
|
||||||
if (prototype === null) {
|
if (prototype === null) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
let constructor = hasOwnProperty.call(prototype, 'constructor') && prototype.constructor
|
const constructor = hasOwnProperty.call(prototype, 'constructor') && prototype.constructor
|
||||||
|
|
||||||
return (
|
return typeof constructor === 'function' && funToString.call(constructor) === funToString.call(Object)
|
||||||
typeof constructor === 'function' && funToString.call(constructor) === funToString.call(Object)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 深度克隆 array 数组或 json 对象,返回克隆后的副本
|
// // 深度克隆 array 数组或 json 对象,返回克隆后的副本
|
||||||
export const deepObjClone = function (obj) {
|
export const deepObjClone = function (obj) {
|
||||||
let weakMap = new WeakMap()
|
const weakMap = new WeakMap()
|
||||||
function clone(obj) {
|
function clone(obj) {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
return obj
|
return obj
|
||||||
|
|
@ -409,11 +403,11 @@ export const deepObjClone = function (obj) {
|
||||||
if (weakMap.get(obj)) {
|
if (weakMap.get(obj)) {
|
||||||
return weakMap.get(obj)
|
return weakMap.get(obj)
|
||||||
}
|
}
|
||||||
let copy = new obj.constructor()
|
const copy = new obj.constructor()
|
||||||
weakMap.set(obj, copy)
|
weakMap.set(obj, copy)
|
||||||
for (let key in obj) {
|
for (const key in obj) {
|
||||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||||
let value = obj[key]
|
const value = obj[key]
|
||||||
copy[key] = clone(value)
|
copy[key] = clone(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -422,13 +416,12 @@ export const deepObjClone = function (obj) {
|
||||||
return clone(obj)
|
return clone(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getTimeStateStr() {
|
export function getTimeStateStr() {
|
||||||
let timeNow = new Date();
|
const timeNow = new Date()
|
||||||
let hours = timeNow.getHours();
|
const hours = timeNow.getHours()
|
||||||
if (hours >= 6 && hours <= 10) return `早上好`;
|
if (hours >= 6 && hours <= 10) return `早上好`
|
||||||
if (hours >= 10 && hours <= 14) return `中午好`;
|
if (hours >= 10 && hours <= 14) return `中午好`
|
||||||
if (hours >= 14 && hours <= 18) return `下午好`;
|
if (hours >= 14 && hours <= 18) return `下午好`
|
||||||
if (hours >= 18 && hours <= 24) return `晚上好`;
|
if (hours >= 18 && hours <= 24) return `晚上好`
|
||||||
if (hours >= 0 && hours <= 6) return `凌晨好`;
|
if (hours >= 0 && hours <= 6) return `凌晨好`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
import raf from "raf";
|
import raf from 'raf'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* requestAnimationFrame 节流
|
* requestAnimationFrame 节流
|
||||||
* scroll 和 touchmove 等事件触发很频繁,比屏幕刷新频率更快,将导致无效的渲染和重绘
|
* scroll 和 touchmove 等事件触发很频繁,比屏幕刷新频率更快,将导致无效的渲染和重绘
|
||||||
* 这里使用 requestAnimationFrame 来优化滚动处理,在一帧中只进行一次有效重绘
|
* 这里使用 requestAnimationFrame 来优化滚动处理,在一帧中只进行一次有效重绘
|
||||||
*/
|
*/
|
||||||
export default function requestAnimationFrameThrottle(callback) {
|
export default function requestAnimationFrameThrottle(callback) {
|
||||||
let id;
|
let id
|
||||||
|
|
||||||
const factory = args => () => {
|
const factory = (args) => () => {
|
||||||
id = null;
|
id = null
|
||||||
callback(...args);
|
callback(...args)
|
||||||
};
|
}
|
||||||
|
|
||||||
const throttled = (...args) => {
|
const throttled = (...args) => {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
id = raf(factory(args));
|
id = raf(factory(args))
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
throttled.cancel = () => raf.cancel(id);
|
throttled.cancel = () => raf.cancel(id)
|
||||||
|
|
||||||
return throttled;
|
return throttled
|
||||||
};
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,13 @@ export default {
|
||||||
window.addEventListener('resize', this.$_resizeHandler)
|
window.addEventListener('resize', this.$_resizeHandler)
|
||||||
|
|
||||||
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
|
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
|
||||||
this.$_sidebarElm &&
|
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||||
this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
|
|
||||||
},
|
},
|
||||||
destroyListener() {
|
destroyListener() {
|
||||||
window.removeEventListener('resize', this.$_resizeHandler)
|
window.removeEventListener('resize', this.$_resizeHandler)
|
||||||
this.$_resizeHandler = null
|
this.$_resizeHandler = null
|
||||||
|
|
||||||
this.$_sidebarElm &&
|
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
|
||||||
this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
|
|
||||||
},
|
},
|
||||||
resize() {
|
resize() {
|
||||||
const { chart } = this
|
const { chart } = this
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue