feat: 使用prettierrc对代码进行格式化
This commit is contained in:
parent
87a4ce17e1
commit
7d9af64f6d
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"vueIndentScriptAndStyle": true,
|
||||||
|
"endOfLine": "lf"
|
||||||
|
}
|
||||||
|
|
@ -1,33 +1,38 @@
|
||||||
# gin-vue-admin web
|
# gin-vue-admin web
|
||||||
|
|
||||||
## Project setup
|
## Project setup
|
||||||
|
|
||||||
```
|
```
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compiles and hot-reloads for development
|
### Compiles and hot-reloads for development
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run serve
|
npm run serve
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compiles and minifies for production
|
### Compiles and minifies for production
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run your tests
|
### Run your tests
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run test
|
npm run test
|
||||||
```
|
```
|
||||||
|
|
||||||
### Lints and fixes files
|
### Lints and fixes files
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run lint
|
npm run lint
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
整理代码结构
|
整理代码结构
|
||||||
``` lua
|
|
||||||
|
```lua
|
||||||
web
|
web
|
||||||
├── babel.config.js
|
├── babel.config.js
|
||||||
├── Dockerfile
|
├── Dockerfile
|
||||||
|
|
@ -67,7 +72,7 @@ web
|
||||||
│ │ ├── asyncRouter.js -- 动态路由相关
|
│ │ ├── asyncRouter.js -- 动态路由相关
|
||||||
│ │ ├── bus.js -- 全局mitt声明文件
|
│ │ ├── bus.js -- 全局mitt声明文件
|
||||||
│ │ ├── date.js -- 日期相关
|
│ │ ├── date.js -- 日期相关
|
||||||
│ │ ├── dictionary.js -- 获取字典方法
|
│ │ ├── dictionary.js -- 获取字典方法
|
||||||
│ │ ├── downloadImg.js -- 下载图片方法
|
│ │ ├── downloadImg.js -- 下载图片方法
|
||||||
│ │ ├── format.js -- 格式整理相关
|
│ │ ├── format.js -- 格式整理相关
|
||||||
│ │ ├── image.js -- 图片相关方法
|
│ │ ├── image.js -- 图片相关方法
|
||||||
|
|
@ -80,21 +85,21 @@ web
|
||||||
| | ├── error -- 错误
|
| | ├── error -- 错误
|
||||||
| | ├── example --上传案例
|
| | ├── example --上传案例
|
||||||
| | ├── iconList -- icon列表
|
| | ├── iconList -- icon列表
|
||||||
| | ├── init -- 初始化数据
|
| | ├── init -- 初始化数据
|
||||||
| | | ├── index -- 新版本
|
| | | ├── index -- 新版本
|
||||||
| | | ├── init -- 旧版本
|
| | | ├── init -- 旧版本
|
||||||
| | ├── layout -- layout约束页面
|
| | ├── layout -- layout约束页面
|
||||||
| | | ├── aside
|
| | | ├── aside
|
||||||
| | | ├── bottomInfo -- bottomInfo
|
| | | ├── bottomInfo -- bottomInfo
|
||||||
| | | ├── screenfull -- 全屏设置
|
| | | ├── screenfull -- 全屏设置
|
||||||
| | | ├── setting -- 系统设置
|
| | | ├── setting -- 系统设置
|
||||||
| | | └── index.vue -- base 约束
|
| | | └── index.vue -- base 约束
|
||||||
| | ├── login --登录
|
| | ├── login --登录
|
||||||
| | ├── person --个人中心
|
| | ├── person --个人中心
|
||||||
| | ├── superAdmin -- 超级管理员操作
|
| | ├── superAdmin -- 超级管理员操作
|
||||||
| | ├── system -- 系统检测页面
|
| | ├── system -- 系统检测页面
|
||||||
| | ├── systemTools -- 系统配置相关页面
|
| | ├── systemTools -- 系统配置相关页面
|
||||||
| | └── routerHolder.vue -- page 入口页面
|
| | └── routerHolder.vue -- page 入口页面
|
||||||
├── vite.config.js -- vite 配置文件
|
├── vite.config.js -- vite 配置文件
|
||||||
└── yarn.lock
|
└── yarn.lock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [
|
presets: [],
|
||||||
|
plugins: []
|
||||||
],
|
|
||||||
'plugins': [
|
|
||||||
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import js from '@eslint/js'
|
import js from '@eslint/js'
|
||||||
import pluginVue from 'eslint-plugin-vue'
|
import pluginVue from 'eslint-plugin-vue'
|
||||||
import globals from "globals"
|
import globals from 'globals'
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
js.configs.recommended,
|
js.configs.recommended,
|
||||||
|
|
@ -10,20 +10,20 @@ export default [
|
||||||
files: ['**/*.{js,mjs,jsx,vue}'],
|
files: ['**/*.{js,mjs,jsx,vue}'],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
ecmaVersion: 'latest',
|
ecmaVersion: 'latest',
|
||||||
sourceType: "module",
|
sourceType: 'module',
|
||||||
globals: globals.node
|
globals: globals.node
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"vue/max-attributes-per-line" : 0,
|
'vue/max-attributes-per-line': 0,
|
||||||
"vue/no-v-model-argument" : 0,
|
'vue/no-v-model-argument': 0,
|
||||||
"vue/multi-word-component-names": "off",
|
'vue/multi-word-component-names': 'off',
|
||||||
'no-lone-blocks': 'off',
|
'no-lone-blocks': 'off',
|
||||||
'no-extend-native': 'off',
|
'no-extend-native': 'off',
|
||||||
'no-unused-vars': ['error', { "argsIgnorePattern": '^_' }],
|
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }]
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'app/files-to-ignore',
|
name: 'app/files-to-ignore',
|
||||||
ignores: ['**/dist/**', '**/build/*.js', '**/src/assets/**', '**/public/**'],
|
ignores: ['**/dist/**', '**/build/*.js', '**/src/assets/**', '**/public/**']
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
167
web/index.html
167
web/index.html
|
|
@ -1,102 +1,115 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="zh-cn" class="transition-colors">
|
<html lang="zh-cn" class="transition-colors">
|
||||||
|
<head>
|
||||||
<head>
|
<meta charset="utf-8" />
|
||||||
<meta charset="utf-8">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta
|
||||||
<meta content="Gin,Vue,Admin.Gin-Vue-Admin,GVA,gin-vue-admin,后台管理框架,vue后台管理框架,gin-vue-admin文档,gin-vue-admin首页,gin-vue-admin" name="keywords" />
|
content="Gin,Vue,Admin.Gin-Vue-Admin,GVA,gin-vue-admin,后台管理框架,vue后台管理框架,gin-vue-admin文档,gin-vue-admin首页,gin-vue-admin"
|
||||||
<link rel="icon" href="favicon.ico">
|
name="keywords"
|
||||||
|
/>
|
||||||
|
<link rel="icon" href="favicon.ico" />
|
||||||
<title></title>
|
<title></title>
|
||||||
<style>
|
<style>
|
||||||
.transition-colors{
|
.transition-colors {
|
||||||
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
|
transition-property: color, background-color, border-color,
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
text-decoration-color, fill, stroke;
|
||||||
transition-duration: 150ms;
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
transition-duration: 150ms;
|
||||||
}
|
}
|
||||||
body{
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
--64f90c3645474bd5: #409eff;
|
--64f90c3645474bd5: #409eff;
|
||||||
|
}
|
||||||
|
#gva-loading-box {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
#loading-text {
|
||||||
|
position: absolute;
|
||||||
|
bottom: calc(50% - 100px);
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
#gva-loading-box{
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100vh;
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
#loading-text {
|
|
||||||
position: absolute;
|
|
||||||
bottom: calc(50% - 100px);
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
color: #666;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
#loading {
|
#loading {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(50% - 20px);
|
top: calc(50% - 20px);
|
||||||
left: calc(50% - 20px);
|
left: calc(50% - 20px);
|
||||||
}
|
}
|
||||||
@keyframes loader {
|
@keyframes loader {
|
||||||
0% { left: -100px }
|
0% {
|
||||||
100% { left: 110%; }
|
left: -100px;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
left: 110%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#box {
|
#box {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
background: var(--64f90c3645474bd5);
|
background: var(--64f90c3645474bd5);
|
||||||
animation: animate .5s linear infinite;
|
animation: animate 0.5s linear infinite;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
@keyframes animate {
|
@keyframes animate {
|
||||||
17% { border-bottom-right-radius: 3px; }
|
17% {
|
||||||
25% { transform: translateY(9px) rotate(22.5deg); }
|
border-bottom-right-radius: 3px;
|
||||||
50% {
|
}
|
||||||
transform: translateY(18px) scale(1,.9) rotate(45deg) ;
|
25% {
|
||||||
border-bottom-right-radius: 40px;
|
transform: translateY(9px) rotate(22.5deg);
|
||||||
}
|
}
|
||||||
75% { transform: translateY(9px) rotate(67.5deg); }
|
50% {
|
||||||
100% { transform: translateY(0) rotate(90deg); }
|
transform: translateY(18px) scale(1, 0.9) rotate(45deg);
|
||||||
|
border-bottom-right-radius: 40px;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: translateY(9px) rotate(67.5deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0) rotate(90deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#shadow {
|
#shadow {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
background: #000;
|
background: #000;
|
||||||
opacity: 0.1;
|
opacity: 0.1;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 59px;
|
top: 59px;
|
||||||
left: 0;
|
left: 0;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
animation: shadow .5s linear infinite;
|
animation: shadow 0.5s linear infinite;
|
||||||
}
|
}
|
||||||
.dark #shadow{
|
.dark #shadow {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
@keyframes shadow {
|
@keyframes shadow {
|
||||||
50% {
|
50% {
|
||||||
transform: scale(1.2,1);
|
transform: scale(1.2, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="gva-loading-box">
|
<div id="gva-loading-box">
|
||||||
<div id="loading">
|
<div id="loading">
|
||||||
<div id="shadow"></div>
|
<div id="shadow"></div>
|
||||||
<div id="box"></div>
|
<div id="box"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="loading-text">系统正在加载中,请稍候...</div>
|
<div id="loading-text">系统正在加载中,请稍候...</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="./src/main.js"></script>
|
<script type="module" src="./src/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": "./",
|
"baseUrl": "./",
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "dist"],
|
"exclude": ["node_modules", "dist"],
|
||||||
"include": ["src/**/*"]
|
"include": ["src/**/*"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
142
web/package.json
142
web/package.json
|
|
@ -1,73 +1,73 @@
|
||||||
{
|
{
|
||||||
"name": "gin-vue-admin",
|
"name": "gin-vue-admin",
|
||||||
"version": "2.7.7",
|
"version": "2.7.7",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "node openDocument.js && vite --host --mode development",
|
"serve": "node openDocument.js && vite --host --mode development",
|
||||||
"build": "vite build --mode production",
|
"build": "vite build --mode production",
|
||||||
"limit-build": "npm install increase-memory-limit-fixbug cross-env -g && npm run fix-memory-limit && node ./limit && npm run build",
|
"limit-build": "npm install increase-memory-limit-fixbug cross-env -g && npm run fix-memory-limit && node ./limit && npm run build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"fix-memory-limit": "cross-env LIMIT=4096 increase-memory-limit"
|
"fix-memory-limit": "cross-env LIMIT=4096 increase-memory-limit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"@form-create/designer": "^3.2.6",
|
"@form-create/designer": "^3.2.6",
|
||||||
"@form-create/element-ui": "^3.2.10",
|
"@form-create/element-ui": "^3.2.10",
|
||||||
"@vue-office/docx": "^1.6.2",
|
"@vue-office/docx": "^1.6.2",
|
||||||
"@vue-office/excel": "^1.7.11",
|
"@vue-office/excel": "^1.7.11",
|
||||||
"@vue-office/pdf": "^2.0.2",
|
"@vue-office/pdf": "^2.0.2",
|
||||||
"@vueuse/core": "^11.0.3",
|
"@vueuse/core": "^11.0.3",
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||||
"ace-builds": "^1.36.4",
|
"ace-builds": "^1.36.4",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
"chokidar": "^4.0.0",
|
"chokidar": "^4.0.0",
|
||||||
"core-js": "^3.38.1",
|
"core-js": "^3.38.1",
|
||||||
"default-passive-events": "^2.0.0",
|
"default-passive-events": "^2.0.0",
|
||||||
"echarts": "5.5.1",
|
"echarts": "5.5.1",
|
||||||
"element-plus": "^2.8.5",
|
"element-plus": "^2.8.5",
|
||||||
"highlight.js": "^11.10.0",
|
"highlight.js": "^11.10.0",
|
||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"marked": "14.1.1",
|
"marked": "14.1.1",
|
||||||
"marked-highlight": "^2.1.4",
|
"marked-highlight": "^2.1.4",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"pinia": "^2.2.2",
|
"pinia": "^2.2.2",
|
||||||
"qs": "^6.13.0",
|
"qs": "^6.13.0",
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
"sortablejs": "^1.15.3",
|
"sortablejs": "^1.15.3",
|
||||||
"spark-md5": "^3.0.2",
|
"spark-md5": "^3.0.2",
|
||||||
"tailwindcss": "^3.4.10",
|
"tailwindcss": "^3.4.10",
|
||||||
"vform3-builds": "^3.0.10",
|
"vform3-builds": "^3.0.10",
|
||||||
"vite-auto-import-svg": "^1.1.0",
|
"vite-auto-import-svg": "^1.1.0",
|
||||||
"vue": "^3.5.7",
|
"vue": "^3.5.7",
|
||||||
"vue-echarts": "^7.0.3",
|
"vue-echarts": "^7.0.3",
|
||||||
"vue-router": "^4.4.3",
|
"vue-router": "^4.4.3",
|
||||||
"vue3-ace-editor": "^2.2.4",
|
"vue3-ace-editor": "^2.2.4",
|
||||||
"vuedraggable": "^4.1.0"
|
"vuedraggable": "^4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/eslint-parser": "^7.25.1",
|
"@babel/eslint-parser": "^7.25.1",
|
||||||
"@eslint/js": "^9.14.0",
|
"@eslint/js": "^9.14.0",
|
||||||
"@vitejs/plugin-legacy": "^5.4.2",
|
"@vitejs/plugin-legacy": "^5.4.2",
|
||||||
"@vitejs/plugin-vue": "^5.1.4",
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
"@vue/cli-plugin-babel": "~5.0.8",
|
"@vue/cli-plugin-babel": "~5.0.8",
|
||||||
"@vue/cli-plugin-eslint": "~5.0.8",
|
"@vue/cli-plugin-eslint": "~5.0.8",
|
||||||
"@vue/cli-plugin-router": "~5.0.8",
|
"@vue/cli-plugin-router": "~5.0.8",
|
||||||
"@vue/cli-plugin-vuex": "~5.0.8",
|
"@vue/cli-plugin-vuex": "~5.0.8",
|
||||||
"@vue/cli-service": "~5.0.8",
|
"@vue/cli-service": "~5.0.8",
|
||||||
"@vue/compiler-sfc": "^3.5.1",
|
"@vue/compiler-sfc": "^3.5.1",
|
||||||
"babel-plugin-import": "^1.13.8",
|
"babel-plugin-import": "^1.13.8",
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"eslint": "^9.14.0",
|
"eslint": "^9.14.0",
|
||||||
"eslint-plugin-vue": "^9.30.0",
|
"eslint-plugin-vue": "^9.30.0",
|
||||||
"sass": "^1.78.0",
|
"sass": "^1.78.0",
|
||||||
"terser": "^5.31.6",
|
"terser": "^5.31.6",
|
||||||
"vite": "^5.4.3",
|
"vite": "^5.4.3",
|
||||||
"vite-plugin-banner": "^0.8.0",
|
"vite-plugin-banner": "^0.8.0",
|
||||||
"vite-plugin-importer": "^0.2.5",
|
"vite-plugin-importer": "^0.2.5",
|
||||||
"vite-plugin-vue-devtools": "^7.4.4"
|
"vite-plugin-vue-devtools": "^7.4.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: {
|
plugins: {
|
||||||
tailwindcss: {},
|
tailwindcss: {},
|
||||||
autoprefixer: {},
|
autoprefixer: {}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app" class="bg-gray-50 text-slate-700 dark:text-slate-500 dark:bg-slate-800">
|
<div
|
||||||
|
id="app"
|
||||||
|
class="bg-gray-50 text-slate-700 dark:text-slate-500 dark:bg-slate-800"
|
||||||
|
>
|
||||||
<el-config-provider :locale="zhCn">
|
<el-config-provider :locale="zhCn">
|
||||||
<router-view />
|
<router-view />
|
||||||
</el-config-provider>
|
</el-config-provider>
|
||||||
|
|
@ -7,35 +10,32 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||||
import {useAppStore} from "@/pinia";
|
import { useAppStore } from '@/pinia'
|
||||||
useAppStore()
|
useAppStore()
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'App'
|
name: 'App'
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
// 引入初始化样式
|
||||||
|
#app {
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
font-weight: 400 !important;
|
||||||
|
}
|
||||||
|
.el-button {
|
||||||
|
font-weight: 400 !important;
|
||||||
|
}
|
||||||
|
|
||||||
// 引入初始化样式
|
.gva-body-h {
|
||||||
#app {
|
min-height: calc(100% - 3rem);
|
||||||
height: 100vh;
|
}
|
||||||
overflow: hidden;
|
|
||||||
font-weight: 400 !important;
|
|
||||||
}
|
|
||||||
.el-button{
|
|
||||||
font-weight: 400 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gva-body-h{
|
|
||||||
min-height: calc(100% - 3rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
.gva-container{
|
|
||||||
height: calc(100% - 2.5rem);
|
|
||||||
}
|
|
||||||
.gva-container2{
|
|
||||||
height: calc(100% - 4.5rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.gva-container {
|
||||||
|
height: calc(100% - 2.5rem);
|
||||||
|
}
|
||||||
|
.gva-container2 {
|
||||||
|
height: calc(100% - 4.5rem);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,6 @@ export const freshCasbin = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const syncApi = () => {
|
export const syncApi = () => {
|
||||||
return service({
|
return service({
|
||||||
url: '/api/syncApi',
|
url: '/api/syncApi',
|
||||||
|
|
@ -153,7 +152,6 @@ export const syncApi = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const getApiGroups = () => {
|
export const getApiGroups = () => {
|
||||||
return service({
|
return service({
|
||||||
url: '/api/getApiGroups',
|
url: '/api/getApiGroups',
|
||||||
|
|
@ -169,11 +167,10 @@ export const ignoreApi = (data) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const enterSyncApi = (data) => {
|
export const enterSyncApi = (data) => {
|
||||||
return service({
|
return service({
|
||||||
url: '/api/enterSyncApi',
|
url: '/api/enterSyncApi',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ export const deleteAuthority = (data) => {
|
||||||
return service({
|
return service({
|
||||||
url: '/authority/deleteAuthority',
|
url: '/authority/deleteAuthority',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data,
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import service from '@/utils/request'
|
import service from '@/utils/request'
|
||||||
|
|
||||||
export const getAuthorityBtnApi = (data) => {
|
export const getAuthorityBtnApi = (data) => {
|
||||||
|
|
@ -24,4 +23,3 @@ export const canRemoveAuthorityBtnApi = (params) => {
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -139,28 +139,26 @@ export const pubPlug = (params) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const llmAuto = (data) => {
|
export const llmAuto = (data) => {
|
||||||
return service({
|
return service({
|
||||||
url: '/autoCode/llmAuto',
|
url: '/autoCode/llmAuto',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data:{...data,mode:'ai'},
|
data: { ...data, mode: 'ai' },
|
||||||
timeout: 1000 * 60 * 10,
|
timeout: 1000 * 60 * 10,
|
||||||
loadingOption:{
|
loadingOption: {
|
||||||
lock: true,
|
lock: true,
|
||||||
fullscreen:true,
|
fullscreen: true,
|
||||||
text: `小淼正在思考,请稍候...`,
|
text: `小淼正在思考,请稍候...`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const butler = (data) => {
|
export const butler = (data) => {
|
||||||
return service({
|
return service({
|
||||||
url: '/autoCode/llmAuto',
|
url: '/autoCode/llmAuto',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data:{...data,mode:'butler'},
|
data: { ...data, mode: 'butler' },
|
||||||
timeout: 1000 * 60 * 10,
|
timeout: 1000 * 60 * 10
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ const service = axios.create()
|
||||||
|
|
||||||
export function Commits(page) {
|
export function Commits(page) {
|
||||||
return service({
|
return service({
|
||||||
url: 'https://api.github.com/repos/flipped-aurora/gin-vue-admin/commits?page=' + page,
|
url:
|
||||||
|
'https://api.github.com/repos/flipped-aurora/gin-vue-admin/commits?page=' +
|
||||||
|
page,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,3 @@ export const reloadSystem = (data) => {
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,42 +27,41 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
defineOptions({
|
||||||
defineOptions({
|
name: 'ArrayCtrl'
|
||||||
name: 'ArrayCtrl',
|
|
||||||
})
|
|
||||||
|
|
||||||
import { nextTick, ref } from 'vue'
|
|
||||||
|
|
||||||
const inputValue = ref('')
|
|
||||||
const inputVisible = ref(false)
|
|
||||||
const InputRef = ref(null)
|
|
||||||
|
|
||||||
const modelValue = defineModel()
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
editable: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleClose = (tag) => {
|
|
||||||
modelValue.value.splice(modelValue.value.indexOf(tag), 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
const showInput = () => {
|
|
||||||
inputVisible.value = true
|
|
||||||
nextTick(() => {
|
|
||||||
InputRef.value?.input?.focus()
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
const handleInputConfirm = () => {
|
import { nextTick, ref } from 'vue'
|
||||||
if (inputValue.value) {
|
|
||||||
modelValue.value.push(inputValue.value)
|
const inputValue = ref('')
|
||||||
|
const inputVisible = ref(false)
|
||||||
|
const InputRef = ref(null)
|
||||||
|
|
||||||
|
const modelValue = defineModel()
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
editable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleClose = (tag) => {
|
||||||
|
modelValue.value.splice(modelValue.value.indexOf(tag), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const showInput = () => {
|
||||||
|
inputVisible.value = true
|
||||||
|
nextTick(() => {
|
||||||
|
InputRef.value?.input?.focus()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleInputConfirm = () => {
|
||||||
|
if (inputValue.value) {
|
||||||
|
modelValue.value.push(inputValue.value)
|
||||||
|
}
|
||||||
|
inputVisible.value = false
|
||||||
|
inputValue.value = ''
|
||||||
}
|
}
|
||||||
inputVisible.value = false
|
|
||||||
inputValue.value = ''
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,17 @@
|
||||||
未经授权的商用使用可能会被我们的资产搜索引擎爬取,并可能导致后续索赔。索赔金额将不低于高级授权费的十倍。请您遵守版权法律法规,尊重知识产权。
|
未经授权的商用使用可能会被我们的资产搜索引擎爬取,并可能导致后续索赔。索赔金额将不低于高级授权费的十倍。请您遵守版权法律法规,尊重知识产权。
|
||||||
-->
|
-->
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col md:flex-row gap-2 items-center text-sm text-slate-700 dark:text-slate-500 justify-center py-2">
|
<div
|
||||||
|
class="flex flex-col md:flex-row gap-2 items-center text-sm text-slate-700 dark:text-slate-500 justify-center py-2"
|
||||||
|
>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<span class="mr-1">Powered by</span>
|
<span class="mr-1">Powered by</span>
|
||||||
<span>
|
<span>
|
||||||
<a
|
<a
|
||||||
class="font-bold text-active"
|
class="font-bold text-active"
|
||||||
href="https://github.com/flipped-aurora/gin-vue-admin"
|
href="https://github.com/flipped-aurora/gin-vue-admin"
|
||||||
>Gin-Vue-Admin</a>
|
>Gin-Vue-Admin</a
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<slot />
|
<slot />
|
||||||
|
|
@ -20,22 +23,22 @@
|
||||||
<a
|
<a
|
||||||
class="font-bold text-active"
|
class="font-bold text-active"
|
||||||
href="https://github.com/flipped-aurora"
|
href="https://github.com/flipped-aurora"
|
||||||
>flipped-aurora团队</a>
|
>flipped-aurora团队</a
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'BottomInfo'
|
name: 'BottomInfo'
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`%c powered by %c flipped-aurorae %c`,
|
`%c powered by %c flipped-aurorae %c`,
|
||||||
'background:#0081ff; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
|
'background:#0081ff; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
|
||||||
'background:#354855; padding: 1px 5px; border-radius: 0 3px 3px 0; color: #fff; font-weight: bold;',
|
'background:#354855; padding: 1px 5px; border-radius: 0 3px 3px 0; color: #fff; font-weight: bold;',
|
||||||
'background:transparent'
|
'background:transparent'
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,43 +14,41 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, nextTick } from 'vue';
|
import { ref, nextTick } from 'vue'
|
||||||
import VCharts from 'vue-echarts';
|
import VCharts from 'vue-echarts'
|
||||||
import { useWindowResize } from '@/hooks/use-windows-resize'
|
import { useWindowResize } from '@/hooks/use-windows-resize'
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
options: {
|
options: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default() {
|
default() {
|
||||||
return {};
|
return {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
autoResize: {
|
||||||
autoResize: {
|
type: Boolean,
|
||||||
type: Boolean,
|
default: true
|
||||||
default: true,
|
},
|
||||||
},
|
width: {
|
||||||
width: {
|
type: String,
|
||||||
type: String,
|
default: '100%'
|
||||||
default: '100%',
|
},
|
||||||
},
|
height: {
|
||||||
height: {
|
type: String,
|
||||||
type: String,
|
default: '100%'
|
||||||
default: '100%',
|
}
|
||||||
},
|
})
|
||||||
});
|
const renderChart = ref(false)
|
||||||
const renderChart = ref(false);
|
|
||||||
nextTick(() => {
|
|
||||||
renderChart.value = true;
|
|
||||||
});
|
|
||||||
useWindowResize(()=>{
|
|
||||||
renderChart.value = false;
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
renderChart.value = true;
|
renderChart.value = true
|
||||||
});
|
})
|
||||||
|
useWindowResize(() => {
|
||||||
})
|
renderChart.value = false
|
||||||
|
nextTick(() => {
|
||||||
|
renderChart.value = true
|
||||||
|
})
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less"></style>
|
<style scoped lang="less"></style>
|
||||||
|
|
|
||||||
|
|
@ -10,20 +10,16 @@
|
||||||
v-model="searchInput"
|
v-model="searchInput"
|
||||||
class="quick-input"
|
class="quick-input"
|
||||||
placeholder="请输入你需要快捷到达的功能"
|
placeholder="请输入你需要快捷到达的功能"
|
||||||
>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div
|
<div v-for="(option, index) in options" :key="index">
|
||||||
v-for="(option,index) in options"
|
<div v-if="option.children.length" class="quick-title">
|
||||||
:key="index"
|
{{ option.label }}
|
||||||
>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="option.children.length"
|
v-for="(item, key) in option.children"
|
||||||
class="quick-title"
|
:key="index + '-' + key"
|
||||||
>{{ option.label }}</div>
|
|
||||||
<div
|
|
||||||
v-for="(item,key) in option.children"
|
|
||||||
:key="index+'-'+key"
|
|
||||||
class="quick-item"
|
class="quick-item"
|
||||||
@click="item.func"
|
@click="item.func"
|
||||||
>
|
>
|
||||||
|
|
@ -40,158 +36,164 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref, watch } from 'vue'
|
import { reactive, ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useRouterStore } from '@/pinia/modules/router'
|
import { useRouterStore } from '@/pinia/modules/router'
|
||||||
import { useAppStore,useUserStore } from '@/pinia'
|
import { useAppStore, useUserStore } from '@/pinia'
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'CommandMenu',
|
name: 'CommandMenu'
|
||||||
})
|
})
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRouter()
|
const route = useRouter()
|
||||||
const routerStore = useRouterStore()
|
const routerStore = useRouterStore()
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const searchInput = ref('')
|
const searchInput = ref('')
|
||||||
const options = reactive([])
|
const options = reactive([])
|
||||||
const deepMenus = (menus) => {
|
const deepMenus = (menus) => {
|
||||||
const arr = []
|
const arr = []
|
||||||
menus.forEach(menu => {
|
menus.forEach((menu) => {
|
||||||
if (menu.children && menu.children.length > 0) {
|
if (menu.children && menu.children.length > 0) {
|
||||||
arr.push(...deepMenus(menu.children))
|
arr.push(...deepMenus(menu.children))
|
||||||
} else {
|
} else {
|
||||||
if (menu.meta.title && menu.meta.title.indexOf(searchInput.value) > -1) {
|
if (
|
||||||
arr.push({
|
menu.meta.title &&
|
||||||
label: menu.meta.title,
|
menu.meta.title.indexOf(searchInput.value) > -1
|
||||||
func: () => changeRouter(menu)
|
) {
|
||||||
})
|
arr.push({
|
||||||
|
label: menu.meta.title,
|
||||||
|
func: () => changeRouter(menu)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
const addQuickMenu = () => {
|
||||||
|
const option = {
|
||||||
|
label: '跳转',
|
||||||
|
children: []
|
||||||
}
|
}
|
||||||
})
|
const menus = deepMenus(routerStore.asyncRouters[0].children)
|
||||||
return arr
|
option.children.push(...menus)
|
||||||
}
|
options.push(option)
|
||||||
|
|
||||||
const addQuickMenu = () => {
|
|
||||||
const option = {
|
|
||||||
label: '跳转',
|
|
||||||
children: []
|
|
||||||
}
|
}
|
||||||
const menus = deepMenus(routerStore.asyncRouters[0].children)
|
|
||||||
option.children.push(...menus)
|
|
||||||
options.push(option)
|
|
||||||
}
|
|
||||||
|
|
||||||
const addQuickOption = () => {
|
const addQuickOption = () => {
|
||||||
const option = {
|
const option = {
|
||||||
label: '操作',
|
label: '操作',
|
||||||
children: []
|
children: []
|
||||||
}
|
|
||||||
const quickArr = [
|
|
||||||
{
|
|
||||||
label: '亮色主题',
|
|
||||||
func: () => changeMode('light')
|
|
||||||
}, {
|
|
||||||
label: '暗色主题',
|
|
||||||
func: () => changeMode('dark')
|
|
||||||
}, {
|
|
||||||
label: '退出登录',
|
|
||||||
func: () => userStore.LoginOut()
|
|
||||||
}
|
}
|
||||||
]
|
const quickArr = [
|
||||||
option.children.push(...quickArr.filter(item => item.label.indexOf(searchInput.value) > -1))
|
{
|
||||||
options.push(option)
|
label: '亮色主题',
|
||||||
}
|
func: () => changeMode('light')
|
||||||
|
},
|
||||||
addQuickMenu()
|
{
|
||||||
addQuickOption()
|
label: '暗色主题',
|
||||||
|
func: () => changeMode('dark')
|
||||||
const open = () => {
|
},
|
||||||
dialogVisible.value = true
|
{
|
||||||
}
|
label: '退出登录',
|
||||||
|
func: () => userStore.LoginOut()
|
||||||
const changeRouter = (e) => {
|
}
|
||||||
const index = e.name
|
]
|
||||||
const query = {}
|
option.children.push(
|
||||||
const params = {}
|
...quickArr.filter((item) => item.label.indexOf(searchInput.value) > -1)
|
||||||
routerStore.routeMap[index]?.parameters &&
|
)
|
||||||
routerStore.routeMap[index]?.parameters.forEach((item) => {
|
options.push(option)
|
||||||
if (item.type === 'query') {
|
|
||||||
query[item.key] = item.value
|
|
||||||
} else {
|
|
||||||
params[item.key] = item.value
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (index === route.name) return
|
|
||||||
if (e.name.indexOf('http://') > -1 || e.name.indexOf('https://') > -1) {
|
|
||||||
window.open(e.name)
|
|
||||||
} else {
|
|
||||||
router.push({ name: index, query, params })
|
|
||||||
}
|
}
|
||||||
dialogVisible.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const changeMode = (e) => {
|
|
||||||
if (e === null) {
|
|
||||||
appStore.toggleTheme(false )
|
|
||||||
return
|
|
||||||
}
|
|
||||||
appStore.toggleTheme(true )
|
|
||||||
}
|
|
||||||
|
|
||||||
const close = () => {
|
|
||||||
dialogVisible.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({ open })
|
|
||||||
|
|
||||||
watch(searchInput, () => {
|
|
||||||
options.length = 0
|
|
||||||
addQuickMenu()
|
addQuickMenu()
|
||||||
addQuickOption()
|
addQuickOption()
|
||||||
})
|
|
||||||
|
const open = () => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeRouter = (e) => {
|
||||||
|
const index = e.name
|
||||||
|
const query = {}
|
||||||
|
const params = {}
|
||||||
|
routerStore.routeMap[index]?.parameters &&
|
||||||
|
routerStore.routeMap[index]?.parameters.forEach((item) => {
|
||||||
|
if (item.type === 'query') {
|
||||||
|
query[item.key] = item.value
|
||||||
|
} else {
|
||||||
|
params[item.key] = item.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (index === route.name) return
|
||||||
|
if (e.name.indexOf('http://') > -1 || e.name.indexOf('https://') > -1) {
|
||||||
|
window.open(e.name)
|
||||||
|
} else {
|
||||||
|
router.push({ name: index, query, params })
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeMode = (e) => {
|
||||||
|
if (e === null) {
|
||||||
|
appStore.toggleTheme(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
appStore.toggleTheme(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
dialogVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
|
||||||
|
watch(searchInput, () => {
|
||||||
|
options.length = 0
|
||||||
|
addQuickMenu()
|
||||||
|
addQuickOption()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.overlay {
|
.overlay {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
.el-dialog__header{
|
.el-dialog__header {
|
||||||
padding:0 !important;
|
padding: 0 !important;
|
||||||
margin-right:0 !important;
|
margin-right: 0 !important;
|
||||||
}
|
}
|
||||||
.el-dialog__body{
|
.el-dialog__body {
|
||||||
padding: 12px !important;
|
padding: 12px !important;
|
||||||
height: 50vh;
|
height: 50vh;
|
||||||
overflow: auto !important;
|
overflow: auto !important;
|
||||||
}
|
}
|
||||||
.quick-title{
|
.quick-title {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
.quick-input{
|
.quick-input {
|
||||||
@apply bg-gray-50 dark:bg-gray-800;
|
@apply bg-gray-50 dark:bg-gray-800;
|
||||||
color: #666;
|
color: #666;
|
||||||
border-radius: 4px 4px 0 0;
|
border-radius: 4px 4px 0 0;
|
||||||
border:none;
|
border: none;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
border-bottom: 1px solid #ddd;
|
border-bottom: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
.quick-item{
|
.quick-item {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
&:hover{
|
&:hover {
|
||||||
@apply bg-gray-200 dark:bg-slate-500;
|
@apply bg-gray-200 dark:bg-slate-500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<span class="headerAvatar ">
|
<span class="headerAvatar">
|
||||||
<template v-if="picType === 'avatar'">
|
<template v-if="picType === 'avatar'">
|
||||||
<el-avatar
|
<el-avatar v-if="userStore.userInfo.headerImg" :size="30" :src="avatar" />
|
||||||
v-if="userStore.userInfo.headerImg"
|
<el-avatar v-else :size="30" :src="noAvatar" />
|
||||||
:size="30"
|
|
||||||
:src="avatar"
|
|
||||||
/>
|
|
||||||
<el-avatar
|
|
||||||
v-else
|
|
||||||
:size="30"
|
|
||||||
:src="noAvatar"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-if="picType === 'img'">
|
<template v-if="picType === 'img'">
|
||||||
<img
|
<img v-if="userStore.userInfo.headerImg" :src="avatar" class="avatar" />
|
||||||
v-if="userStore.userInfo.headerImg"
|
<img v-else :src="noAvatar" class="avatar" />
|
||||||
:src="avatar"
|
|
||||||
class="avatar"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
v-else
|
|
||||||
:src="noAvatar"
|
|
||||||
class="avatar"
|
|
||||||
>
|
|
||||||
</template>
|
</template>
|
||||||
<template v-if="picType === 'file'">
|
<template v-if="picType === 'file'">
|
||||||
<el-image
|
<el-image
|
||||||
|
|
@ -36,69 +20,71 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import noAvatarPng from '@/assets/noBody.png'
|
import noAvatarPng from '@/assets/noBody.png'
|
||||||
import { useUserStore } from '@/pinia/modules/user'
|
import { useUserStore } from '@/pinia/modules/user'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'CustomPic'
|
name: 'CustomPic'
|
||||||
})
|
})
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
picType: {
|
picType: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: 'avatar'
|
default: 'avatar'
|
||||||
},
|
},
|
||||||
picSrc: {
|
picSrc: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
preview: {
|
preview: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const path = ref(import.meta.env.VITE_BASE_API + '/')
|
|
||||||
const noAvatar = ref(noAvatarPng)
|
|
||||||
|
|
||||||
const userStore = useUserStore()
|
|
||||||
|
|
||||||
const avatar = computed(() => {
|
|
||||||
if (props.picSrc === '') {
|
|
||||||
if (userStore.userInfo.headerImg !== '' && userStore.userInfo.headerImg.slice(0, 4) === 'http') {
|
|
||||||
return userStore.userInfo.headerImg
|
|
||||||
}
|
}
|
||||||
return path.value + userStore.userInfo.headerImg
|
})
|
||||||
} else {
|
|
||||||
if (props.picSrc !== '' && props.picSrc.slice(0, 4) === 'http') {
|
|
||||||
return props.picSrc
|
|
||||||
}
|
|
||||||
return path.value + props.picSrc
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const file = computed(() => {
|
|
||||||
if (props.picSrc && props.picSrc.slice(0, 4) !== 'http') {
|
|
||||||
return path.value + props.picSrc
|
|
||||||
}
|
|
||||||
return props.picSrc
|
|
||||||
})
|
|
||||||
const previewSrcList = computed(() => props.preview ? [file.value] : [])
|
|
||||||
|
|
||||||
|
const path = ref(import.meta.env.VITE_BASE_API + '/')
|
||||||
|
const noAvatar = ref(noAvatarPng)
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
|
const avatar = computed(() => {
|
||||||
|
if (props.picSrc === '') {
|
||||||
|
if (
|
||||||
|
userStore.userInfo.headerImg !== '' &&
|
||||||
|
userStore.userInfo.headerImg.slice(0, 4) === 'http'
|
||||||
|
) {
|
||||||
|
return userStore.userInfo.headerImg
|
||||||
|
}
|
||||||
|
return path.value + userStore.userInfo.headerImg
|
||||||
|
} else {
|
||||||
|
if (props.picSrc !== '' && props.picSrc.slice(0, 4) === 'http') {
|
||||||
|
return props.picSrc
|
||||||
|
}
|
||||||
|
return path.value + props.picSrc
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const file = computed(() => {
|
||||||
|
if (props.picSrc && props.picSrc.slice(0, 4) !== 'http') {
|
||||||
|
return path.value + props.picSrc
|
||||||
|
}
|
||||||
|
return props.picSrc
|
||||||
|
})
|
||||||
|
const previewSrcList = computed(() => (props.preview ? [file.value] : []))
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.headerAvatar{
|
.headerAvatar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
.file{
|
.file {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 80px;
|
height: 80px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,59 @@
|
||||||
<template>
|
<template>
|
||||||
<el-button
|
<el-button type="primary" icon="download" @click="exportExcelFunc"
|
||||||
type="primary"
|
>导出</el-button
|
||||||
icon="download"
|
>
|
||||||
@click="exportExcelFunc"
|
|
||||||
>导出</el-button>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
templateId: {
|
templateId: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
condition: {
|
condition: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
},
|
},
|
||||||
limit: {
|
limit: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
},
|
},
|
||||||
offset: {
|
offset: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
},
|
},
|
||||||
order: {
|
order: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
const exportExcelFunc = async() => {
|
const exportExcelFunc = async () => {
|
||||||
if (props.templateId === '') {
|
if (props.templateId === '') {
|
||||||
ElMessage.error('组件未设置模板ID')
|
ElMessage.error('组件未设置模板ID')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const baseUrl = import.meta.env.VITE_BASE_API
|
const baseUrl = import.meta.env.VITE_BASE_API
|
||||||
const paramsCopy = JSON.parse(JSON.stringify(props.condition))
|
const paramsCopy = JSON.parse(JSON.stringify(props.condition))
|
||||||
if (props.limit) {
|
if (props.limit) {
|
||||||
paramsCopy.limit = props.limit
|
paramsCopy.limit = props.limit
|
||||||
}
|
}
|
||||||
if (props.offset) {
|
if (props.offset) {
|
||||||
paramsCopy.offset = props.offset
|
paramsCopy.offset = props.offset
|
||||||
}
|
}
|
||||||
if (props.order) {
|
if (props.order) {
|
||||||
paramsCopy.order = props.order
|
paramsCopy.order = props.order
|
||||||
}
|
}
|
||||||
const params = Object.entries(paramsCopy)
|
const params = Object.entries(paramsCopy)
|
||||||
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
|
.map(
|
||||||
.join('&')
|
([key, value]) =>
|
||||||
const url = `${baseUrl}/sysExportTemplate/exportExcel?templateID=${props.templateId}${params ? '&' + params : ''}`
|
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
|
||||||
|
)
|
||||||
|
.join('&')
|
||||||
|
const url = `${baseUrl}/sysExportTemplate/exportExcel?templateID=${props.templateId}${params ? '&' + params : ''}`
|
||||||
|
|
||||||
window.open(url, '_blank')
|
window.open(url, '_blank')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,26 @@
|
||||||
<template>
|
<template>
|
||||||
<el-button
|
<el-button type="primary" icon="download" @click="exportTemplate"
|
||||||
type="primary"
|
>下载模板</el-button
|
||||||
icon="download"
|
>
|
||||||
@click="exportTemplate"
|
|
||||||
>下载模板</el-button>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
templateId: {
|
templateId: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
const exportTemplate = async() => {
|
const exportTemplate = async () => {
|
||||||
if (props.templateId === '') {
|
if (props.templateId === '') {
|
||||||
ElMessage.error('组件未设置模板ID')
|
ElMessage.error('组件未设置模板ID')
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
const baseUrl = import.meta.env.VITE_BASE_API
|
||||||
|
const url = `${baseUrl}/sysExportTemplate/exportTemplate?templateID=${props.templateId}`
|
||||||
|
window.open(url, '_blank')
|
||||||
}
|
}
|
||||||
const baseUrl = import.meta.env.VITE_BASE_API
|
|
||||||
const url = `${baseUrl}/sysExportTemplate/exportTemplate?templateID=${props.templateId}`
|
|
||||||
window.open(url, '_blank')
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -5,38 +5,32 @@
|
||||||
:on-success="handleSuccess"
|
:on-success="handleSuccess"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
>
|
>
|
||||||
<el-button
|
<el-button type="primary" icon="upload" class="ml-3"> 导入 </el-button>
|
||||||
type="primary"
|
|
||||||
icon="upload"
|
|
||||||
class="ml-3"
|
|
||||||
>
|
|
||||||
导入
|
|
||||||
</el-button>
|
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
const baseUrl = import.meta.env.VITE_BASE_API
|
const baseUrl = import.meta.env.VITE_BASE_API
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
templateId: {
|
templateId: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['on-success'])
|
||||||
|
|
||||||
|
const url = `${baseUrl}/sysExportTemplate/importExcel?templateID=${props.templateId}`
|
||||||
|
|
||||||
|
const handleSuccess = (res) => {
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage.success('导入成功')
|
||||||
|
emit('on-success')
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['on-success'])
|
|
||||||
|
|
||||||
const url = `${baseUrl}/sysExportTemplate/importExcel?templateID=${props.templateId}`
|
|
||||||
|
|
||||||
const handleSuccess = (res) => {
|
|
||||||
if (res.code === 0) {
|
|
||||||
ElMessage.success('导入成功')
|
|
||||||
emit('on-success')
|
|
||||||
} else {
|
|
||||||
ElMessage.error(res.msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,31 @@
|
||||||
<template>
|
<template>
|
||||||
<vue-office-docx
|
<vue-office-docx :src="docx" @rendered="rendered" />
|
||||||
:src="docx"
|
|
||||||
@rendered="rendered"
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'Docx'
|
name: 'Docx'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
|
|
||||||
// 引入VueOfficeDocx组件
|
// 引入VueOfficeDocx组件
|
||||||
import VueOfficeDocx from '@vue-office/docx'
|
import VueOfficeDocx from '@vue-office/docx'
|
||||||
// 引入相关样式
|
// 引入相关样式
|
||||||
import '@vue-office/docx/lib/index.css'
|
import '@vue-office/docx/lib/index.css'
|
||||||
|
|
||||||
const model = defineModel({
|
const model = defineModel({
|
||||||
type: String,
|
type: String
|
||||||
})
|
})
|
||||||
|
|
||||||
const docx = ref(null)
|
const docx = ref(null)
|
||||||
watch(
|
watch(
|
||||||
() => model,
|
() => model,
|
||||||
value => { docx.value = value },
|
(value) => {
|
||||||
{ immediate: true }
|
docx.value = value
|
||||||
)
|
},
|
||||||
const rendered = () => {
|
{ immediate: true }
|
||||||
}
|
)
|
||||||
|
const rendered = () => {}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,36 @@
|
||||||
<template>
|
<template>
|
||||||
<VueOfficeExcel :src="excel" @rendered="renderedHandler" @error="errorHandler" style="height: 100vh;width: 100vh"/>
|
<VueOfficeExcel
|
||||||
|
:src="excel"
|
||||||
|
@rendered="renderedHandler"
|
||||||
|
@error="errorHandler"
|
||||||
|
style="height: 100vh; width: 100vh"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'Excel'
|
name: 'Excel'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script setup>
|
<script setup>
|
||||||
//引入VueOfficeExcel组件
|
//引入VueOfficeExcel组件
|
||||||
import VueOfficeExcel from '@vue-office/excel'
|
import VueOfficeExcel from '@vue-office/excel'
|
||||||
//引入相关样式
|
//引入相关样式
|
||||||
import '@vue-office/excel/lib/index.css'
|
import '@vue-office/excel/lib/index.css'
|
||||||
import {ref, watch} from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => ""
|
default: () => ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const excel = ref('')
|
const excel = ref('')
|
||||||
watch(() => props.modelValue, val => excel.value = val, {immediate: true})
|
watch(
|
||||||
const renderedHandler = () => {
|
() => props.modelValue,
|
||||||
|
(val) => (excel.value = val),
|
||||||
}
|
{ immediate: true }
|
||||||
const errorHandler = () => {
|
)
|
||||||
|
const renderedHandler = () => {}
|
||||||
}
|
const errorHandler = () => {}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,49 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="border border-solid border-gray-100 h-full w-full">
|
<div class="border border-solid border-gray-100 h-full w-full">
|
||||||
<el-row>
|
<el-row>
|
||||||
<div v-if="ext==='docx'">
|
<div v-if="ext === 'docx'">
|
||||||
<Docx v-model="fullFileURL" />
|
<Docx v-model="fullFileURL" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="ext==='pdf'">
|
<div v-else-if="ext === 'pdf'">
|
||||||
<Pdf v-model="fullFileURL" />
|
<Pdf v-model="fullFileURL" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="ext==='xlsx'">
|
<div v-else-if="ext === 'xlsx'">
|
||||||
<Excel v-model="fullFileURL" />
|
<Excel v-model="fullFileURL" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="ext==='image'">
|
<div v-else-if="ext === 'image'">
|
||||||
<el-image
|
<el-image :src="fullFileURL" lazy />
|
||||||
:src="fullFileURL"
|
|
||||||
lazy
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: 'Office'
|
name: 'Office'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch, computed } from 'vue'
|
import { ref, watch, computed } from 'vue'
|
||||||
import Docx from '@/components/office/docx.vue'
|
import Docx from '@/components/office/docx.vue'
|
||||||
import Pdf from '@/components/office/pdf.vue'
|
import Pdf from '@/components/office/pdf.vue'
|
||||||
import Excel from '@/components/office/excel.vue'
|
import Excel from '@/components/office/excel.vue'
|
||||||
|
|
||||||
const path = ref(import.meta.env.VITE_BASE_API)
|
const path = ref(import.meta.env.VITE_BASE_API)
|
||||||
|
|
||||||
const model = defineModel({ type: String})
|
const model = defineModel({ type: String })
|
||||||
|
|
||||||
const fileUrl = ref('')
|
const fileUrl = ref('')
|
||||||
const ext = ref('')
|
const ext = ref('')
|
||||||
watch(
|
watch(
|
||||||
() => model,
|
() => model,
|
||||||
val => {
|
(val) => {
|
||||||
fileUrl.value = val
|
fileUrl.value = val
|
||||||
const fileExt = val.split('.')[1] || ''
|
const fileExt = val.split('.')[1] || ''
|
||||||
const image = ['png', 'jpg', 'jpeg', 'gif']
|
const image = ['png', 'jpg', 'jpeg', 'gif']
|
||||||
ext.value = image.includes(fileExt) ? 'image' : fileExt
|
ext.value = image.includes(fileExt) ? 'image' : fileExt
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
const fullFileURL = computed(() => {
|
const fullFileURL = computed(() => {
|
||||||
return path.value + '/' + fileUrl.value
|
return path.value + '/' + fileUrl.value
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,39 @@
|
||||||
<template>
|
<template>
|
||||||
<vue-office-pdf
|
<vue-office-pdf
|
||||||
|
:src="pdf"
|
||||||
:src="pdf"
|
@rendered="renderedHandler"
|
||||||
@rendered="renderedHandler"
|
@error="errorHandler"
|
||||||
@error="errorHandler"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
name: "Pdf"
|
name: 'Pdf'
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script setup>
|
<script setup>
|
||||||
import {ref, watch} from "vue"
|
import { ref, watch } from 'vue'
|
||||||
|
|
||||||
//引入VueOfficeDocx组件
|
//引入VueOfficeDocx组件
|
||||||
import VueOfficePdf from "@vue-office/pdf";
|
import VueOfficePdf from '@vue-office/pdf'
|
||||||
//引入相关样式
|
//引入相关样式
|
||||||
import '@vue-office/docx/lib/index.css'
|
import '@vue-office/docx/lib/index.css'
|
||||||
console.log("pdf===>")
|
console.log('pdf===>')
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => ""
|
default: () => ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const pdf = ref(null)
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(val) => (pdf.value = val),
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
const renderedHandler = () => {
|
||||||
|
console.log('pdf 加载成功')
|
||||||
}
|
}
|
||||||
})
|
const errorHandler = () => {
|
||||||
const pdf = ref(null)
|
console.log('pdf 错误')
|
||||||
watch(() => props.modelValue, val => pdf.value = val, {immediate: true})
|
}
|
||||||
const renderedHandler = () => {
|
</script>
|
||||||
console.log("pdf 加载成功")
|
|
||||||
}
|
|
||||||
const errorHandler = () => {
|
|
||||||
console.log("pdf 错误")
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
<Editor
|
<Editor
|
||||||
v-model="valueHtml"
|
v-model="valueHtml"
|
||||||
class="overflow-y-hidden mt-0.5"
|
class="overflow-y-hidden mt-0.5"
|
||||||
style="height: 18rem;"
|
style="height: 18rem"
|
||||||
:default-config="editorConfig"
|
:default-config="editorConfig"
|
||||||
mode="default"
|
mode="default"
|
||||||
@onCreated="handleCreated"
|
@onCreated="handleCreated"
|
||||||
|
|
@ -18,70 +18,69 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
||||||
|
|
||||||
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
const basePath = import.meta.env.VITE_BASE_API
|
||||||
|
|
||||||
const basePath = import.meta.env.VITE_BASE_API
|
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
|
||||||
|
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
||||||
|
|
||||||
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
|
import { ElMessage } from 'element-plus'
|
||||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
|
import { getUrl } from '@/utils/image'
|
||||||
|
|
||||||
import { ElMessage } from 'element-plus'
|
const emits = defineEmits(['change', 'update:modelValue'])
|
||||||
import { getUrl } from '@/utils/image'
|
|
||||||
|
|
||||||
const emits = defineEmits(['change', 'update:modelValue'])
|
const change = (editor) => {
|
||||||
|
emits('change', editor)
|
||||||
const change = (editor) => {
|
emits('update:modelValue', valueHtml.value)
|
||||||
emits('change', editor)
|
|
||||||
emits('update:modelValue', valueHtml.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const editorRef = shallowRef()
|
const props = defineProps({
|
||||||
const valueHtml = ref('')
|
modelValue: {
|
||||||
|
type: String,
|
||||||
const toolbarConfig = {}
|
default: ''
|
||||||
const editorConfig = {
|
}
|
||||||
placeholder: '请输入内容...',
|
})
|
||||||
MENU_CONF: {}
|
|
||||||
}
|
const editorRef = shallowRef()
|
||||||
editorConfig.MENU_CONF['uploadImage'] = {
|
const valueHtml = ref('')
|
||||||
fieldName: 'file',
|
|
||||||
server: basePath + '/fileUploadAndDownload/upload?noSave=1',
|
const toolbarConfig = {}
|
||||||
customInsert(res, insertFn) {
|
const editorConfig = {
|
||||||
if (res.code === 0) {
|
placeholder: '请输入内容...',
|
||||||
const urlPath = getUrl(res.data.file.url)
|
MENU_CONF: {}
|
||||||
insertFn(urlPath, res.data.file.name)
|
}
|
||||||
return
|
editorConfig.MENU_CONF['uploadImage'] = {
|
||||||
|
fieldName: 'file',
|
||||||
|
server: basePath + '/fileUploadAndDownload/upload?noSave=1',
|
||||||
|
customInsert(res, insertFn) {
|
||||||
|
if (res.code === 0) {
|
||||||
|
const urlPath = getUrl(res.data.file.url)
|
||||||
|
insertFn(urlPath, res.data.file.name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ElMessage.error(res.msg)
|
||||||
}
|
}
|
||||||
ElMessage.error(res.msg)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 组件销毁时,也及时销毁编辑器
|
// 组件销毁时,也及时销毁编辑器
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
const editor = editorRef.value
|
const editor = editorRef.value
|
||||||
if (editor == null) return
|
if (editor == null) return
|
||||||
editor.destroy()
|
editor.destroy()
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleCreated = (editor) => {
|
const handleCreated = (editor) => {
|
||||||
editorRef.value = editor
|
editorRef.value = editor
|
||||||
valueHtml.value = props.modelValue
|
valueHtml.value = props.modelValue
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.modelValue, () => {
|
|
||||||
valueHtml.value = props.modelValue
|
|
||||||
})
|
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
() => {
|
||||||
|
valueHtml.value = props.modelValue
|
||||||
|
}
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -11,48 +11,48 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
||||||
|
|
||||||
import '@wangeditor/editor/dist/css/style.css' // 引入 css
|
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
|
||||||
|
import { Editor } from '@wangeditor/editor-for-vue'
|
||||||
|
|
||||||
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
|
const emits = defineEmits(['change', 'update:modelValue'])
|
||||||
import { Editor } from '@wangeditor/editor-for-vue'
|
const editorConfig = ref({
|
||||||
|
readOnly: true
|
||||||
const emits = defineEmits(['change', 'update:modelValue'])
|
})
|
||||||
const editorConfig = ref({
|
const change = (editor) => {
|
||||||
readOnly: true
|
emits('change', editor)
|
||||||
})
|
emits('update:modelValue', valueHtml.value)
|
||||||
const change = (editor) => {
|
|
||||||
emits('change', editor)
|
|
||||||
emits('update:modelValue', valueHtml.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const editorRef = shallowRef()
|
const props = defineProps({
|
||||||
const valueHtml = ref('')
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 组件销毁时,也及时销毁编辑器
|
const editorRef = shallowRef()
|
||||||
onBeforeUnmount(() => {
|
const valueHtml = ref('')
|
||||||
const editor = editorRef.value
|
|
||||||
if (editor == null) return
|
|
||||||
editor.destroy()
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleCreated = (editor) => {
|
// 组件销毁时,也及时销毁编辑器
|
||||||
editorRef.value = editor
|
onBeforeUnmount(() => {
|
||||||
valueHtml.value = props.modelValue
|
const editor = editorRef.value
|
||||||
}
|
if (editor == null) return
|
||||||
|
editor.destroy()
|
||||||
|
})
|
||||||
|
|
||||||
watch(() => props.modelValue, () => {
|
const handleCreated = (editor) => {
|
||||||
valueHtml.value = props.modelValue
|
editorRef.value = editor
|
||||||
})
|
valueHtml.value = props.modelValue
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
() => {
|
||||||
|
valueHtml.value = props.modelValue
|
||||||
|
}
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -12,76 +12,70 @@
|
||||||
:accept="accept"
|
:accept="accept"
|
||||||
class="upload-btn"
|
class="upload-btn"
|
||||||
>
|
>
|
||||||
<el-button type="primary">
|
<el-button type="primary"> 上传文件 </el-button>
|
||||||
上传文件
|
|
||||||
</el-button>
|
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { getBaseUrl } from '@/utils/format'
|
||||||
|
|
||||||
import { ref } from 'vue'
|
defineOptions({
|
||||||
import { ElMessage } from 'element-plus'
|
name: 'UploadCommon'
|
||||||
import { getBaseUrl } from '@/utils/format'
|
})
|
||||||
|
|
||||||
defineOptions({
|
defineProps({
|
||||||
name: 'UploadCommon',
|
limit: {
|
||||||
})
|
type: Number,
|
||||||
|
default: 3
|
||||||
|
},
|
||||||
|
accept: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
defineProps({
|
const fullscreenLoading = ref(false)
|
||||||
limit: {
|
|
||||||
type: Number,
|
|
||||||
default: 3
|
|
||||||
},
|
|
||||||
accept: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
const model = defineModel({ type: Array })
|
||||||
|
|
||||||
const fullscreenLoading = ref(false)
|
const fileList = ref(model.value)
|
||||||
|
|
||||||
const model = defineModel({ type: Array })
|
const emits = defineEmits(['on-success', 'on-error'])
|
||||||
|
|
||||||
const fileList = ref(model.value)
|
const uploadSuccess = (res) => {
|
||||||
|
const { data, code } = res
|
||||||
|
if (code !== 0) {
|
||||||
|
ElMessage({
|
||||||
|
type: 'error',
|
||||||
|
message: '上传失败' + res.msg
|
||||||
|
})
|
||||||
|
fileList.value.pop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
model.value.push({
|
||||||
|
name: data.file.name,
|
||||||
|
url: data.file.url
|
||||||
|
})
|
||||||
|
emits('on-success', res)
|
||||||
|
}
|
||||||
|
|
||||||
const emits = defineEmits(['on-success', 'on-error'])
|
const uploadRemove = (file) => {
|
||||||
|
const index = model.value.indexOf(file)
|
||||||
|
if (index > -1) {
|
||||||
|
model.value.splice(index, 1)
|
||||||
|
fileList.value = model.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const uploadSuccess = (res) => {
|
const uploadError = (err) => {
|
||||||
const { data,code } = res
|
|
||||||
if(code !== 0){
|
|
||||||
ElMessage({
|
ElMessage({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: '上传失败'+res.msg
|
message: '上传失败'
|
||||||
})
|
})
|
||||||
fileList.value.pop()
|
fullscreenLoading.value = false
|
||||||
return
|
emits('on-error', err)
|
||||||
}
|
}
|
||||||
model.value.push({
|
|
||||||
name: data.file.name,
|
|
||||||
url: data.file.url
|
|
||||||
})
|
|
||||||
emits('on-success', res)
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploadRemove = (file) => {
|
|
||||||
const index = model.value.indexOf(file)
|
|
||||||
if (index > -1) {
|
|
||||||
model.value.splice(index, 1)
|
|
||||||
fileList.value = model.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploadError = (err) => {
|
|
||||||
ElMessage({
|
|
||||||
type: 'error',
|
|
||||||
message: '上传失败'
|
|
||||||
})
|
|
||||||
fullscreenLoading.value = false
|
|
||||||
emits('on-error',err)
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,15 @@
|
||||||
muted
|
muted
|
||||||
preload="metadata"
|
preload="metadata"
|
||||||
>
|
>
|
||||||
<source :src="getUrl(model) + '#t=1'">
|
<source :src="getUrl(model) + '#t=1'" />
|
||||||
</video>
|
</video>
|
||||||
|
|
||||||
<img v-if="model&&!isVideoExt(model)" class="w-full h-full" :src="getUrl(model)" alt="图片">
|
<img
|
||||||
|
v-if="model && !isVideoExt(model)"
|
||||||
|
class="w-full h-full"
|
||||||
|
:src="getUrl(model)"
|
||||||
|
alt="图片"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="model"
|
v-if="model"
|
||||||
class="left-0 top-0 hidden text-gray-600 group-hover:bg-gray-600 group-hover:bg-opacity-30 w-full h-full group-hover:flex justify-center items-center absolute z-10"
|
class="left-0 top-0 hidden text-gray-600 group-hover:bg-gray-600 group-hover:bg-opacity-30 w-full h-full group-hover:flex justify-center items-center absolute z-10"
|
||||||
|
|
@ -42,24 +47,23 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { getUrl, isVideoExt } from '@/utils/image'
|
import { getUrl, isVideoExt } from '@/utils/image'
|
||||||
import { Delete, Plus } from '@element-plus/icons-vue'
|
import { Delete, Plus } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
model: {
|
model: {
|
||||||
default: '',
|
default: '',
|
||||||
type: String
|
type: String
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emits = defineEmits(['chooseItem', 'deleteItem'])
|
||||||
|
|
||||||
|
const chooseItem = () => {
|
||||||
|
emits('chooseItem')
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const emits = defineEmits(['chooseItem', 'deleteItem'])
|
|
||||||
|
|
||||||
const chooseItem = () => {
|
|
||||||
emits('chooseItem')
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteItem = () => {
|
|
||||||
emits('deleteItem')
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const deleteItem = () => {
|
||||||
|
emits('deleteItem')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,96 +1,80 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<selectComponent
|
<selectComponent
|
||||||
v-if="!props.multiple"
|
v-if="!props.multiple"
|
||||||
:model="model"
|
:model="model"
|
||||||
@chooseItem="openChooseImg"
|
@chooseItem="openChooseImg"
|
||||||
@deleteItem="openChooseImg"
|
@deleteItem="openChooseImg"
|
||||||
/>
|
/>
|
||||||
<div
|
<div v-else class="w-full gap-4 flex flex-wrap">
|
||||||
v-else
|
|
||||||
class="w-full gap-4 flex flex-wrap"
|
|
||||||
>
|
|
||||||
<selectComponent
|
<selectComponent
|
||||||
v-for="(item, index) in model"
|
v-for="(item, index) in model"
|
||||||
:key="index"
|
:key="index"
|
||||||
:model="item"
|
:model="item"
|
||||||
@chooseItem="openChooseImg"
|
@chooseItem="openChooseImg"
|
||||||
@deleteItem="deleteImg(index)"
|
@deleteItem="deleteImg(index)"
|
||||||
/>
|
/>
|
||||||
<selectComponent
|
<selectComponent
|
||||||
v-if="model?.length < props.maxUpdateCount || props.maxUpdateCount === 0"
|
v-if="
|
||||||
@chooseItem="openChooseImg"
|
model?.length < props.maxUpdateCount || props.maxUpdateCount === 0
|
||||||
@deleteItem="openChooseImg"
|
"
|
||||||
|
@chooseItem="openChooseImg"
|
||||||
|
@deleteItem="openChooseImg"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-drawer
|
<el-drawer v-model="drawer" title="媒体库" size="650px">
|
||||||
v-model="drawer"
|
<warning-bar title="点击“文件名/备注”可以编辑文件名或者备注内容。" />
|
||||||
title="媒体库"
|
|
||||||
size="650px"
|
|
||||||
>
|
|
||||||
<warning-bar
|
|
||||||
title="点击“文件名/备注”可以编辑文件名或者备注内容。"
|
|
||||||
/>
|
|
||||||
<div class="gva-btn-list gap-2">
|
<div class="gva-btn-list gap-2">
|
||||||
<upload-common
|
<upload-common :image-common="imageCommon" @on-success="getImageList" />
|
||||||
:image-common="imageCommon"
|
|
||||||
@on-success="getImageList"
|
|
||||||
/>
|
|
||||||
<upload-image
|
<upload-image
|
||||||
:image-url="imageUrl"
|
:image-url="imageUrl"
|
||||||
:file-size="512"
|
:file-size="512"
|
||||||
:max-w-h="1080"
|
:max-w-h="1080"
|
||||||
@on-success="getImageList"
|
@on-success="getImageList"
|
||||||
/>
|
/>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="search.keyword"
|
v-model="search.keyword"
|
||||||
class="keyword"
|
class="keyword"
|
||||||
placeholder="请输入文件名或备注"
|
placeholder="请输入文件名或备注"
|
||||||
/>
|
/>
|
||||||
<el-button
|
<el-button type="primary" icon="search" @click="getImageList">
|
||||||
type="primary"
|
|
||||||
icon="search"
|
|
||||||
@click="getImageList"
|
|
||||||
>
|
|
||||||
查询
|
查询
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap gap-4">
|
<div class="flex flex-wrap gap-4">
|
||||||
<div
|
<div v-for="(item, key) in picList" :key="key" class="w-40">
|
||||||
v-for="(item,key) in picList"
|
<div
|
||||||
:key="key"
|
class="w-40 h-40 border rounded overflow-hidden border-dashed border-gray-300 cursor-pointer relative group"
|
||||||
class="w-40"
|
>
|
||||||
>
|
|
||||||
<div class="w-40 h-40 border rounded overflow-hidden border-dashed border-gray-300 cursor-pointer relative group">
|
|
||||||
<el-image
|
<el-image
|
||||||
:key="key"
|
:key="key"
|
||||||
:src="getUrl(item.url)"
|
:src="getUrl(item.url)"
|
||||||
fit="cover"
|
fit="cover"
|
||||||
class="w-full h-full relative"
|
class="w-full h-full relative"
|
||||||
@click="chooseImg(item.url)"
|
@click="chooseImg(item.url)"
|
||||||
>
|
>
|
||||||
<template #error>
|
<template #error>
|
||||||
<el-icon
|
<el-icon
|
||||||
v-if="isVideoExt(item.url || '')"
|
v-if="isVideoExt(item.url || '')"
|
||||||
:size="32"
|
:size="32"
|
||||||
class="absolute top-[calc(50%-16px)] left-[calc(50%-16px)]"
|
class="absolute top-[calc(50%-16px)] left-[calc(50%-16px)]"
|
||||||
>
|
>
|
||||||
<VideoPlay />
|
<VideoPlay />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<video
|
<video
|
||||||
v-if="isVideoExt(item.url || '')"
|
v-if="isVideoExt(item.url || '')"
|
||||||
class="w-full h-full object-cover"
|
class="w-full h-full object-cover"
|
||||||
muted
|
muted
|
||||||
preload="metadata"
|
preload="metadata"
|
||||||
@click="chooseImg(item.url)"
|
@click="chooseImg(item.url)"
|
||||||
>
|
>
|
||||||
<source :src="getUrl(item.url) + '#t=1'">
|
<source :src="getUrl(item.url) + '#t=1'" />
|
||||||
您的浏览器不支持视频播放
|
您的浏览器不支持视频播放
|
||||||
</video>
|
</video>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="w-full h-full object-cover flex items-center justify-center"
|
class="w-full h-full object-cover flex items-center justify-center"
|
||||||
>
|
>
|
||||||
<el-icon :size="32">
|
<el-icon :size="32">
|
||||||
<icon-picture />
|
<icon-picture />
|
||||||
|
|
@ -98,179 +82,206 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-image>
|
</el-image>
|
||||||
<div class="absolute -right-1 top-1 w-8 h-8 group-hover:inline-block hidden" @click="deleteCheck(item)">
|
<div
|
||||||
|
class="absolute -right-1 top-1 w-8 h-8 group-hover:inline-block hidden"
|
||||||
|
@click="deleteCheck(item)"
|
||||||
|
>
|
||||||
<el-icon :size="16"><CircleClose /></el-icon>
|
<el-icon :size="16"><CircleClose /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="overflow-hidden text-nowrap overflow-ellipsis text-center w-full"
|
class="overflow-hidden text-nowrap overflow-ellipsis text-center w-full"
|
||||||
@click="editFileNameFunc(item)"
|
@click="editFileNameFunc(item)"
|
||||||
>
|
>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:current-page="page"
|
:current-page="page"
|
||||||
:page-size="pageSize"
|
:page-size="pageSize"
|
||||||
:total="total"
|
:total="total"
|
||||||
:style="{'justify-content':'center'}"
|
:style="{ 'justify-content': 'center' }"
|
||||||
layout="total, prev, pager, next, jumper"
|
layout="total, prev, pager, next, jumper"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
/>
|
/>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { getUrl, isVideoExt } from '@/utils/image'
|
import { getUrl, isVideoExt } from '@/utils/image'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { getFileList, editFileName, deleteFile } from '@/api/fileUploadAndDownload'
|
import {
|
||||||
import UploadImage from '@/components/upload/image.vue'
|
getFileList,
|
||||||
import UploadCommon from '@/components/upload/common.vue'
|
editFileName,
|
||||||
import WarningBar from '@/components/warningBar/warningBar.vue'
|
deleteFile
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
} from '@/api/fileUploadAndDownload'
|
||||||
import { Picture as IconPicture } from '@element-plus/icons-vue'
|
import UploadImage from '@/components/upload/image.vue'
|
||||||
import selectComponent from '@/components/selectImage/selectComponent.vue'
|
import UploadCommon from '@/components/upload/common.vue'
|
||||||
|
import WarningBar from '@/components/warningBar/warningBar.vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import { Picture as IconPicture } from '@element-plus/icons-vue'
|
||||||
|
import selectComponent from '@/components/selectImage/selectComponent.vue'
|
||||||
|
|
||||||
const imageUrl = ref('')
|
const imageUrl = ref('')
|
||||||
const imageCommon = ref('')
|
const imageCommon = ref('')
|
||||||
|
|
||||||
const search = ref({})
|
const search = ref({})
|
||||||
const page = ref(1)
|
const page = ref(1)
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
const pageSize = ref(20)
|
const pageSize = ref(20)
|
||||||
|
|
||||||
const model = defineModel({ type: [String, Array] })
|
const model = defineModel({ type: [String, Array] })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
multiple: {
|
multiple: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
fileType: {
|
fileType: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
maxUpdateCount: {
|
maxUpdateCount: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const deleteImg = (index) => {
|
|
||||||
model.value.splice(index, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSizeChange = (val) => {
|
|
||||||
pageSize.value = val
|
|
||||||
getImageList()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCurrentChange = (val) => {
|
|
||||||
page.value = val
|
|
||||||
getImageList()
|
|
||||||
}
|
|
||||||
|
|
||||||
const editFileNameFunc = async(row) => {
|
|
||||||
ElMessageBox.prompt('请输入文件名或者备注', '编辑', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
inputPattern: /\S/,
|
|
||||||
inputErrorMessage: '不能为空',
|
|
||||||
inputValue: row.name
|
|
||||||
}).then(async({ value }) => {
|
|
||||||
row.name = value
|
|
||||||
const res = await editFileName(row)
|
|
||||||
if (res.code === 0) {
|
|
||||||
ElMessage({
|
|
||||||
type: 'success',
|
|
||||||
message: '编辑成功!',
|
|
||||||
})
|
|
||||||
getImageList()
|
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
|
||||||
ElMessage({
|
|
||||||
type: 'info',
|
|
||||||
message: '取消修改'
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
const drawer = ref(false)
|
const deleteImg = (index) => {
|
||||||
const picList = ref([])
|
model.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
const imageTypeList = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp']
|
const handleSizeChange = (val) => {
|
||||||
const videoTyteList = ['mp4', 'avi', 'rmvb', 'rm', 'asf', 'divx', 'mpg', 'mpeg', 'mpe', 'wmv', 'mkv', 'vob']
|
pageSize.value = val
|
||||||
|
getImageList()
|
||||||
|
}
|
||||||
|
|
||||||
const listObj = {
|
const handleCurrentChange = (val) => {
|
||||||
image: imageTypeList,
|
page.value = val
|
||||||
video: videoTyteList
|
getImageList()
|
||||||
}
|
}
|
||||||
|
|
||||||
const chooseImg = (url) => {
|
const editFileNameFunc = async (row) => {
|
||||||
if (props.fileType) {
|
ElMessageBox.prompt('请输入文件名或者备注', '编辑', {
|
||||||
const typeSuccess = listObj[props.fileType].some(item => {
|
confirmButtonText: '确定',
|
||||||
if (url.includes(item)) {
|
cancelButtonText: '取消',
|
||||||
return true
|
inputPattern: /\S/,
|
||||||
}
|
inputErrorMessage: '不能为空',
|
||||||
|
inputValue: row.name
|
||||||
})
|
})
|
||||||
if (!typeSuccess) {
|
.then(async ({ value }) => {
|
||||||
ElMessage({
|
row.name = value
|
||||||
type: 'error',
|
const res = await editFileName(row)
|
||||||
message: '当前类型不支持使用'
|
if (res.code === 0) {
|
||||||
|
ElMessage({
|
||||||
|
type: 'success',
|
||||||
|
message: '编辑成功!'
|
||||||
|
})
|
||||||
|
getImageList()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
.catch(() => {
|
||||||
|
ElMessage({
|
||||||
|
type: 'info',
|
||||||
|
message: '取消修改'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const drawer = ref(false)
|
||||||
|
const picList = ref([])
|
||||||
|
|
||||||
|
const imageTypeList = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp']
|
||||||
|
const videoTyteList = [
|
||||||
|
'mp4',
|
||||||
|
'avi',
|
||||||
|
'rmvb',
|
||||||
|
'rm',
|
||||||
|
'asf',
|
||||||
|
'divx',
|
||||||
|
'mpg',
|
||||||
|
'mpeg',
|
||||||
|
'mpe',
|
||||||
|
'wmv',
|
||||||
|
'mkv',
|
||||||
|
'vob'
|
||||||
|
]
|
||||||
|
|
||||||
|
const listObj = {
|
||||||
|
image: imageTypeList,
|
||||||
|
video: videoTyteList
|
||||||
|
}
|
||||||
|
|
||||||
|
const chooseImg = (url) => {
|
||||||
|
if (props.fileType) {
|
||||||
|
const typeSuccess = listObj[props.fileType].some((item) => {
|
||||||
|
if (url.includes(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!typeSuccess) {
|
||||||
|
ElMessage({
|
||||||
|
type: 'error',
|
||||||
|
message: '当前类型不支持使用'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (props.multiple) {
|
||||||
|
model.value.push(url)
|
||||||
|
} else {
|
||||||
|
model.value = url
|
||||||
|
}
|
||||||
|
drawer.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const openChooseImg = async () => {
|
||||||
|
if (model.value && !props.multiple) {
|
||||||
|
model.value = ''
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
await getImageList()
|
||||||
|
drawer.value = true
|
||||||
}
|
}
|
||||||
if (props.multiple) {
|
|
||||||
model.value.push(url)
|
|
||||||
} else {
|
|
||||||
model.value = url
|
|
||||||
}
|
|
||||||
drawer.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
const openChooseImg = async() => {
|
const getImageList = async () => {
|
||||||
if (model.value && !props.multiple) {
|
const res = await getFileList({
|
||||||
model.value = ''
|
page: page.value,
|
||||||
return
|
pageSize: pageSize.value,
|
||||||
}
|
...search.value
|
||||||
await getImageList()
|
|
||||||
drawer.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const getImageList = async() => {
|
|
||||||
const res = await getFileList({ page: page.value, pageSize: pageSize.value, ...search.value })
|
|
||||||
if (res.code === 0) {
|
|
||||||
picList.value = res.data.list
|
|
||||||
total.value = res.data.total
|
|
||||||
page.value = res.data.page
|
|
||||||
pageSize.value = res.data.pageSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteCheck = (item) => {
|
|
||||||
ElMessageBox.confirm('是否删除该文件', '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(async() => {
|
|
||||||
const res = await deleteFile(item)
|
|
||||||
if (res.code === 0) {
|
|
||||||
ElMessage({
|
|
||||||
type: 'success',
|
|
||||||
message: '删除成功!',
|
|
||||||
})
|
|
||||||
getImageList()
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
ElMessage({
|
|
||||||
type: 'info',
|
|
||||||
message: '已取消删除'
|
|
||||||
})
|
})
|
||||||
})
|
if (res.code === 0) {
|
||||||
}
|
picList.value = res.data.list
|
||||||
|
total.value = res.data.total
|
||||||
|
page.value = res.data.page
|
||||||
|
pageSize.value = res.data.pageSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteCheck = (item) => {
|
||||||
|
ElMessageBox.confirm('是否删除该文件', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
const res = await deleteFile(item)
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage({
|
||||||
|
type: 'success',
|
||||||
|
message: '删除成功!'
|
||||||
|
})
|
||||||
|
getImageList()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
ElMessage({
|
||||||
|
type: 'info',
|
||||||
|
message: '已取消删除'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,32 @@
|
||||||
<template>
|
<template>
|
||||||
<svg
|
<svg :class="svgClass" v-bind="$attrs" :color="color">
|
||||||
:class="svgClass"
|
<use :xlink:href="'#' + name" rel="external nofollow" />
|
||||||
v-bind="$attrs"
|
|
||||||
:color="color"
|
|
||||||
>
|
|
||||||
<use
|
|
||||||
:xlink:href="'#'+name"
|
|
||||||
rel="external nofollow"
|
|
||||||
/>
|
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
color: {
|
color: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'currentColor'
|
default: 'currentColor'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const svgClass = computed(() => {
|
const svgClass = computed(() => {
|
||||||
if (props.name) {
|
if (props.name) {
|
||||||
return `svg-icon ${props.name}`
|
return `svg-icon ${props.name}`
|
||||||
}
|
}
|
||||||
return 'svg-icon'
|
return 'svg-icon'
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
@apply w-4 h-4;
|
@apply w-4 h-4;
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -15,62 +15,61 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { isVideoMime, isImageMime } from '@/utils/image'
|
||||||
|
import { getBaseUrl } from '@/utils/format'
|
||||||
|
|
||||||
import { ref } from 'vue'
|
defineOptions({
|
||||||
import { ElMessage } from 'element-plus'
|
name: 'UploadCommon'
|
||||||
import { isVideoMime, isImageMime } from '@/utils/image'
|
|
||||||
import { getBaseUrl } from '@/utils/format'
|
|
||||||
|
|
||||||
defineOptions({
|
|
||||||
name: 'UploadCommon',
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['on-success'])
|
|
||||||
|
|
||||||
const fullscreenLoading = ref(false)
|
|
||||||
|
|
||||||
const checkFile = (file) => {
|
|
||||||
fullscreenLoading.value = true
|
|
||||||
const isLt500K = file.size / 1024 / 1024 < 0.5 // 500K, @todo 应支持在项目中设置
|
|
||||||
const isLt5M = file.size / 1024 / 1024 < 5 // 5MB, @todo 应支持项目中设置
|
|
||||||
const isVideo = isVideoMime(file.type)
|
|
||||||
const isImage = isImageMime(file.type)
|
|
||||||
let pass = true
|
|
||||||
if (!isVideo && !isImage) {
|
|
||||||
ElMessage.error('上传图片只能是 jpg,png,svg,webp 格式, 上传视频只能是 mp4,webm 格式!')
|
|
||||||
fullscreenLoading.value = false
|
|
||||||
pass = false
|
|
||||||
}
|
|
||||||
if (!isLt5M && isVideo) {
|
|
||||||
ElMessage.error('上传视频大小不能超过 5MB')
|
|
||||||
fullscreenLoading.value = false
|
|
||||||
pass = false
|
|
||||||
}
|
|
||||||
if (!isLt500K && isImage) {
|
|
||||||
ElMessage.error('未压缩的上传图片大小不能超过 500KB,请使用压缩上传')
|
|
||||||
fullscreenLoading.value = false
|
|
||||||
pass = false
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('upload file check result: ', pass)
|
|
||||||
|
|
||||||
return pass
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploadSuccess = (res) => {
|
|
||||||
const { data } = res
|
|
||||||
if (data.file) {
|
|
||||||
emit('on-success', data.file.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploadError = () => {
|
|
||||||
ElMessage({
|
|
||||||
type: 'error',
|
|
||||||
message: '上传失败'
|
|
||||||
})
|
})
|
||||||
fullscreenLoading.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const emit = defineEmits(['on-success'])
|
||||||
|
|
||||||
|
const fullscreenLoading = ref(false)
|
||||||
|
|
||||||
|
const checkFile = (file) => {
|
||||||
|
fullscreenLoading.value = true
|
||||||
|
const isLt500K = file.size / 1024 / 1024 < 0.5 // 500K, @todo 应支持在项目中设置
|
||||||
|
const isLt5M = file.size / 1024 / 1024 < 5 // 5MB, @todo 应支持项目中设置
|
||||||
|
const isVideo = isVideoMime(file.type)
|
||||||
|
const isImage = isImageMime(file.type)
|
||||||
|
let pass = true
|
||||||
|
if (!isVideo && !isImage) {
|
||||||
|
ElMessage.error(
|
||||||
|
'上传图片只能是 jpg,png,svg,webp 格式, 上传视频只能是 mp4,webm 格式!'
|
||||||
|
)
|
||||||
|
fullscreenLoading.value = false
|
||||||
|
pass = false
|
||||||
|
}
|
||||||
|
if (!isLt5M && isVideo) {
|
||||||
|
ElMessage.error('上传视频大小不能超过 5MB')
|
||||||
|
fullscreenLoading.value = false
|
||||||
|
pass = false
|
||||||
|
}
|
||||||
|
if (!isLt500K && isImage) {
|
||||||
|
ElMessage.error('未压缩的上传图片大小不能超过 500KB,请使用压缩上传')
|
||||||
|
fullscreenLoading.value = false
|
||||||
|
pass = false
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('upload file check result: ', pass)
|
||||||
|
|
||||||
|
return pass
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadSuccess = (res) => {
|
||||||
|
const { data } = res
|
||||||
|
if (data.file) {
|
||||||
|
emit('on-success', data.file.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadError = () => {
|
||||||
|
ElMessage({
|
||||||
|
type: 'error',
|
||||||
|
message: '上传失败'
|
||||||
|
})
|
||||||
|
fullscreenLoading.value = false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<el-upload
|
<el-upload
|
||||||
|
|
@ -14,79 +13,78 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import ImageCompress from '@/utils/image'
|
import ImageCompress from '@/utils/image'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { getBaseUrl } from '@/utils/format'
|
import { getBaseUrl } from '@/utils/format'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'UploadImage',
|
name: 'UploadImage'
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['on-success'])
|
const emit = defineEmits(['on-success'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
imageUrl: {
|
imageUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
fileSize: {
|
fileSize: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 2048 // 2M 超出后执行压缩
|
default: 2048 // 2M 超出后执行压缩
|
||||||
},
|
},
|
||||||
maxWH: {
|
maxWH: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1920 // 图片长宽上限
|
default: 1920 // 图片长宽上限
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const beforeImageUpload = (file) => {
|
const beforeImageUpload = (file) => {
|
||||||
const isJPG = file.type === 'image/jpeg'
|
const isJPG = file.type === 'image/jpeg'
|
||||||
const isPng = file.type === 'image/png'
|
const isPng = file.type === 'image/png'
|
||||||
if (!isJPG && !isPng) {
|
if (!isJPG && !isPng) {
|
||||||
ElMessage.error('上传头像图片只能是 jpg或png 格式!')
|
ElMessage.error('上传头像图片只能是 jpg或png 格式!')
|
||||||
return false
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const isRightSize = file.size / 1024 < props.fileSize
|
||||||
|
if (!isRightSize) {
|
||||||
|
// 压缩
|
||||||
|
const compress = new ImageCompress(file, props.fileSize, props.maxWH)
|
||||||
|
return compress.compress()
|
||||||
|
}
|
||||||
|
return isRightSize
|
||||||
}
|
}
|
||||||
|
|
||||||
const isRightSize = file.size / 1024 < props.fileSize
|
const handleImageSuccess = (res) => {
|
||||||
if (!isRightSize) {
|
const { data } = res
|
||||||
// 压缩
|
if (data.file) {
|
||||||
const compress = new ImageCompress(file, props.fileSize, props.maxWH)
|
emit('on-success', data.file.url)
|
||||||
return compress.compress()
|
}
|
||||||
}
|
}
|
||||||
return isRightSize
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleImageSuccess = (res) => {
|
|
||||||
const { data } = res
|
|
||||||
if (data.file) {
|
|
||||||
emit('on-success', data.file.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.image-uploader {
|
.image-uploader {
|
||||||
border: 1px dashed #d9d9d9;
|
border: 1px dashed #d9d9d9;
|
||||||
width: 180px;
|
width: 180px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.image-uploader {
|
.image-uploader {
|
||||||
border-color: #409eff;
|
border-color: #409eff;
|
||||||
}
|
}
|
||||||
.image-uploader-icon {
|
.image-uploader-icon {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
color: #8c939d;
|
color: #8c939d;
|
||||||
width: 178px;
|
width: 178px;
|
||||||
height: 178px;
|
height: 178px;
|
||||||
line-height: 178px;
|
line-height: 178px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.image {
|
.image {
|
||||||
width: 178px;
|
width: 178px;
|
||||||
height: 178px;
|
height: 178px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="px-1.5 py-2 flex items-center rounded-sm mt-2 bg-amber-50 gap-2 mb-3 text-amber-500 dark:bg-amber-700 dark:text-gray-200"
|
class="px-1.5 py-2 flex items-center rounded-sm mt-2 bg-amber-50 gap-2 mb-3 text-amber-500 dark:bg-amber-700 dark:text-gray-200"
|
||||||
:class="href&&'cursor-pointer'"
|
:class="href && 'cursor-pointer'"
|
||||||
@click="open"
|
@click="open"
|
||||||
>
|
>
|
||||||
<el-icon class="text-xl">
|
<el-icon class="text-xl">
|
||||||
|
|
@ -13,21 +13,21 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { WarningFilled } from '@element-plus/icons-vue'
|
import { WarningFilled } from '@element-plus/icons-vue'
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
href: {
|
href: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const open = () => {
|
const open = () => {
|
||||||
if (prop.href) {
|
if (prop.href) {
|
||||||
window.open(prop.href)
|
window.open(prop.href)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,52 @@
|
||||||
/**
|
/**
|
||||||
* 网站配置文件
|
* 网站配置文件
|
||||||
*/
|
*/
|
||||||
const greenText = (text) => `\x1b[32m${text}\x1b[0m`;
|
const greenText = (text) => `\x1b[32m${text}\x1b[0m`
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
appName: 'Gin-Vue-Admin',
|
appName: 'Gin-Vue-Admin',
|
||||||
appLogo: 'logo.png',
|
appLogo: 'logo.png',
|
||||||
showViteLogo: true,
|
showViteLogo: true,
|
||||||
logs: [],
|
logs: []
|
||||||
}
|
}
|
||||||
|
|
||||||
export const viteLogo = (env) => {
|
export const viteLogo = (env) => {
|
||||||
if (config.showViteLogo) {
|
if (config.showViteLogo) {
|
||||||
console.log(greenText(`> 欢迎使用Gin-Vue-Admin,开源地址:https://github.com/flipped-aurora/gin-vue-admin`));
|
console.log(
|
||||||
console.log(greenText(`> 当前版本:v2.7.7`));
|
greenText(
|
||||||
console.log(greenText(`> 加群方式:微信:shouzi_1994 QQ群:470239250`));
|
`> 欢迎使用Gin-Vue-Admin,开源地址:https://github.com/flipped-aurora/gin-vue-admin`
|
||||||
console.log(greenText(`> 项目地址:https://github.com/flipped-aurora/gin-vue-admin`));
|
)
|
||||||
console.log(greenText(`> 插件市场:https://plugin.gin-vue-admin.com`));
|
)
|
||||||
console.log(greenText(`> GVA讨论社区:https://support.qq.com/products/371961`));
|
console.log(greenText(`> 当前版本:v2.7.7`))
|
||||||
console.log(greenText(`> 默认自动化文档地址:http://127.0.0.1:${env.VITE_SERVER_PORT}/swagger/index.html`));
|
console.log(greenText(`> 加群方式:微信:shouzi_1994 QQ群:470239250`))
|
||||||
console.log(greenText(`> 默认前端文件运行地址:http://127.0.0.1:${env.VITE_CLI_PORT}`));
|
console.log(
|
||||||
console.log(greenText(`--------------------------------------版权声明--------------------------------------`));
|
greenText(`> 项目地址:https://github.com/flipped-aurora/gin-vue-admin`)
|
||||||
console.log(greenText(`** 版权所有方:flipped-aurora开源团队 **`));
|
)
|
||||||
console.log(greenText(`** 版权持有公司:北京翻转极光科技有限责任公司 **`));
|
console.log(greenText(`> 插件市场:https://plugin.gin-vue-admin.com`))
|
||||||
console.log(greenText(`** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html **`));
|
console.log(
|
||||||
console.log('\n');
|
greenText(`> GVA讨论社区:https://support.qq.com/products/371961`)
|
||||||
|
)
|
||||||
|
console.log(
|
||||||
|
greenText(
|
||||||
|
`> 默认自动化文档地址:http://127.0.0.1:${env.VITE_SERVER_PORT}/swagger/index.html`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
console.log(
|
||||||
|
greenText(`> 默认前端文件运行地址:http://127.0.0.1:${env.VITE_CLI_PORT}`)
|
||||||
|
)
|
||||||
|
console.log(
|
||||||
|
greenText(
|
||||||
|
`--------------------------------------版权声明--------------------------------------`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
console.log(greenText(`** 版权所有方:flipped-aurora开源团队 **`))
|
||||||
|
console.log(greenText(`** 版权持有公司:北京翻转极光科技有限责任公司 **`))
|
||||||
|
console.log(
|
||||||
|
greenText(
|
||||||
|
`** 剔除授权标识需购买商用授权:https://gin-vue-admin.com/empower/index.html **`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
console.log('\n')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,21 +10,26 @@ const createIconComponent = (name) => ({
|
||||||
name: 'SvgIcon',
|
name: 'SvgIcon',
|
||||||
render() {
|
render() {
|
||||||
return h(svgIcon, {
|
return h(svgIcon, {
|
||||||
name: name,
|
name: name
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const registerIcons = async(app) => {
|
const registerIcons = async (app) => {
|
||||||
const iconModules = import.meta.glob('@/assets/icons/**/*.svg') // 系统目录 svg 图标
|
const iconModules = import.meta.glob('@/assets/icons/**/*.svg') // 系统目录 svg 图标
|
||||||
const pluginIconModules = import.meta.glob('@/plugin/**/assets/icons/**/*.svg') // 插件目录 svg 图标
|
const pluginIconModules = import.meta.glob(
|
||||||
const mergedIconModules = Object.assign({}, iconModules, pluginIconModules); // 合并所有 svg 图标
|
'@/plugin/**/assets/icons/**/*.svg'
|
||||||
|
) // 插件目录 svg 图标
|
||||||
|
const mergedIconModules = Object.assign({}, iconModules, pluginIconModules) // 合并所有 svg 图标
|
||||||
for (const path in mergedIconModules) {
|
for (const path in mergedIconModules) {
|
||||||
let pluginName = ""
|
let pluginName = ''
|
||||||
if (path.startsWith("/src/plugin/")) {
|
if (path.startsWith('/src/plugin/')) {
|
||||||
pluginName = `${path.split('/')[3]}-`
|
pluginName = `${path.split('/')[3]}-`
|
||||||
}
|
}
|
||||||
const iconName = path.split('/').pop().replace(/\.svg$/, '')
|
const iconName = path
|
||||||
|
.split('/')
|
||||||
|
.pop()
|
||||||
|
.replace(/\.svg$/, '')
|
||||||
// 如果iconName带空格则不加入到图标库中并且提示名称不合法
|
// 如果iconName带空格则不加入到图标库中并且提示名称不合法
|
||||||
if (iconName.indexOf(' ') !== -1) {
|
if (iconName.indexOf(' ') !== -1) {
|
||||||
console.error(`icon ${iconName}.svg includes whitespace in ${path}`)
|
console.error(`icon ${iconName}.svg includes whitespace in ${path}`)
|
||||||
|
|
@ -32,11 +37,12 @@ const registerIcons = async(app) => {
|
||||||
}
|
}
|
||||||
const key = `${pluginName}${iconName}`
|
const key = `${pluginName}${iconName}`
|
||||||
// 开发模式下列出所有 svg 图标,方便开发者直接查找复制使用
|
// 开发模式下列出所有 svg 图标,方便开发者直接查找复制使用
|
||||||
import.meta.env.MODE == 'development' && console.log(`svg-icon-component: <${key} />`)
|
import.meta.env.MODE == 'development' &&
|
||||||
|
console.log(`svg-icon-component: <${key} />`)
|
||||||
const iconComponent = createIconComponent(key)
|
const iconComponent = createIconComponent(key)
|
||||||
config.logs.push({
|
config.logs.push({
|
||||||
'key': key,
|
key: key,
|
||||||
'label': key,
|
label: key
|
||||||
})
|
})
|
||||||
app.component(key, iconComponent)
|
app.component(key, iconComponent)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export default {
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
app.directive('auth', {
|
app.directive('auth', {
|
||||||
// 当被绑定的元素插入到 DOM 中时……
|
// 当被绑定的元素插入到 DOM 中时……
|
||||||
mounted: function(el, binding) {
|
mounted: function (el, binding) {
|
||||||
const userInfo = userStore.userInfo
|
const userInfo = userStore.userInfo
|
||||||
let type = ''
|
let type = ''
|
||||||
switch (Object.prototype.toString.call(binding.value)) {
|
switch (Object.prototype.toString.call(binding.value)) {
|
||||||
|
|
@ -27,7 +27,7 @@ export default {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const waitUse = binding.value.toString().split(',')
|
const waitUse = binding.value.toString().split(',')
|
||||||
let flag = waitUse.some(item => Number(item) === userInfo.authorityId)
|
let flag = waitUse.some((item) => Number(item) === userInfo.authorityId)
|
||||||
if (binding.modifiers.not) {
|
if (binding.modifiers.not) {
|
||||||
flag = !flag
|
flag = !flag
|
||||||
}
|
}
|
||||||
|
|
@ -38,4 +38,3 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
// 本组件参考 arco-pro 的实现
|
// 本组件参考 arco-pro 的实现
|
||||||
// https://github.com/arco-design/arco-design-pro-vue/blob/main/arco-design-pro-vite/src/hooks/chart-option.ts
|
// https://github.com/arco-design/arco-design-pro-vue/blob/main/arco-design-pro-vite/src/hooks/chart-option.ts
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue'
|
||||||
import { useAppStore } from '@/pinia';
|
import { useAppStore } from '@/pinia'
|
||||||
|
|
||||||
|
|
||||||
export default function useChartOption(sourceOption) {
|
export default function useChartOption(sourceOption) {
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore()
|
||||||
const isDark = computed(() => {
|
const isDark = computed(() => {
|
||||||
return appStore.theme === 'dark';
|
return appStore.theme === 'dark'
|
||||||
});
|
})
|
||||||
const chartOption = computed(() => {
|
const chartOption = computed(() => {
|
||||||
return sourceOption(isDark.value);
|
return sourceOption(isDark.value)
|
||||||
});
|
})
|
||||||
return {
|
return {
|
||||||
chartOption,
|
chartOption
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,35 @@
|
||||||
// 本组件参考 arco-pro 的实现
|
// 本组件参考 arco-pro 的实现
|
||||||
// https://github.com/arco-design/arco-design-pro-vue/blob/main/arco-design-pro-vite/src/hooks/responsive.ts
|
// https://github.com/arco-design/arco-design-pro-vue/blob/main/arco-design-pro-vite/src/hooks/responsive.ts
|
||||||
|
|
||||||
import { onMounted, onBeforeMount, onBeforeUnmount } from 'vue';
|
import { onMounted, onBeforeMount, onBeforeUnmount } from 'vue'
|
||||||
import { useDebounceFn } from '@vueuse/core';
|
import { useDebounceFn } from '@vueuse/core'
|
||||||
import { useAppStore } from '@/pinia';
|
import { useAppStore } from '@/pinia'
|
||||||
import { addEventListen, removeEventListen } from '@/utils/event';
|
import { addEventListen, removeEventListen } from '@/utils/event'
|
||||||
|
|
||||||
const WIDTH = 992;
|
const WIDTH = 992
|
||||||
|
|
||||||
function queryDevice() {
|
function queryDevice() {
|
||||||
const rect = document.body.getBoundingClientRect();
|
const rect = document.body.getBoundingClientRect()
|
||||||
return rect.width - 1 < WIDTH;
|
return rect.width - 1 < WIDTH
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useResponsive(immediate) {
|
export default function useResponsive(immediate) {
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore()
|
||||||
function resizeHandler() {
|
function resizeHandler() {
|
||||||
if (!document.hidden) {
|
if (!document.hidden) {
|
||||||
const isMobile = queryDevice();
|
const isMobile = queryDevice()
|
||||||
appStore.toggleDevice(isMobile ? 'mobile' : 'desktop');
|
appStore.toggleDevice(isMobile ? 'mobile' : 'desktop')
|
||||||
// appStore.toggleDevice(isMobile);
|
// appStore.toggleDevice(isMobile);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const debounceFn = useDebounceFn(resizeHandler, 100);
|
}
|
||||||
onMounted(() => {
|
const debounceFn = useDebounceFn(resizeHandler, 100)
|
||||||
if (immediate) debounceFn();
|
onMounted(() => {
|
||||||
});
|
if (immediate) debounceFn()
|
||||||
onBeforeMount(() => {
|
})
|
||||||
addEventListen(window, 'resize', debounceFn);
|
onBeforeMount(() => {
|
||||||
});
|
addEventListen(window, 'resize', debounceFn)
|
||||||
onBeforeUnmount(() => {
|
})
|
||||||
removeEventListen(window, 'resize', debounceFn);
|
onBeforeUnmount(() => {
|
||||||
});
|
removeEventListen(window, 'resize', debounceFn)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,6 @@ export const useWindowResize = (cb) => {
|
||||||
useEventListener('resize', onResize, { passive: true })
|
useEventListener('resize', onResize, { passive: true })
|
||||||
return {
|
return {
|
||||||
width,
|
width,
|
||||||
height,
|
height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,5 @@ import 'default-passive-events'
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
app.config.productionTip = false
|
app.config.productionTip = false
|
||||||
|
|
||||||
app
|
app.use(run).use(ElementPlus).use(store).use(auth).use(router).mount('#app')
|
||||||
.use(run)
|
|
||||||
.use(ElementPlus)
|
|
||||||
.use(store)
|
|
||||||
.use(auth)
|
|
||||||
.use(router)
|
|
||||||
.mount('#app')
|
|
||||||
export default app
|
export default app
|
||||||
|
|
|
||||||
|
|
@ -64,4 +64,4 @@
|
||||||
"/src/plugin/announcement/form/info.vue": "InfoForm",
|
"/src/plugin/announcement/form/info.vue": "InfoForm",
|
||||||
"/src/plugin/announcement/view/info.vue": "Info",
|
"/src/plugin/announcement/view/info.vue": "Info",
|
||||||
"/src/plugin/email/view/index.vue": "Email"
|
"/src/plugin/email/view/index.vue": "Email"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,26 +8,25 @@ Nprogress.configure({ showSpinner: false, ease: 'ease', speed: 500 })
|
||||||
|
|
||||||
const whiteList = ['Login', 'Init']
|
const whiteList = ['Login', 'Init']
|
||||||
|
|
||||||
const getRouter = async(userStore) => {
|
const getRouter = async (userStore) => {
|
||||||
const routerStore = useRouterStore()
|
const routerStore = useRouterStore()
|
||||||
await routerStore.SetAsyncRouter()
|
await routerStore.SetAsyncRouter()
|
||||||
await userStore.GetUserInfo()
|
await userStore.GetUserInfo()
|
||||||
const asyncRouters = routerStore.asyncRouters
|
const asyncRouters = routerStore.asyncRouters
|
||||||
asyncRouters.forEach(asyncRouter => {
|
asyncRouters.forEach((asyncRouter) => {
|
||||||
router.addRoute(asyncRouter)
|
router.addRoute(asyncRouter)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeLoading = () => {
|
const removeLoading = () => {
|
||||||
const element = document.getElementById('gva-loading-box');
|
const element = document.getElementById('gva-loading-box')
|
||||||
if (element) {
|
if (element) {
|
||||||
element.remove();
|
element.remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function handleKeepAlive(to) {
|
async function handleKeepAlive(to) {
|
||||||
if (to.matched.some(item => item.meta.keepAlive)) {
|
if (to.matched.some((item) => item.meta.keepAlive)) {
|
||||||
if (to.matched && to.matched.length > 2) {
|
if (to.matched && to.matched.length > 2) {
|
||||||
for (let i = 1; i < to.matched.length; i++) {
|
for (let i = 1; i < to.matched.length; i++) {
|
||||||
const element = to.matched[i - 1]
|
const element = to.matched[i - 1]
|
||||||
|
|
@ -45,7 +44,7 @@ async function handleKeepAlive(to) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
router.beforeEach(async(to, from) => {
|
router.beforeEach(async (to, from) => {
|
||||||
const routerStore = useRouterStore()
|
const routerStore = useRouterStore()
|
||||||
Nprogress.start()
|
Nprogress.start()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
@ -54,7 +53,7 @@ router.beforeEach(async(to, from) => {
|
||||||
const token = userStore.token
|
const token = userStore.token
|
||||||
// 在白名单中的判断情况
|
// 在白名单中的判断情况
|
||||||
document.title = getPageTitle(to.meta.title, to)
|
document.title = getPageTitle(to.meta.title, to)
|
||||||
if(to.meta.client) {
|
if (to.meta.client) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if (whiteList.indexOf(to.name) > -1) {
|
if (whiteList.indexOf(to.name) > -1) {
|
||||||
|
|
@ -85,9 +84,9 @@ router.beforeEach(async(to, from) => {
|
||||||
} else {
|
} else {
|
||||||
// 不在白名单中并且已经登录的时候
|
// 不在白名单中并且已经登录的时候
|
||||||
if (token) {
|
if (token) {
|
||||||
if(sessionStorage.getItem("needToHome") === 'true') {
|
if (sessionStorage.getItem('needToHome') === 'true') {
|
||||||
sessionStorage.removeItem("needToHome")
|
sessionStorage.removeItem('needToHome')
|
||||||
return { path: '/'}
|
return { path: '/' }
|
||||||
}
|
}
|
||||||
// 添加flag防止多次获取动态路由和栈溢出
|
// 添加flag防止多次获取动态路由和栈溢出
|
||||||
if (!routerStore.asyncRouterFlag && whiteList.indexOf(from.name) < 0) {
|
if (!routerStore.asyncRouterFlag && whiteList.indexOf(from.name) < 0) {
|
||||||
|
|
@ -124,7 +123,6 @@ router.beforeEach(async(to, from) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
router.afterEach(() => {
|
router.afterEach(() => {
|
||||||
// 路由加载完成后关闭进度条
|
// 路由加载完成后关闭进度条
|
||||||
document.getElementsByClassName('main-cont main-right')[0]?.scrollTo(0, 0)
|
document.getElementsByClassName('main-cont main-right')[0]?.scrollTo(0, 0)
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,4 @@ import { useDictionaryStore } from '@/pinia/modules/dictionary'
|
||||||
|
|
||||||
const store = createPinia()
|
const store = createPinia()
|
||||||
|
|
||||||
export {
|
export { store, useAppStore, useUserStore, useDictionaryStore }
|
||||||
store,
|
|
||||||
useAppStore,
|
|
||||||
useUserStore,
|
|
||||||
useDictionaryStore
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,56 @@
|
||||||
|
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref, watchEffect, reactive } from 'vue'
|
import { ref, watchEffect, reactive } from 'vue'
|
||||||
import { setBodyPrimaryColor } from '@/utils/format'
|
import { setBodyPrimaryColor } from '@/utils/format'
|
||||||
export const useAppStore = defineStore('app', () => {
|
export const useAppStore = defineStore('app', () => {
|
||||||
|
const device = ref('')
|
||||||
const device = ref("")
|
|
||||||
const config = reactive({
|
const config = reactive({
|
||||||
weakness: false,
|
weakness: false,
|
||||||
grey: false,
|
grey: false,
|
||||||
primaryColor: '#3b82f6',
|
primaryColor: '#3b82f6',
|
||||||
showTabs: true,
|
showTabs: true,
|
||||||
darkMode: 'auto',
|
darkMode: 'auto',
|
||||||
layout_side_width : 256,
|
layout_side_width: 256,
|
||||||
layout_side_collapsed_width : 80,
|
layout_side_collapsed_width: 80,
|
||||||
layout_side_item_height : 48,
|
layout_side_item_height: 48,
|
||||||
show_watermark: true,
|
show_watermark: true,
|
||||||
side_mode : 'normal'
|
side_mode: 'normal'
|
||||||
})
|
})
|
||||||
|
|
||||||
const theme = ref( 'auto')
|
const theme = ref('auto')
|
||||||
|
|
||||||
const toggleTheme = (dark) => {
|
const toggleTheme = (dark) => {
|
||||||
if (dark) {
|
if (dark) {
|
||||||
theme.value = 'dark';
|
theme.value = 'dark'
|
||||||
} else {
|
} else {
|
||||||
theme.value = 'light';
|
theme.value = 'light'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleWeakness = (e) => {
|
const toggleWeakness = (e) => {
|
||||||
config.weakness = e;
|
config.weakness = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleGrey = (e) => {
|
const toggleGrey = (e) => {
|
||||||
config.grey = e;
|
config.grey = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const togglePrimaryColor = (e) => {
|
const togglePrimaryColor = (e) => {
|
||||||
config.primaryColor = e;
|
config.primaryColor = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleTabs = (e) => {
|
const toggleTabs = (e) => {
|
||||||
config.showTabs = e;
|
config.showTabs = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleDevice = (e) => {
|
const toggleDevice = (e) => {
|
||||||
device.value = e;
|
device.value = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleDarkMode = (e) => {
|
const toggleDarkMode = (e) => {
|
||||||
config.darkMode = e
|
config.darkMode = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleDarkModeAuto = () =>{
|
const toggleDarkModeAuto = () => {
|
||||||
// 处理浏览器主题
|
// 处理浏览器主题
|
||||||
const darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
const darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
||||||
const dark = darkQuery.matches
|
const dark = darkQuery.matches
|
||||||
|
|
@ -63,61 +61,59 @@ export const useAppStore = defineStore('app', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleConfigSideWidth = (e) => {
|
const toggleConfigSideWidth = (e) => {
|
||||||
config.layout_side_width = e;
|
config.layout_side_width = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleConfigSideCollapsedWidth = (e) => {
|
const toggleConfigSideCollapsedWidth = (e) => {
|
||||||
config.layout_side_collapsed_width = e;
|
config.layout_side_collapsed_width = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleConfigSideItemHeight = (e) => {
|
const toggleConfigSideItemHeight = (e) => {
|
||||||
config.layout_side_item_height = e;
|
config.layout_side_item_height = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleConfigWatermark = (e) => {
|
const toggleConfigWatermark = (e) => {
|
||||||
config.show_watermark = e;
|
config.show_watermark = e
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleSideModel= (e) =>{
|
const toggleSideModel = (e) => {
|
||||||
config.side_mode = e
|
config.side_mode = e
|
||||||
}
|
}
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (theme.value === 'dark') {
|
if (theme.value === 'dark') {
|
||||||
document.documentElement.classList.add('dark');
|
document.documentElement.classList.add('dark')
|
||||||
document.documentElement.classList.remove('light');
|
document.documentElement.classList.remove('light')
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.add('light');
|
document.documentElement.classList.add('light')
|
||||||
document.documentElement.classList.remove('dark');
|
document.documentElement.classList.remove('dark')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
// 色弱模式监听处理
|
// 色弱模式监听处理
|
||||||
if (config.weakness) {
|
if (config.weakness) {
|
||||||
document.documentElement.classList.add('html-weakenss');
|
document.documentElement.classList.add('html-weakenss')
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.remove('html-weakenss');
|
document.documentElement.classList.remove('html-weakenss')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
// 灰色模式监听处理
|
// 灰色模式监听处理
|
||||||
if (config.grey) {
|
if (config.grey) {
|
||||||
document.documentElement.classList.add('html-grey');
|
document.documentElement.classList.add('html-grey')
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.remove('html-grey');
|
document.documentElement.classList.remove('html-grey')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if(config.darkMode === 'auto'){
|
if (config.darkMode === 'auto') {
|
||||||
toggleDarkModeAuto()
|
toggleDarkModeAuto()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config.darkMode === 'dark'){
|
if (config.darkMode === 'dark') {
|
||||||
toggleTheme(true)
|
toggleTheme(true)
|
||||||
}else{
|
} else {
|
||||||
toggleTheme(false)
|
toggleTheme(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -143,5 +139,4 @@ export const useAppStore = defineStore('app', () => {
|
||||||
toggleConfigWatermark,
|
toggleConfigWatermark,
|
||||||
toggleSideModel
|
toggleSideModel
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export const useDictionaryStore = defineStore('dictionary', () => {
|
||||||
dictionaryMap.value = { ...dictionaryMap.value, ...dictionaryRes }
|
dictionaryMap.value = { ...dictionaryMap.value, ...dictionaryRes }
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDictionary = async(type) => {
|
const getDictionary = async (type) => {
|
||||||
if (dictionaryMap.value[type] && dictionaryMap.value[type].length) {
|
if (dictionaryMap.value[type] && dictionaryMap.value[type].length) {
|
||||||
return dictionaryMap.value[type]
|
return dictionaryMap.value[type]
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -18,13 +18,14 @@ export const useDictionaryStore = defineStore('dictionary', () => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
const dictionaryRes = {}
|
const dictionaryRes = {}
|
||||||
const dict = []
|
const dict = []
|
||||||
res.data.resysDictionary.sysDictionaryDetails && res.data.resysDictionary.sysDictionaryDetails.forEach(item => {
|
res.data.resysDictionary.sysDictionaryDetails &&
|
||||||
dict.push({
|
res.data.resysDictionary.sysDictionaryDetails.forEach((item) => {
|
||||||
label: item.label,
|
dict.push({
|
||||||
value: item.value,
|
label: item.label,
|
||||||
extend: item.extend
|
value: item.value,
|
||||||
|
extend: item.extend
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
dictionaryRes[res.data.resysDictionary.type] = dict
|
dictionaryRes[res.data.resysDictionary.type] = dict
|
||||||
setDictionaryMap(dictionaryRes)
|
setDictionaryMap(dictionaryRes)
|
||||||
return dictionaryMap.value[type]
|
return dictionaryMap.value[type]
|
||||||
|
|
|
||||||
|
|
@ -2,43 +2,48 @@ import { asyncRouterHandle } from '@/utils/asyncRouter'
|
||||||
import { emitter } from '@/utils/bus.js'
|
import { emitter } from '@/utils/bus.js'
|
||||||
import { asyncMenu } from '@/api/menu'
|
import { asyncMenu } from '@/api/menu'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref,watchEffect } from 'vue'
|
import { ref, watchEffect } from 'vue'
|
||||||
import pathInfo from "@/pathInfo.json";
|
import pathInfo from '@/pathInfo.json'
|
||||||
|
|
||||||
const notLayoutRouterArr = []
|
const notLayoutRouterArr = []
|
||||||
const keepAliveRoutersArr = []
|
const keepAliveRoutersArr = []
|
||||||
const nameMap = {}
|
const nameMap = {}
|
||||||
|
|
||||||
const formatRouter = (routes, routeMap, parent) => {
|
const formatRouter = (routes, routeMap, parent) => {
|
||||||
routes && routes.forEach(item => {
|
routes &&
|
||||||
item.parent = parent
|
routes.forEach((item) => {
|
||||||
item.meta.btns = item.btns
|
item.parent = parent
|
||||||
item.meta.hidden = item.hidden
|
item.meta.btns = item.btns
|
||||||
if (item.meta.defaultMenu === true) {
|
item.meta.hidden = item.hidden
|
||||||
if (!parent) {
|
if (item.meta.defaultMenu === true) {
|
||||||
item = { ...item, path: `/${item.path}` }
|
if (!parent) {
|
||||||
notLayoutRouterArr.push(item)
|
item = { ...item, path: `/${item.path}` }
|
||||||
|
notLayoutRouterArr.push(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
routeMap[item.name] = item
|
||||||
routeMap[item.name] = item
|
if (item.children && item.children.length > 0) {
|
||||||
if (item.children && item.children.length > 0) {
|
formatRouter(item.children, routeMap, item)
|
||||||
formatRouter(item.children, routeMap, item)
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const KeepAliveFilter = (routes) => {
|
const KeepAliveFilter = (routes) => {
|
||||||
routes && routes.forEach(item => {
|
routes &&
|
||||||
// 子菜单中有 keep-alive 的,父菜单也必须 keep-alive,否则无效。这里将子菜单中有 keep-alive 的父菜单也加入。
|
routes.forEach((item) => {
|
||||||
if ((item.children && item.children.some(ch => ch.meta.keepAlive) || item.meta.keepAlive)) {
|
// 子菜单中有 keep-alive 的,父菜单也必须 keep-alive,否则无效。这里将子菜单中有 keep-alive 的父菜单也加入。
|
||||||
const path = item.meta.path
|
if (
|
||||||
keepAliveRoutersArr.push(pathInfo[path])
|
(item.children && item.children.some((ch) => ch.meta.keepAlive)) ||
|
||||||
nameMap[item.name] = pathInfo[path]
|
item.meta.keepAlive
|
||||||
}
|
) {
|
||||||
if (item.children && item.children.length > 0) {
|
const path = item.meta.path
|
||||||
KeepAliveFilter(item.children)
|
keepAliveRoutersArr.push(pathInfo[path])
|
||||||
}
|
nameMap[item.name] = pathInfo[path]
|
||||||
})
|
}
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
KeepAliveFilter(item.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useRouterStore = defineStore('router', () => {
|
export const useRouterStore = defineStore('router', () => {
|
||||||
|
|
@ -46,7 +51,7 @@ export const useRouterStore = defineStore('router', () => {
|
||||||
const asyncRouterFlag = ref(0)
|
const asyncRouterFlag = ref(0)
|
||||||
const setKeepAliveRouters = (history) => {
|
const setKeepAliveRouters = (history) => {
|
||||||
const keepArrTemp = []
|
const keepArrTemp = []
|
||||||
history.forEach(item => {
|
history.forEach((item) => {
|
||||||
if (nameMap[item.name]) {
|
if (nameMap[item.name]) {
|
||||||
keepArrTemp.push(nameMap[item.name])
|
keepArrTemp.push(nameMap[item.name])
|
||||||
}
|
}
|
||||||
|
|
@ -63,64 +68,63 @@ export const useRouterStore = defineStore('router', () => {
|
||||||
|
|
||||||
const menuMap = {}
|
const menuMap = {}
|
||||||
|
|
||||||
const topActive = ref("")
|
const topActive = ref('')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const setLeftMenu = (name) => {
|
const setLeftMenu = (name) => {
|
||||||
sessionStorage.setItem('topActive', name)
|
sessionStorage.setItem('topActive', name)
|
||||||
topActive.value = name
|
topActive.value = name
|
||||||
if(menuMap[name]?.children){
|
if (menuMap[name]?.children) {
|
||||||
leftMenu.value = menuMap[name].children
|
leftMenu.value = menuMap[name].children
|
||||||
}
|
}
|
||||||
return menuMap[name]?.children
|
return menuMap[name]?.children
|
||||||
}
|
}
|
||||||
|
|
||||||
watchEffect(()=>{
|
watchEffect(() => {
|
||||||
let topActive = sessionStorage.getItem("topActive")
|
let topActive = sessionStorage.getItem('topActive')
|
||||||
let firstHasChildren = ''
|
let firstHasChildren = ''
|
||||||
asyncRouters.value[0]?.children.forEach((item) => {
|
asyncRouters.value[0]?.children.forEach((item) => {
|
||||||
if (item.hidden) return;
|
if (item.hidden) return
|
||||||
menuMap[item.name] = item;
|
menuMap[item.name] = item
|
||||||
if (!firstHasChildren && item.children && item.children.length > 0) {
|
if (!firstHasChildren && item.children && item.children.length > 0) {
|
||||||
firstHasChildren = item.name
|
firstHasChildren = item.name
|
||||||
}
|
}
|
||||||
topMenu.value.push({...item, children: []})
|
topMenu.value.push({ ...item, children: [] })
|
||||||
});
|
})
|
||||||
|
|
||||||
if(!menuMap[topActive]?.children && firstHasChildren){
|
if (!menuMap[topActive]?.children && firstHasChildren) {
|
||||||
topActive = firstHasChildren
|
topActive = firstHasChildren
|
||||||
}
|
}
|
||||||
setLeftMenu(topActive)
|
setLeftMenu(topActive)
|
||||||
})
|
})
|
||||||
|
|
||||||
const routeMap = ({})
|
const routeMap = {}
|
||||||
// 从后台获取动态路由
|
// 从后台获取动态路由
|
||||||
const SetAsyncRouter = async() => {
|
const SetAsyncRouter = async () => {
|
||||||
asyncRouterFlag.value++
|
asyncRouterFlag.value++
|
||||||
const baseRouter = [{
|
const baseRouter = [
|
||||||
path: '/layout',
|
{
|
||||||
name: 'layout',
|
path: '/layout',
|
||||||
component: 'view/layout/index.vue',
|
name: 'layout',
|
||||||
meta: {
|
component: 'view/layout/index.vue',
|
||||||
title: '底层layout'
|
meta: {
|
||||||
},
|
title: '底层layout'
|
||||||
children: []
|
},
|
||||||
}]
|
children: []
|
||||||
|
}
|
||||||
|
]
|
||||||
const asyncRouterRes = await asyncMenu()
|
const asyncRouterRes = await asyncMenu()
|
||||||
const asyncRouter = asyncRouterRes.data.menus
|
const asyncRouter = asyncRouterRes.data.menus
|
||||||
asyncRouter && asyncRouter.push({
|
asyncRouter &&
|
||||||
path: 'reload',
|
asyncRouter.push({
|
||||||
name: 'Reload',
|
path: 'reload',
|
||||||
hidden: true,
|
name: 'Reload',
|
||||||
meta: {
|
hidden: true,
|
||||||
title: '',
|
meta: {
|
||||||
closeTab: true,
|
title: '',
|
||||||
},
|
closeTab: true
|
||||||
component: 'view/error/reload.vue'
|
},
|
||||||
})
|
component: 'view/error/reload.vue'
|
||||||
|
})
|
||||||
formatRouter(asyncRouter, routeMap)
|
formatRouter(asyncRouter, routeMap)
|
||||||
baseRouter[0].children = asyncRouter
|
baseRouter[0].children = asyncRouter
|
||||||
if (notLayoutRouterArr.length !== 0) {
|
if (notLayoutRouterArr.length !== 0) {
|
||||||
|
|
@ -144,4 +148,3 @@ export const useRouterStore = defineStore('router', () => {
|
||||||
routeMap
|
routeMap
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { ref, watch } from 'vue'
|
||||||
import { useRouterStore } from './router'
|
import { useRouterStore } from './router'
|
||||||
import cookie from 'js-cookie'
|
import cookie from 'js-cookie'
|
||||||
|
|
||||||
import {useAppStore} from "@/pinia";
|
import { useAppStore } from '@/pinia'
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', () => {
|
export const useUserStore = defineStore('user', () => {
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
|
|
@ -17,13 +17,15 @@ export const useUserStore = defineStore('user', () => {
|
||||||
uuid: '',
|
uuid: '',
|
||||||
nickName: '',
|
nickName: '',
|
||||||
headerImg: '',
|
headerImg: '',
|
||||||
authority: {},
|
authority: {}
|
||||||
})
|
})
|
||||||
const token = ref(window.localStorage.getItem('token') || cookie.get('x-token') || '')
|
const token = ref(
|
||||||
|
window.localStorage.getItem('token') || cookie.get('x-token') || ''
|
||||||
|
)
|
||||||
const setUserInfo = (val) => {
|
const setUserInfo = (val) => {
|
||||||
userInfo.value = val
|
userInfo.value = val
|
||||||
if(val.originSetting){
|
if (val.originSetting) {
|
||||||
Object.keys(appStore.config).forEach(key => {
|
Object.keys(appStore.config).forEach((key) => {
|
||||||
appStore.config[key] = val.originSetting[key]
|
appStore.config[key] = val.originSetting[key]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +38,7 @@ export const useUserStore = defineStore('user', () => {
|
||||||
const NeedInit = async () => {
|
const NeedInit = async () => {
|
||||||
token.value = ''
|
token.value = ''
|
||||||
window.localStorage.removeItem('token')
|
window.localStorage.removeItem('token')
|
||||||
await router.push({name: 'Init', replace: true})
|
await router.push({ name: 'Init', replace: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
const ResetUserInfo = (value = {}) => {
|
const ResetUserInfo = (value = {}) => {
|
||||||
|
|
@ -46,7 +48,7 @@ export const useUserStore = defineStore('user', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* 获取用户信息*/
|
/* 获取用户信息*/
|
||||||
const GetUserInfo = async() => {
|
const GetUserInfo = async () => {
|
||||||
const res = await getUserInfo()
|
const res = await getUserInfo()
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
setUserInfo(res.data.userInfo)
|
setUserInfo(res.data.userInfo)
|
||||||
|
|
@ -54,10 +56,10 @@ export const useUserStore = defineStore('user', () => {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
/* 登录*/
|
/* 登录*/
|
||||||
const LoginIn = async(loginInfo) => {
|
const LoginIn = async (loginInfo) => {
|
||||||
loadingInstance.value = ElLoading.service({
|
loadingInstance.value = ElLoading.service({
|
||||||
fullscreen: true,
|
fullscreen: true,
|
||||||
text: '登录中,请稍候...',
|
text: '登录中,请稍候...'
|
||||||
})
|
})
|
||||||
|
|
||||||
const res = await login(loginInfo)
|
const res = await login(loginInfo)
|
||||||
|
|
@ -78,7 +80,7 @@ export const useUserStore = defineStore('user', () => {
|
||||||
const asyncRouters = routerStore.asyncRouters
|
const asyncRouters = routerStore.asyncRouters
|
||||||
|
|
||||||
// 注册到路由表里
|
// 注册到路由表里
|
||||||
asyncRouters.forEach(asyncRouter => {
|
asyncRouters.forEach((asyncRouter) => {
|
||||||
router.addRoute(asyncRouter)
|
router.addRoute(asyncRouter)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -95,13 +97,12 @@ export const useUserStore = defineStore('user', () => {
|
||||||
window.localStorage.setItem('osType', 'MAC')
|
window.localStorage.setItem('osType', 'MAC')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 全部操作均结束,关闭loading并返回
|
// 全部操作均结束,关闭loading并返回
|
||||||
loadingInstance.value.close()
|
loadingInstance.value.close()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
/* 登出*/
|
/* 登出*/
|
||||||
const LoginOut = async() => {
|
const LoginOut = async () => {
|
||||||
const res = await jsonInBlacklist()
|
const res = await jsonInBlacklist()
|
||||||
|
|
||||||
// 登出失败
|
// 登出失败
|
||||||
|
|
@ -116,7 +117,7 @@ export const useUserStore = defineStore('user', () => {
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
/* 清理数据 */
|
/* 清理数据 */
|
||||||
const ClearStorage = async() => {
|
const ClearStorage = async () => {
|
||||||
token.value = ''
|
token.value = ''
|
||||||
sessionStorage.clear()
|
sessionStorage.clear()
|
||||||
window.localStorage.removeItem('token')
|
window.localStorage.removeItem('token')
|
||||||
|
|
@ -124,9 +125,12 @@ export const useUserStore = defineStore('user', () => {
|
||||||
localStorage.removeItem('originSetting')
|
localStorage.removeItem('originSetting')
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => token.value, () => {
|
watch(
|
||||||
window.localStorage.setItem('token', token.value)
|
() => token.value,
|
||||||
})
|
() => {
|
||||||
|
window.localStorage.setItem('token', token.value)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userInfo,
|
userInfo,
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,6 @@ export const getInfoList = (params) => {
|
||||||
export const getInfoDataSource = () => {
|
export const getInfoDataSource = () => {
|
||||||
return service({
|
return service({
|
||||||
url: '/info/getInfoDataSource',
|
url: '/info/getInfoDataSource',
|
||||||
method: 'get',
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,41 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="gva-form-box">
|
<div class="gva-form-box">
|
||||||
<el-form :model="formData" ref="elFormRef" label-position="right" :rules="rule" label-width="80px">
|
<el-form
|
||||||
|
:model="formData"
|
||||||
|
ref="elFormRef"
|
||||||
|
label-position="right"
|
||||||
|
:rules="rule"
|
||||||
|
label-width="80px"
|
||||||
|
>
|
||||||
<el-form-item label="标题:" prop="title">
|
<el-form-item label="标题:" prop="title">
|
||||||
<el-input v-model="formData.title" :clearable="true" placeholder="请输入标题" />
|
<el-input
|
||||||
</el-form-item>
|
v-model="formData.title"
|
||||||
|
:clearable="true"
|
||||||
|
placeholder="请输入标题"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="内容:" prop="content">
|
<el-form-item label="内容:" prop="content">
|
||||||
<RichEdit v-model="formData.content"/>
|
<RichEdit v-model="formData.content" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="作者:" prop="userID">
|
<el-form-item label="作者:" prop="userID">
|
||||||
<el-select v-model="formData.userID" placeholder="请选择作者" style="width:100%" :clearable="true" >
|
<el-select
|
||||||
<el-option v-for="(item,key) in dataSource.userID" :key="key" :label="item.label" :value="item.value" />
|
v-model="formData.userID"
|
||||||
</el-select>
|
placeholder="请选择作者"
|
||||||
</el-form-item>
|
style="width: 100%"
|
||||||
|
:clearable="true"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(item, key) in dataSource.userID"
|
||||||
|
:key="key"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="附件:" prop="attachments">
|
<el-form-item label="附件:" prop="attachments">
|
||||||
<SelectFile v-model="formData.attachments" />
|
<SelectFile v-model="formData.attachments" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="save">保存</el-button>
|
<el-button type="primary" @click="save">保存</el-button>
|
||||||
<el-button type="primary" @click="back">返回</el-button>
|
<el-button type="primary" @click="back">返回</el-button>
|
||||||
|
|
@ -26,42 +46,41 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
getInfoDataSource,
|
getInfoDataSource,
|
||||||
createInfo,
|
createInfo,
|
||||||
updateInfo,
|
updateInfo,
|
||||||
findInfo
|
findInfo
|
||||||
} from '@/plugin/announcement/api/info'
|
} from '@/plugin/announcement/api/info'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'InfoForm'
|
name: 'InfoForm'
|
||||||
})
|
})
|
||||||
|
|
||||||
// 自动获取字典
|
// 自动获取字典
|
||||||
import { useRoute, useRouter } from "vue-router"
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import SelectFile from '@/components/selectFile/selectFile.vue'
|
import SelectFile from '@/components/selectFile/selectFile.vue'
|
||||||
// 富文本组件
|
// 富文本组件
|
||||||
import RichEdit from '@/components/richtext/rich-edit.vue'
|
import RichEdit from '@/components/richtext/rich-edit.vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const type = ref('')
|
const type = ref('')
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
title: '',
|
title: '',
|
||||||
content: '',
|
content: '',
|
||||||
userID: undefined,
|
userID: undefined,
|
||||||
attachments: [],
|
attachments: []
|
||||||
})
|
})
|
||||||
// 验证规则
|
// 验证规则
|
||||||
const rule = reactive({
|
const rule = reactive({})
|
||||||
})
|
|
||||||
|
|
||||||
const elFormRef = ref()
|
const elFormRef = ref()
|
||||||
const dataSource = ref([])
|
const dataSource = ref([])
|
||||||
const getDataSourceFunc = async()=>{
|
const getDataSourceFunc = async () => {
|
||||||
const res = await getInfoDataSource()
|
const res = await getInfoDataSource()
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
dataSource.value = res.data
|
dataSource.value = res.data
|
||||||
|
|
@ -69,9 +88,9 @@ const elFormRef = ref()
|
||||||
}
|
}
|
||||||
getDataSourceFunc()
|
getDataSourceFunc()
|
||||||
|
|
||||||
// 初始化方法
|
// 初始化方法
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
// 建议通过url传参获取目标数据ID 调用 find方法进行查询数据操作 从而决定本页面是create还是update 以下为id作为url参数示例
|
// 建议通过url传参获取目标数据ID 调用 find方法进行查询数据操作 从而决定本页面是create还是update 以下为id作为url参数示例
|
||||||
if (route.query.id) {
|
if (route.query.id) {
|
||||||
const res = await findInfo({ ID: route.query.id })
|
const res = await findInfo({ ID: route.query.id })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
|
|
@ -81,40 +100,38 @@ const init = async () => {
|
||||||
} else {
|
} else {
|
||||||
type.value = 'create'
|
type.value = 'create'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init()
|
init()
|
||||||
// 保存按钮
|
// 保存按钮
|
||||||
const save = async() => {
|
const save = async () => {
|
||||||
elFormRef.value?.validate( async (valid) => {
|
elFormRef.value?.validate(async (valid) => {
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
let res
|
let res
|
||||||
switch (type.value) {
|
switch (type.value) {
|
||||||
case 'create':
|
case 'create':
|
||||||
res = await createInfo(formData.value)
|
res = await createInfo(formData.value)
|
||||||
break
|
break
|
||||||
case 'update':
|
case 'update':
|
||||||
res = await updateInfo(formData.value)
|
res = await updateInfo(formData.value)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
res = await createInfo(formData.value)
|
res = await createInfo(formData.value)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: '创建/更改成功'
|
message: '创建/更改成功'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回按钮
|
// 返回按钮
|
||||||
const back = () => {
|
const back = () => {
|
||||||
router.go(-1)
|
router.go(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style></style>
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,50 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="gva-search-box">
|
<div class="gva-search-box">
|
||||||
<el-form ref="elSearchFormRef" :inline="true" :model="searchInfo" class="demo-form-inline" :rules="searchRule" @keyup.enter="onSubmit">
|
<el-form
|
||||||
|
ref="elSearchFormRef"
|
||||||
|
:inline="true"
|
||||||
|
:model="searchInfo"
|
||||||
|
class="demo-form-inline"
|
||||||
|
:rules="searchRule"
|
||||||
|
@keyup.enter="onSubmit"
|
||||||
|
>
|
||||||
<el-form-item label="创建日期" prop="createdAt">
|
<el-form-item label="创建日期" prop="createdAt">
|
||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
创建日期
|
创建日期
|
||||||
<el-tooltip content="搜索范围是开始日期(包含)至结束日期(不包含)">
|
<el-tooltip
|
||||||
|
content="搜索范围是开始日期(包含)至结束日期(不包含)"
|
||||||
|
>
|
||||||
<el-icon><QuestionFilled /></el-icon>
|
<el-icon><QuestionFilled /></el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<el-date-picker v-model="searchInfo.startCreatedAt" type="datetime" placeholder="开始日期" :disabled-date="time=> searchInfo.endCreatedAt ? time.getTime() > searchInfo.endCreatedAt.getTime() : false" />
|
<el-date-picker
|
||||||
|
v-model="searchInfo.startCreatedAt"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="开始日期"
|
||||||
|
:disabled-date="
|
||||||
|
(time) =>
|
||||||
|
searchInfo.endCreatedAt
|
||||||
|
? time.getTime() > searchInfo.endCreatedAt.getTime()
|
||||||
|
: false
|
||||||
|
"
|
||||||
|
/>
|
||||||
—
|
—
|
||||||
<el-date-picker v-model="searchInfo.endCreatedAt" type="datetime" placeholder="结束日期" :disabled-date="time=> searchInfo.startCreatedAt ? time.getTime() < searchInfo.startCreatedAt.getTime() : false" />
|
<el-date-picker
|
||||||
|
v-model="searchInfo.endCreatedAt"
|
||||||
|
type="datetime"
|
||||||
|
placeholder="结束日期"
|
||||||
|
:disabled-date="
|
||||||
|
(time) =>
|
||||||
|
searchInfo.startCreatedAt
|
||||||
|
? time.getTime() < searchInfo.startCreatedAt.getTime()
|
||||||
|
: false
|
||||||
|
"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
|
|
||||||
<template v-if="showAllQuery">
|
<template v-if="showAllQuery">
|
||||||
<!-- 将需要控制显示状态的查询条件添加到此范围内 -->
|
<!-- 将需要控制显示状态的查询条件添加到此范围内 -->
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -25,13 +53,23 @@
|
||||||
<el-button type="primary" icon="search" @click="onSubmit">
|
<el-button type="primary" icon="search" @click="onSubmit">
|
||||||
查询
|
查询
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button icon="refresh" @click="onReset">
|
<el-button icon="refresh" @click="onReset"> 重置 </el-button>
|
||||||
重置
|
<el-button
|
||||||
</el-button>
|
v-if="!showAllQuery"
|
||||||
<el-button v-if="!showAllQuery" link type="primary" icon="arrow-down" @click="showAllQuery=true">
|
link
|
||||||
|
type="primary"
|
||||||
|
icon="arrow-down"
|
||||||
|
@click="showAllQuery = true"
|
||||||
|
>
|
||||||
展开
|
展开
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button v-else link type="primary" icon="arrow-up" @click="showAllQuery=false">
|
<el-button
|
||||||
|
v-else
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
icon="arrow-up"
|
||||||
|
@click="showAllQuery = false"
|
||||||
|
>
|
||||||
收起
|
收起
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -42,7 +80,12 @@
|
||||||
<el-button type="primary" icon="plus" @click="openDialog">
|
<el-button type="primary" icon="plus" @click="openDialog">
|
||||||
新增
|
新增
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button icon="delete" style="margin-left: 10px;" :disabled="!multipleSelection.length" @click="onDelete">
|
<el-button
|
||||||
|
icon="delete"
|
||||||
|
style="margin-left: 10px"
|
||||||
|
:disabled="!multipleSelection.length"
|
||||||
|
@click="onDelete"
|
||||||
|
>
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -65,24 +108,46 @@
|
||||||
<el-table-column align="left" label="标题" prop="title" width="120" />
|
<el-table-column align="left" label="标题" prop="title" width="120" />
|
||||||
<el-table-column align="left" label="作者" prop="userID" width="120">
|
<el-table-column align="left" label="作者" prop="userID" width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>{{ filterDataSource(dataSource.userID,scope.row.userID) }}</span>
|
<span>{{
|
||||||
|
filterDataSource(dataSource.userID, scope.row.userID)
|
||||||
|
}}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="附件" prop="attachments" width="200">
|
<el-table-column label="附件" prop="attachments" width="200">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div class="file-list">
|
<div class="file-list">
|
||||||
<el-tag v-for="file in scope.row.attachments" :key="file.uid" @click="downloadFile(file.url)">
|
<el-tag
|
||||||
|
v-for="file in scope.row.attachments"
|
||||||
|
:key="file.uid"
|
||||||
|
@click="downloadFile(file.url)"
|
||||||
|
>
|
||||||
{{ file.name }}
|
{{ file.name }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="left" label="操作" fixed="right" min-width="240">
|
<el-table-column
|
||||||
|
align="left"
|
||||||
|
label="操作"
|
||||||
|
fixed="right"
|
||||||
|
min-width="240"
|
||||||
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="primary" link icon="edit" class="table-button" @click="updateInfoFunc(scope.row)">
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
icon="edit"
|
||||||
|
class="table-button"
|
||||||
|
@click="updateInfoFunc(scope.row)"
|
||||||
|
>
|
||||||
变更
|
变更
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" link icon="delete" @click="deleteRow(scope.row)">
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
link
|
||||||
|
icon="delete"
|
||||||
|
@click="deleteRow(scope.row)"
|
||||||
|
>
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -100,31 +165,53 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-drawer v-model="dialogFormVisible" destroy-on-close size="800" :show-close="false" :before-close="closeDialog">
|
<el-drawer
|
||||||
|
v-model="dialogFormVisible"
|
||||||
|
destroy-on-close
|
||||||
|
size="800"
|
||||||
|
:show-close="false"
|
||||||
|
:before-close="closeDialog"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<span class="text-lg">{{ type==='create'?'添加':'修改' }}</span>
|
<span class="text-lg">{{ type === 'create' ? '添加' : '修改' }}</span>
|
||||||
<div>
|
<div>
|
||||||
<el-button type="primary" @click="enterDialog">
|
<el-button type="primary" @click="enterDialog"> 确 定 </el-button>
|
||||||
确 定
|
<el-button @click="closeDialog"> 取 消 </el-button>
|
||||||
</el-button>
|
|
||||||
<el-button @click="closeDialog">
|
|
||||||
取 消
|
|
||||||
</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-form ref="elFormRef" :model="formData" label-position="top" :rules="rule" label-width="80px">
|
<el-form
|
||||||
|
ref="elFormRef"
|
||||||
|
:model="formData"
|
||||||
|
label-position="top"
|
||||||
|
:rules="rule"
|
||||||
|
label-width="80px"
|
||||||
|
>
|
||||||
<el-form-item label="标题:" prop="title">
|
<el-form-item label="标题:" prop="title">
|
||||||
<el-input v-model="formData.title" :clearable="true" placeholder="请输入标题" />
|
<el-input
|
||||||
|
v-model="formData.title"
|
||||||
|
:clearable="true"
|
||||||
|
placeholder="请输入标题"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="内容:" prop="content">
|
<el-form-item label="内容:" prop="content">
|
||||||
<RichEdit v-model="formData.content" />
|
<RichEdit v-model="formData.content" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="作者:" prop="userID">
|
<el-form-item label="作者:" prop="userID">
|
||||||
<el-select v-model="formData.userID" placeholder="请选择作者" style="width:100%" :clearable="true">
|
<el-select
|
||||||
<el-option v-for="(item,key) in dataSource.userID" :key="key" :label="item.label" :value="item.value" />
|
v-model="formData.userID"
|
||||||
|
placeholder="请选择作者"
|
||||||
|
style="width: 100%"
|
||||||
|
:clearable="true"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(item, key) in dataSource.userID"
|
||||||
|
:key="key"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="附件:" prop="attachments">
|
<el-form-item label="附件:" prop="attachments">
|
||||||
|
|
@ -136,42 +223,42 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
getInfoDataSource,
|
getInfoDataSource,
|
||||||
createInfo,
|
createInfo,
|
||||||
deleteInfo,
|
deleteInfo,
|
||||||
deleteInfoByIds,
|
deleteInfoByIds,
|
||||||
updateInfo,
|
updateInfo,
|
||||||
findInfo,
|
findInfo,
|
||||||
getInfoList
|
getInfoList
|
||||||
} from '@/plugin/announcement/api/info'
|
} from '@/plugin/announcement/api/info'
|
||||||
import { getUrl } from '@/utils/image'
|
import { getUrl } from '@/utils/image'
|
||||||
// 富文本组件
|
// 富文本组件
|
||||||
import RichEdit from '@/components/richtext/rich-edit.vue'
|
import RichEdit from '@/components/richtext/rich-edit.vue'
|
||||||
// 文件选择组件
|
// 文件选择组件
|
||||||
import SelectFile from '@/components/selectFile/selectFile.vue'
|
import SelectFile from '@/components/selectFile/selectFile.vue'
|
||||||
|
|
||||||
// 全量引入格式化工具 请按需保留
|
// 全量引入格式化工具 请按需保留
|
||||||
import { formatDate, filterDataSource } from '@/utils/format'
|
import { formatDate, filterDataSource } from '@/utils/format'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Info'
|
name: 'Info'
|
||||||
})
|
})
|
||||||
|
|
||||||
// 控制更多查询条件显示/隐藏状态
|
// 控制更多查询条件显示/隐藏状态
|
||||||
const showAllQuery = ref(false)
|
const showAllQuery = ref(false)
|
||||||
|
|
||||||
// 自动化生成的字典(可能为空)以及字段
|
// 自动化生成的字典(可能为空)以及字段
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
title: '',
|
title: '',
|
||||||
content: '',
|
content: '',
|
||||||
userID: undefined,
|
userID: undefined,
|
||||||
attachments: [],
|
attachments: []
|
||||||
})
|
})
|
||||||
const dataSource = ref([])
|
const dataSource = ref([])
|
||||||
const getDataSourceFunc = async()=>{
|
const getDataSourceFunc = async () => {
|
||||||
const res = await getInfoDataSource()
|
const res = await getInfoDataSource()
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
dataSource.value = res.data
|
dataSource.value = res.data
|
||||||
|
|
@ -179,114 +266,129 @@ const formData = ref({
|
||||||
}
|
}
|
||||||
getDataSourceFunc()
|
getDataSourceFunc()
|
||||||
|
|
||||||
|
// 验证规则
|
||||||
|
const rule = reactive({})
|
||||||
|
|
||||||
|
const searchRule = reactive({
|
||||||
// 验证规则
|
createdAt: [
|
||||||
const rule = reactive({
|
{
|
||||||
})
|
validator: (rule, value, callback) => {
|
||||||
|
if (
|
||||||
const searchRule = reactive({
|
searchInfo.value.startCreatedAt &&
|
||||||
createdAt: [
|
!searchInfo.value.endCreatedAt
|
||||||
{ validator: (rule, value, callback) => {
|
) {
|
||||||
if (searchInfo.value.startCreatedAt && !searchInfo.value.endCreatedAt) {
|
callback(new Error('请填写结束日期'))
|
||||||
callback(new Error('请填写结束日期'))
|
} else if (
|
||||||
} else if (!searchInfo.value.startCreatedAt && searchInfo.value.endCreatedAt) {
|
!searchInfo.value.startCreatedAt &&
|
||||||
callback(new Error('请填写开始日期'))
|
searchInfo.value.endCreatedAt
|
||||||
} else if (searchInfo.value.startCreatedAt && searchInfo.value.endCreatedAt && (searchInfo.value.startCreatedAt.getTime() === searchInfo.value.endCreatedAt.getTime() || searchInfo.value.startCreatedAt.getTime() > searchInfo.value.endCreatedAt.getTime())) {
|
) {
|
||||||
callback(new Error('开始日期应当早于结束日期'))
|
callback(new Error('请填写开始日期'))
|
||||||
} else {
|
} else if (
|
||||||
callback()
|
searchInfo.value.startCreatedAt &&
|
||||||
|
searchInfo.value.endCreatedAt &&
|
||||||
|
(searchInfo.value.startCreatedAt.getTime() ===
|
||||||
|
searchInfo.value.endCreatedAt.getTime() ||
|
||||||
|
searchInfo.value.startCreatedAt.getTime() >
|
||||||
|
searchInfo.value.endCreatedAt.getTime())
|
||||||
|
) {
|
||||||
|
callback(new Error('开始日期应当早于结束日期'))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
}
|
}
|
||||||
}, trigger: 'change' }
|
]
|
||||||
],
|
|
||||||
})
|
|
||||||
|
|
||||||
const elFormRef = ref()
|
|
||||||
const elSearchFormRef = ref()
|
|
||||||
|
|
||||||
// =========== 表格控制部分 ===========
|
|
||||||
const page = ref(1)
|
|
||||||
const total = ref(0)
|
|
||||||
const pageSize = ref(10)
|
|
||||||
const tableData = ref([])
|
|
||||||
const searchInfo = ref({})
|
|
||||||
|
|
||||||
// 重置
|
|
||||||
const onReset = () => {
|
|
||||||
searchInfo.value = {}
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 搜索
|
|
||||||
const onSubmit = () => {
|
|
||||||
elSearchFormRef.value?.validate(async(valid) => {
|
|
||||||
if (!valid) return
|
|
||||||
page.value = 1
|
|
||||||
pageSize.value = 10
|
|
||||||
getTableData()
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 分页
|
const elFormRef = ref()
|
||||||
const handleSizeChange = (val) => {
|
const elSearchFormRef = ref()
|
||||||
pageSize.value = val
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改页面容量
|
// =========== 表格控制部分 ===========
|
||||||
const handleCurrentChange = (val) => {
|
const page = ref(1)
|
||||||
page.value = val
|
const total = ref(0)
|
||||||
getTableData()
|
const pageSize = ref(10)
|
||||||
}
|
const tableData = ref([])
|
||||||
|
const searchInfo = ref({})
|
||||||
|
|
||||||
// 查询
|
// 重置
|
||||||
const getTableData = async() => {
|
const onReset = () => {
|
||||||
const table = await getInfoList({ page: page.value, pageSize: pageSize.value, ...searchInfo.value })
|
searchInfo.value = {}
|
||||||
if (table.code === 0) {
|
getTableData()
|
||||||
tableData.value = table.data.list
|
|
||||||
total.value = table.data.total
|
|
||||||
page.value = table.data.page
|
|
||||||
pageSize.value = table.data.pageSize
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
getTableData()
|
// 搜索
|
||||||
|
const onSubmit = () => {
|
||||||
|
elSearchFormRef.value?.validate(async (valid) => {
|
||||||
|
if (!valid) return
|
||||||
|
page.value = 1
|
||||||
|
pageSize.value = 10
|
||||||
|
getTableData()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// ============== 表格控制部分结束 ===============
|
// 分页
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
// 获取需要的字典 可能为空 按需保留
|
// 修改页面容量
|
||||||
const setOptions = async () =>{
|
const handleCurrentChange = (val) => {
|
||||||
}
|
page.value = val
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
// 获取需要的字典 可能为空 按需保留
|
// 查询
|
||||||
setOptions()
|
const getTableData = async () => {
|
||||||
|
const table = await getInfoList({
|
||||||
|
page: page.value,
|
||||||
// 多选数据
|
pageSize: pageSize.value,
|
||||||
const multipleSelection = ref([])
|
...searchInfo.value
|
||||||
// 多选
|
})
|
||||||
const handleSelectionChange = (val) => {
|
if (table.code === 0) {
|
||||||
multipleSelection.value = val
|
tableData.value = table.data.list
|
||||||
}
|
total.value = table.data.total
|
||||||
|
page.value = table.data.page
|
||||||
// 删除行
|
pageSize.value = table.data.pageSize
|
||||||
const deleteRow = (row) => {
|
|
||||||
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(() => {
|
|
||||||
deleteInfoFunc(row)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 多选删除
|
getTableData()
|
||||||
const onDelete = async() => {
|
|
||||||
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
// ============== 表格控制部分结束 ===============
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
// 获取需要的字典 可能为空 按需保留
|
||||||
type: 'warning'
|
const setOptions = async () => {}
|
||||||
}).then(async() => {
|
|
||||||
|
// 获取需要的字典 可能为空 按需保留
|
||||||
|
setOptions()
|
||||||
|
|
||||||
|
// 多选数据
|
||||||
|
const multipleSelection = ref([])
|
||||||
|
// 多选
|
||||||
|
const handleSelectionChange = (val) => {
|
||||||
|
multipleSelection.value = val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除行
|
||||||
|
const deleteRow = (row) => {
|
||||||
|
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
deleteInfoFunc(row)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多选删除
|
||||||
|
const onDelete = async () => {
|
||||||
|
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(async () => {
|
||||||
const IDs = []
|
const IDs = []
|
||||||
if (multipleSelection.value.length === 0) {
|
if (multipleSelection.value.length === 0) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
|
|
@ -296,7 +398,7 @@ const onDelete = async() => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
multipleSelection.value &&
|
multipleSelection.value &&
|
||||||
multipleSelection.value.map(item => {
|
multipleSelection.value.map((item) => {
|
||||||
IDs.push(item.ID)
|
IDs.push(item.ID)
|
||||||
})
|
})
|
||||||
const res = await deleteInfoByIds({ IDs })
|
const res = await deleteInfoByIds({ IDs })
|
||||||
|
|
@ -310,104 +412,100 @@ const onDelete = async() => {
|
||||||
}
|
}
|
||||||
getTableData()
|
getTableData()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 行为控制标记(弹窗内部需要增还是改)
|
// 行为控制标记(弹窗内部需要增还是改)
|
||||||
const type = ref('')
|
const type = ref('')
|
||||||
|
|
||||||
// 更新行
|
// 更新行
|
||||||
const updateInfoFunc = async(row) => {
|
const updateInfoFunc = async (row) => {
|
||||||
const res = await findInfo({ ID: row.ID })
|
const res = await findInfo({ ID: row.ID })
|
||||||
type.value = 'update'
|
type.value = 'update'
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
formData.value = res.data
|
formData.value = res.data
|
||||||
dialogFormVisible.value = true
|
dialogFormVisible.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除行
|
||||||
// 删除行
|
const deleteInfoFunc = async (row) => {
|
||||||
const deleteInfoFunc = async (row) => {
|
|
||||||
const res = await deleteInfo({ ID: row.ID })
|
const res = await deleteInfo({ ID: row.ID })
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: '删除成功'
|
message: '删除成功'
|
||||||
})
|
})
|
||||||
if (tableData.value.length === 1 && page.value > 1) {
|
if (tableData.value.length === 1 && page.value > 1) {
|
||||||
page.value--
|
page.value--
|
||||||
}
|
}
|
||||||
getTableData()
|
getTableData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 弹窗控制标记
|
// 弹窗控制标记
|
||||||
const dialogFormVisible = ref(false)
|
const dialogFormVisible = ref(false)
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = () => {
|
const openDialog = () => {
|
||||||
type.value = 'create'
|
type.value = 'create'
|
||||||
dialogFormVisible.value = true
|
dialogFormVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭弹窗
|
// 关闭弹窗
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
dialogFormVisible.value = false
|
dialogFormVisible.value = false
|
||||||
formData.value = {
|
formData.value = {
|
||||||
title: '',
|
title: '',
|
||||||
content: '',
|
content: '',
|
||||||
userID: undefined,
|
userID: undefined,
|
||||||
attachments: [],
|
attachments: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 弹窗确定
|
// 弹窗确定
|
||||||
const enterDialog = async () => {
|
const enterDialog = async () => {
|
||||||
elFormRef.value?.validate( async (valid) => {
|
elFormRef.value?.validate(async (valid) => {
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
let res
|
let res
|
||||||
switch (type.value) {
|
switch (type.value) {
|
||||||
case 'create':
|
case 'create':
|
||||||
res = await createInfo(formData.value)
|
res = await createInfo(formData.value)
|
||||||
break
|
break
|
||||||
case 'update':
|
case 'update':
|
||||||
res = await updateInfo(formData.value)
|
res = await updateInfo(formData.value)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
res = await createInfo(formData.value)
|
res = await createInfo(formData.value)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: '创建/更改成功'
|
message: '创建/更改成功'
|
||||||
})
|
})
|
||||||
closeDialog()
|
closeDialog()
|
||||||
getTableData()
|
getTableData()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadFile = (url) => {
|
const downloadFile = (url) => {
|
||||||
window.open(getUrl(url), '_blank')
|
window.open(getUrl(url), '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.file-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.file-list{
|
.fileBtn {
|
||||||
display: flex;
|
margin-bottom: 10px;
|
||||||
flex-wrap: wrap;
|
}
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fileBtn{
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fileBtn:last-child{
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
.fileBtn:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -27,4 +27,3 @@ export const sendEmail = (data) => {
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<warning-bar title="需要提前配置email配置文件,为防止不必要的垃圾邮件,在线体验功能不开放此功能体验。" />
|
<warning-bar
|
||||||
|
title="需要提前配置email配置文件,为防止不必要的垃圾邮件,在线体验功能不开放此功能体验。"
|
||||||
|
/>
|
||||||
<div class="gva-form-box">
|
<div class="gva-form-box">
|
||||||
<el-form
|
<el-form
|
||||||
ref="emailForm"
|
ref="emailForm"
|
||||||
|
|
@ -15,10 +17,7 @@
|
||||||
<el-input v-model="form.subject" />
|
<el-input v-model="form.subject" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="邮件内容">
|
<el-form-item label="邮件内容">
|
||||||
<el-input
|
<el-input v-model="form.body" type="textarea" />
|
||||||
v-model="form.body"
|
|
||||||
type="textarea"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button @click="sendTestEmail">发送测试邮件</el-button>
|
<el-button @click="sendTestEmail">发送测试邮件</el-button>
|
||||||
|
|
@ -27,37 +26,35 @@
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import WarningBar from '@/components/warningBar/warningBar.vue'
|
import WarningBar from '@/components/warningBar/warningBar.vue'
|
||||||
import { emailTest } from '@/plugin/email/api/email.js'
|
import { emailTest } from '@/plugin/email/api/email.js'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Email',
|
name: 'Email'
|
||||||
})
|
})
|
||||||
|
|
||||||
const emailForm = ref(null)
|
const emailForm = ref(null)
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
to: '',
|
to: '',
|
||||||
subject: '',
|
subject: '',
|
||||||
body: '',
|
body: ''
|
||||||
})
|
})
|
||||||
const sendTestEmail = async() => {
|
const sendTestEmail = async () => {
|
||||||
const res = await emailTest()
|
const res = await emailTest()
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
ElMessage.success('发送成功')
|
ElMessage.success('发送成功')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const sendEmail = async() => {
|
const sendEmail = async () => {
|
||||||
const res = await emailTest()
|
const res = await emailTest()
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
ElMessage.success('发送成功,请查收')
|
ElMessage.success('发送成功,请查收')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,32 @@
|
||||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
|
|
||||||
const routes = [{
|
const routes = [
|
||||||
path: '/',
|
{
|
||||||
redirect: '/login'
|
path: '/',
|
||||||
},
|
redirect: '/login'
|
||||||
{
|
|
||||||
path: '/init',
|
|
||||||
name: 'Init',
|
|
||||||
component: () => import('@/view/init/index.vue')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/login',
|
|
||||||
name: 'Login',
|
|
||||||
component: () => import('@/view/login/index.vue')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/:catchAll(.*)',
|
|
||||||
meta: {
|
|
||||||
closeTab: true,
|
|
||||||
},
|
},
|
||||||
component: () => import('@/view/error/index.vue')
|
{
|
||||||
}
|
path: '/init',
|
||||||
|
name: 'Init',
|
||||||
|
component: () => import('@/view/init/index.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/login',
|
||||||
|
name: 'Login',
|
||||||
|
component: () => import('@/view/login/index.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/:catchAll(.*)',
|
||||||
|
meta: {
|
||||||
|
closeTab: true
|
||||||
|
},
|
||||||
|
component: () => import('@/view/error/index.vue')
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHashHistory(),
|
history: createWebHashHistory(),
|
||||||
routes,
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
|
@forward 'element-plus/theme-chalk/src/common/var.scss' with (
|
||||||
$colors: (
|
$colors: (
|
||||||
'white': #ffffff,
|
'white': #ffffff,
|
||||||
'black': #000000,
|
'black': #000000,
|
||||||
'primary': (
|
'primary': (
|
||||||
'base': #4d70ff,
|
'base': #4d70ff
|
||||||
),
|
),
|
||||||
'success': (
|
'success': (
|
||||||
'base': #67c23a,
|
'base': #67c23a
|
||||||
),
|
),
|
||||||
'warning': (
|
'warning': (
|
||||||
'base': #e6a23c,
|
'base': #e6a23c
|
||||||
),
|
),
|
||||||
'danger': (
|
'danger': (
|
||||||
'base': #f56c6c,
|
'base': #f56c6c
|
||||||
),
|
),
|
||||||
'error': (
|
'error': (
|
||||||
'base': #f56c6c,
|
'base': #f56c6c
|
||||||
),
|
),
|
||||||
'info': (
|
'info': (
|
||||||
'base': #909399,
|
'base': #909399
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,138 +1,136 @@
|
||||||
@use '@/style/main.scss';
|
@use '@/style/main.scss';
|
||||||
@use "@/style/reset";
|
@use '@/style/reset';
|
||||||
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
.el-button {
|
.el-button {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gva-pagination {
|
.gva-pagination {
|
||||||
@apply flex justify-end;
|
@apply flex justify-end;
|
||||||
.el-pagination__editor {
|
.el-pagination__editor {
|
||||||
.el-input__inner {
|
.el-input__inner {
|
||||||
@apply h-8;
|
@apply h-8;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.is-active {
|
.is-active {
|
||||||
@apply rounded text-white;
|
@apply rounded text-white;
|
||||||
background: var(--el-color-primary);
|
background: var(--el-color-primary);
|
||||||
color: #ffffff !important;
|
color: #ffffff !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-drawer__header {
|
||||||
.el-drawer__header{
|
margin-bottom: 0 !important;
|
||||||
margin-bottom: 0 !important;
|
padding-top: 16px !important;
|
||||||
padding-top: 16px !important;
|
padding-bottom: 16px !important;
|
||||||
padding-bottom: 16px !important;
|
@apply border-0 border-b border-solid border-gray-200;
|
||||||
@apply border-0 border-b border-solid border-gray-200;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.el-form--inline {
|
.el-form--inline {
|
||||||
.el-form-item {
|
.el-form-item {
|
||||||
& > .el-input, .el-cascader, .el-select, .el-date-editor, .el-autocomplete {
|
& > .el-input,
|
||||||
@apply w-52;
|
.el-cascader,
|
||||||
}
|
.el-select,
|
||||||
|
.el-date-editor,
|
||||||
|
.el-autocomplete {
|
||||||
|
@apply w-52;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-dropdown {
|
.el-dropdown {
|
||||||
@apply overflow-hidden
|
@apply overflow-hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.el-table {
|
.el-table {
|
||||||
tr{
|
tr {
|
||||||
th {
|
th {
|
||||||
@apply dark:bg-slate-900;
|
@apply dark:bg-slate-900;
|
||||||
.cell {
|
.cell {
|
||||||
@apply leading-[36px] text-gray-700 dark:text-gray-200;
|
@apply leading-[36px] text-gray-700 dark:text-gray-200;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.el-table__row {
|
}
|
||||||
td {
|
.el-table__row {
|
||||||
@apply dark:bg-slate-900;
|
td {
|
||||||
.cell {
|
@apply dark:bg-slate-900;
|
||||||
@apply leading-[32px] text-gray-600 dark:text-gray-300;
|
.cell {
|
||||||
}
|
@apply leading-[32px] text-gray-600 dark:text-gray-300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tr{
|
}
|
||||||
th{
|
tr {
|
||||||
&.is-leaf {
|
th {
|
||||||
@apply dark:bg-slate-900;
|
&.is-leaf {
|
||||||
}
|
@apply dark:bg-slate-900;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// layout
|
// layout
|
||||||
|
|
||||||
// table
|
// table
|
||||||
.el-pagination {
|
.el-pagination {
|
||||||
@apply mt-8;
|
@apply mt-8;
|
||||||
.btn-prev,
|
.btn-prev,
|
||||||
.btn-next {
|
.btn-next {
|
||||||
@apply border border-solid border-gray-300 dark:border-gray-700 rounded;
|
@apply border border-solid border-gray-300 dark:border-gray-700 rounded;
|
||||||
}
|
}
|
||||||
.el-pager {
|
.el-pager {
|
||||||
li {
|
li {
|
||||||
@apply border border-solid border-gray-300 dark:border-gray-600 rounded text-gray-600 text-sm mx-1;
|
@apply border border-solid border-gray-300 dark:border-gray-600 rounded text-gray-600 text-sm mx-1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.el-menu{
|
.el-menu {
|
||||||
li{
|
li {
|
||||||
@apply my-1;
|
@apply my-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.el-menu--vertical{
|
.el-menu--vertical {
|
||||||
.el-menu-item{
|
.el-menu-item {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
&.is-active{
|
&.is-active {
|
||||||
background-color: var(--el-color-primary) !important;
|
background-color: var(--el-color-primary) !important;
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-sub-menu.el-sub-menu__hide-arrow {
|
||||||
.el-sub-menu.el-sub-menu__hide-arrow{
|
height: 44px;
|
||||||
height: 44px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-tabs__header {
|
||||||
.el-tabs__header{
|
margin: 0 0 1px !important;
|
||||||
margin: 0 0 1px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-sub-menu.is-active{
|
.el-sub-menu.is-active {
|
||||||
> .el-sub-menu__title{
|
> .el-sub-menu__title {
|
||||||
color: var(--el-color-primary) !important;
|
color: var(--el-color-primary) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-sub-menu__title.el-tooltip__trigger,
|
.el-sub-menu__title.el-tooltip__trigger,
|
||||||
.el-menu-item .el-menu-tooltip__trigger{
|
.el-menu-item .el-menu-tooltip__trigger {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-menu--horizontal .el-menu .el-sub-menu__title{
|
.el-menu--horizontal .el-menu .el-sub-menu__title {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.dark {
|
html.dark {
|
||||||
/* 自定义深色背景颜色 */
|
/* 自定义深色背景颜色 */
|
||||||
--el-bg-color: rgb(30 ,41 ,59);
|
--el-bg-color: rgb(30, 41, 59);
|
||||||
--el-bg-color-overlay: rgb(40 ,51 ,69);
|
--el-bg-color-overlay: rgb(40, 51, 69);
|
||||||
--el-fill-color-light: rgb(15 ,23 ,42);
|
--el-fill-color-light: rgb(15, 23, 42);
|
||||||
--el-fill-color : rgb(15 ,23 ,42);
|
--el-fill-color: rgb(15, 23, 42);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,47 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'gvaIcon';
|
font-family: 'gvaIcon';
|
||||||
src: url('data:font/ttf;charset=utf-8;base64,AAEAAAANAIAAAwBQRkZUTZJUyU8AAA14AAAAHEdERUYAKQARAAANWAAAAB5PUy8yPJpJTAAAAVgAAABgY21hcM0T0L4AAAHYAAABWmdhc3D//wADAAANUAAAAAhnbHlmRk3UvwAAA0wAAAbYaGVhZB/a5jgAAADcAAAANmhoZWEHngOFAAABFAAAACRobXR4DaoBrAAAAbgAAAAebG9jYQbMCGgAAAM0AAAAGG1heHABGgB+AAABOAAAACBuYW1lXoIBAgAACiQAAAKCcG9zdN15OnUAAAyoAAAAqAABAAAAAQAA+a916l8PPPUACwQAAAAAAN5YUSMAAAAA3lhRIwBL/8ADwAM1AAAACAACAAAAAAAAAAEAAAOA/4AAXAQAAAAAAAPAAAEAAAAAAAAAAAAAAAAAAAAEAAEAAAALAHIABQAAAAAAAgAAAAoACgAAAP8AAAAAAAAABAQAAZAABQAAAokCzAAAAI8CiQLMAAAB6wAyAQgAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZADA5mXmfQOA/4AAAAPcAIAAAAABAAAAAAAAAAAAAAAgAAEEAAAAAAAAAAQAAAAEAACLAIoAYAB1AHYASwBLAGAAAAAAAAMAAAADAAAAHAABAAAAAABUAAMAAQAAABwABAA4AAAACgAIAAIAAuZm5mrmduZ9//8AAOZl5mrmdeZ7//8ZnhmbGZEZjQABAAAAAAAAAAAAAAAAAQYAAAEAAAAAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEYAigEcAbgCUAK6AxoDbAACAIsAIANsAswAEQAjAAAlIicBJjQ3ATYeAQYHCQEeAQYhIicBJjQ3ATYeAQYHCQEeAQYDSw0J/qsLCwFVChsSAgr+xAE8CgIV/qkNCP6qCgoBVgkbEgIK/sUBOwoCFCAJATULGQsBNQoCExwI/uL+4ggbFAkBNQsZCwE1CgITHAj+4v7iCRoUAAAAAAIAigAgA2sCzAARACIAAAE0JwEmDgEWFwkBDgEWMjcBNiUBJg4BFhcJAQ4BFjI3ATY0AiAL/qsJHBECCQE8/sQJAhQZCQFVCwFA/qsKGxICCgE8/sQKAhUZCQFVCwF1DQsBNQoCExwI/uL+4gkaFAkBNQskATUKAhMcCP7i/uIJGhQJATULGQADAGD/wAOgAzUATABcAGwAAAE1NCcmJyYiBwYHBh0BDgEdARQWOwEyNj0BNCYrATU0NzY3NjIXFhcWHQEjIgYdARQWOwEGBwYHLgEjIgYUFjMyNjc2NzY3PgE9ATQmBRUUBisBIiY9ATQ2OwEyFgUUBisBIiY9ATQ2OwEyFhUDYDAvT1O+U08vMBslLB9VHi0tHiAoJkFDnENBJiggHi0tHhUPJC5SChwRHCQkHBEeCHJAMxAfKiX9kAYFVQUGBgVVBQYCVQYFVQUGBgVVBQYByQxgUlAuMDAuUFJgDAQqG6seLCweqx4tCk5DQScnJydBQ04KLR6rHiwrGiAGDxElNiUSEAc1KkUBKx6rGyhFqwQGBgSrBQYGsAQGBgSrBQYGBQAABAB1//UDjQMLABsANwBSAHEAABMyNj0BFxYyNjQvATMyNjQmKwEiBwYHBh0BFBYFIgYdAScmIgYUHwEjIgYUFjsBMjc2NzY9ATYmJQc1NCYiBh0BFBcWFxY7ATI2NCYrATc2NCYGATQ1FSYnJisBIgYUFjsBBwYUFjI/ARUUFjI2PQEnJpUNE7wJHRMKvIcMFBQM1ggCDAgCFALiDRPJCRoTCcmJDBQUDNYIAg8CAwES/gbJExkUAggKBAbWDBQUDInJCRMXAgEHCwQG2AwUFAyJvAkSHgi8ExoTAgEB9RQMibwIEhkKvBMZFAIGDAQI1gwU6hQMickJExoJyRMZFAIICgQG2AwUIsmHDBQUDNYIAg8CAxQZE8kKGRMBAcABAQIOAwMUGRO8ChkTCbyHDBQUDNYFBAAABAB2//cDjgMMABoANQBRAG0AAAEjIgYUFjsBMjc2NzY9ATQmIgYdAScmIgYUFwEzMjY0JisBIgcGBwYdARQWMjY9ARcWMjY0JyUmJyYrASIGFBY7AQcGFBYyPwEVFBYyNj0BLgE3FhcWOwEyNjQmKwE3NjQmIg8BNTQmIgYdAR4BATqJDRMTDdUJAg8CAhMaE7cKGRQKAjeJDRMTDdUJAg8CAhMaE8gJHhIK/i8HCgQH1w0TEw2JyQoTHQnIFBkTAQKoBwoEBtYNExMNibwKFBkKvBMZFAICAhoUGRMCBwoEBtYNExMNib4KExoK/iAUGRMCBwoEB9UNExMNickIEhkK8w8CAhMZFMgKGRMJyYkNExMN1QIJzQ8CAhMZFLsKGhMKvIkNExMN1QMIAAAAAAUAS//LA7UDNQAUACkAKgA3AEQAAAEiBwYHBhQXFhcWMjc2NzY0JyYnJgMiJyYnJjQ3Njc2MhcWFxYUBwYHBgMjFB4BMj4BNC4BIg4BFyIGHQEUFjI2PQE0JgIAd2ZiOzs7O2Jm7mZiOzs7O2Jmd2VXVDIzMzJUV8pXVDIzMzJUV2UrDBQWFAwMFBYUDCsNExMaExMDNTs7YmbuZmI7Ozs7YmbuZmI7O/zWMzJUV8pXVDIzMzJUV8pXVDIzAjULFAwMFBYUDAwUgBQM6w0TEw3rDBQAAQBL/+ADwAMgAD0AAAEmBg8BLgEjIgcGBwYUFxYXFjMyPgE3Ni4BBgcOAiMiJyYnJjQ3Njc2MzIeARcnJg4BFh8BMj8BNj8BNCYDpgwXAxc5yXZyY184Ojo4X2NyWaB4HgULGhcFGWaJS2FUUTAwMTBRU2FIhGQbgA0WBw4NwgUIBAwDMQ0CsQMODFhmeDk3XmHiYV43OUV9UQ0XCQsMRWo6MC9PUr9TTy8wNmNBJQMOGhYDMwMBCAu6DRYAAAAAAgBg/8YDugMiAB4AMwAABSc+ATU0JyYnJiIHBgcGFBcWFxYzMjc2NxcWMjc2JiUiJyYnJjQ3Njc2MhcWFxYUBwYHBgOxviouNDFVV8lXVTIzMzJVV2RDPzwzvgkeCAcB/hxUSEYpKiopRkioSEYpKyspRkgCvjB9RGRYVDIzNDJVWMlXVTE0GBYqvgkJChuBKylGSKhIRikqKilGSKhIRikrAAAAABIA3gABAAAAAAAAABMAKAABAAAAAAABAAgATgABAAAAAAACAAcAZwABAAAAAAADAAgAgQABAAAAAAAEAAgAnAABAAAAAAAFAAsAvQABAAAAAAAGAAgA2wABAAAAAAAKACsBPAABAAAAAAALABMBkAADAAEECQAAACYAAAADAAEECQABABAAPAADAAEECQACAA4AVwADAAEECQADABAAbwADAAEECQAEABAAigADAAEECQAFABYApQADAAEECQAGABAAyQADAAEECQAKAFYA5AADAAEECQALACYBaABDAHIAZQBhAHQAZQBkACAAYgB5ACAAaQBjAG8AbgBmAG8AbgB0AABDcmVhdGVkIGJ5IGljb25mb250AABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABSAGUAZwB1AGwAYQByAABSZWd1bGFyAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABWAGUAcgBzAGkAbwBuACAAMQAuADAAAFZlcnNpb24gMS4wAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAHMAdgBnADIAdAB0AGYAIABmAHIAbwBtACAARgBvAG4AdABlAGwAbABvACAAcAByAG8AagBlAGMAdAAuAABHZW5lcmF0ZWQgYnkgc3ZnMnR0ZiBmcm9tIEZvbnRlbGxvIHByb2plY3QuAABoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAABodHRwOi8vZm9udGVsbG8uY29tAAAAAAIAAAAAAAAACgAAAAAAAQAAAAAAAAAAAAAAAAAAAAAACwAAAAEAAgECAQMBBAEFAQYBBwEIAQkRYXJyb3ctZG91YmxlLWxlZnQSYXJyb3ctZG91YmxlLXJpZ2h0EGN1c3RvbWVyLXNlcnZpY2URZnVsbHNjcmVlbi1leHBhbmQRZnVsbHNjcmVlbi1zaHJpbmsGcHJvbXB0B3JlZnJlc2gGc2VhcmNoAAAAAf//AAIAAQAAAAwAAAAWAAAAAgABAAMACgABAAQAAAACAAAAAAAAAAEAAAAA1aQnCAAAAADeWFEjAAAAAN5YUSM=') format('truetype');
|
src: url('data:font/ttf;charset=utf-8;base64,AAEAAAANAIAAAwBQRkZUTZJUyU8AAA14AAAAHEdERUYAKQARAAANWAAAAB5PUy8yPJpJTAAAAVgAAABgY21hcM0T0L4AAAHYAAABWmdhc3D//wADAAANUAAAAAhnbHlmRk3UvwAAA0wAAAbYaGVhZB/a5jgAAADcAAAANmhoZWEHngOFAAABFAAAACRobXR4DaoBrAAAAbgAAAAebG9jYQbMCGgAAAM0AAAAGG1heHABGgB+AAABOAAAACBuYW1lXoIBAgAACiQAAAKCcG9zdN15OnUAAAyoAAAAqAABAAAAAQAA+a916l8PPPUACwQAAAAAAN5YUSMAAAAA3lhRIwBL/8ADwAM1AAAACAACAAAAAAAAAAEAAAOA/4AAXAQAAAAAAAPAAAEAAAAAAAAAAAAAAAAAAAAEAAEAAAALAHIABQAAAAAAAgAAAAoACgAAAP8AAAAAAAAABAQAAZAABQAAAokCzAAAAI8CiQLMAAAB6wAyAQgAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZADA5mXmfQOA/4AAAAPcAIAAAAABAAAAAAAAAAAAAAAgAAEEAAAAAAAAAAQAAAAEAACLAIoAYAB1AHYASwBLAGAAAAAAAAMAAAADAAAAHAABAAAAAABUAAMAAQAAABwABAA4AAAACgAIAAIAAuZm5mrmduZ9//8AAOZl5mrmdeZ7//8ZnhmbGZEZjQABAAAAAAAAAAAAAAAAAQYAAAEAAAAAAAAAAQIAAAACAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEYAigEcAbgCUAK6AxoDbAACAIsAIANsAswAEQAjAAAlIicBJjQ3ATYeAQYHCQEeAQYhIicBJjQ3ATYeAQYHCQEeAQYDSw0J/qsLCwFVChsSAgr+xAE8CgIV/qkNCP6qCgoBVgkbEgIK/sUBOwoCFCAJATULGQsBNQoCExwI/uL+4ggbFAkBNQsZCwE1CgITHAj+4v7iCRoUAAAAAAIAigAgA2sCzAARACIAAAE0JwEmDgEWFwkBDgEWMjcBNiUBJg4BFhcJAQ4BFjI3ATY0AiAL/qsJHBECCQE8/sQJAhQZCQFVCwFA/qsKGxICCgE8/sQKAhUZCQFVCwF1DQsBNQoCExwI/uL+4gkaFAkBNQskATUKAhMcCP7i/uIJGhQJATULGQADAGD/wAOgAzUATABcAGwAAAE1NCcmJyYiBwYHBh0BDgEdARQWOwEyNj0BNCYrATU0NzY3NjIXFhcWHQEjIgYdARQWOwEGBwYHLgEjIgYUFjMyNjc2NzY3PgE9ATQmBRUUBisBIiY9ATQ2OwEyFgUUBisBIiY9ATQ2OwEyFhUDYDAvT1O+U08vMBslLB9VHi0tHiAoJkFDnENBJiggHi0tHhUPJC5SChwRHCQkHBEeCHJAMxAfKiX9kAYFVQUGBgVVBQYCVQYFVQUGBgVVBQYByQxgUlAuMDAuUFJgDAQqG6seLCweqx4tCk5DQScnJydBQ04KLR6rHiwrGiAGDxElNiUSEAc1KkUBKx6rGyhFqwQGBgSrBQYGsAQGBgSrBQYGBQAABAB1//UDjQMLABsANwBSAHEAABMyNj0BFxYyNjQvATMyNjQmKwEiBwYHBh0BFBYFIgYdAScmIgYUHwEjIgYUFjsBMjc2NzY9ATYmJQc1NCYiBh0BFBcWFxY7ATI2NCYrATc2NCYGATQ1FSYnJisBIgYUFjsBBwYUFjI/ARUUFjI2PQEnJpUNE7wJHRMKvIcMFBQM1ggCDAgCFALiDRPJCRoTCcmJDBQUDNYIAg8CAwES/gbJExkUAggKBAbWDBQUDInJCRMXAgEHCwQG2AwUFAyJvAkSHgi8ExoTAgEB9RQMibwIEhkKvBMZFAIGDAQI1gwU6hQMickJExoJyRMZFAIICgQG2AwUIsmHDBQUDNYIAg8CAxQZE8kKGRMBAcABAQIOAwMUGRO8ChkTCbyHDBQUDNYFBAAABAB2//cDjgMMABoANQBRAG0AAAEjIgYUFjsBMjc2NzY9ATQmIgYdAScmIgYUFwEzMjY0JisBIgcGBwYdARQWMjY9ARcWMjY0JyUmJyYrASIGFBY7AQcGFBYyPwEVFBYyNj0BLgE3FhcWOwEyNjQmKwE3NjQmIg8BNTQmIgYdAR4BATqJDRMTDdUJAg8CAhMaE7cKGRQKAjeJDRMTDdUJAg8CAhMaE8gJHhIK/i8HCgQH1w0TEw2JyQoTHQnIFBkTAQKoBwoEBtYNExMNibwKFBkKvBMZFAICAhoUGRMCBwoEBtYNExMNib4KExoK/iAUGRMCBwoEB9UNExMNickIEhkK8w8CAhMZFMgKGRMJyYkNExMN1QIJzQ8CAhMZFLsKGhMKvIkNExMN1QMIAAAAAAUAS//LA7UDNQAUACkAKgA3AEQAAAEiBwYHBhQXFhcWMjc2NzY0JyYnJgMiJyYnJjQ3Njc2MhcWFxYUBwYHBgMjFB4BMj4BNC4BIg4BFyIGHQEUFjI2PQE0JgIAd2ZiOzs7O2Jm7mZiOzs7O2Jmd2VXVDIzMzJUV8pXVDIzMzJUV2UrDBQWFAwMFBYUDCsNExMaExMDNTs7YmbuZmI7Ozs7YmbuZmI7O/zWMzJUV8pXVDIzMzJUV8pXVDIzAjULFAwMFBYUDAwUgBQM6w0TEw3rDBQAAQBL/+ADwAMgAD0AAAEmBg8BLgEjIgcGBwYUFxYXFjMyPgE3Ni4BBgcOAiMiJyYnJjQ3Njc2MzIeARcnJg4BFh8BMj8BNj8BNCYDpgwXAxc5yXZyY184Ojo4X2NyWaB4HgULGhcFGWaJS2FUUTAwMTBRU2FIhGQbgA0WBw4NwgUIBAwDMQ0CsQMODFhmeDk3XmHiYV43OUV9UQ0XCQsMRWo6MC9PUr9TTy8wNmNBJQMOGhYDMwMBCAu6DRYAAAAAAgBg/8YDugMiAB4AMwAABSc+ATU0JyYnJiIHBgcGFBcWFxYzMjc2NxcWMjc2JiUiJyYnJjQ3Njc2MhcWFxYUBwYHBgOxviouNDFVV8lXVTIzMzJVV2RDPzwzvgkeCAcB/hxUSEYpKiopRkioSEYpKyspRkgCvjB9RGRYVDIzNDJVWMlXVTE0GBYqvgkJChuBKylGSKhIRikqKilGSKhIRikrAAAAABIA3gABAAAAAAAAABMAKAABAAAAAAABAAgATgABAAAAAAACAAcAZwABAAAAAAADAAgAgQABAAAAAAAEAAgAnAABAAAAAAAFAAsAvQABAAAAAAAGAAgA2wABAAAAAAAKACsBPAABAAAAAAALABMBkAADAAEECQAAACYAAAADAAEECQABABAAPAADAAEECQACAA4AVwADAAEECQADABAAbwADAAEECQAEABAAigADAAEECQAFABYApQADAAEECQAGABAAyQADAAEECQAKAFYA5AADAAEECQALACYBaABDAHIAZQBhAHQAZQBkACAAYgB5ACAAaQBjAG8AbgBmAG8AbgB0AABDcmVhdGVkIGJ5IGljb25mb250AABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABSAGUAZwB1AGwAYQByAABSZWd1bGFyAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABWAGUAcgBzAGkAbwBuACAAMQAuADAAAFZlcnNpb24gMS4wAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAHMAdgBnADIAdAB0AGYAIABmAHIAbwBtACAARgBvAG4AdABlAGwAbABvACAAcAByAG8AagBlAGMAdAAuAABHZW5lcmF0ZWQgYnkgc3ZnMnR0ZiBmcm9tIEZvbnRlbGxvIHByb2plY3QuAABoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAABodHRwOi8vZm9udGVsbG8uY29tAAAAAAIAAAAAAAAACgAAAAAAAQAAAAAAAAAAAAAAAAAAAAAACwAAAAEAAgECAQMBBAEFAQYBBwEIAQkRYXJyb3ctZG91YmxlLWxlZnQSYXJyb3ctZG91YmxlLXJpZ2h0EGN1c3RvbWVyLXNlcnZpY2URZnVsbHNjcmVlbi1leHBhbmQRZnVsbHNjcmVlbi1zaHJpbmsGcHJvbXB0B3JlZnJlc2gGc2VhcmNoAAAAAf//AAIAAQAAAAwAAAAWAAAAAgABAAMACgABAAQAAAACAAAAAAAAAAEAAAAA1aQnCAAAAADeWFEjAAAAAN5YUSM=')
|
||||||
font-weight: 600;
|
format('truetype');
|
||||||
font-style: normal;
|
font-weight: 600;
|
||||||
font-display: swap;
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
}
|
}
|
||||||
.gvaIcon {
|
.gvaIcon {
|
||||||
font-family: "gvaIcon" !important;
|
font-family: 'gvaIcon' !important;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gvaIcon-arrow-double-left:before {
|
.gvaIcon-arrow-double-left:before {
|
||||||
content: "\e665";
|
content: '\e665';
|
||||||
}
|
}
|
||||||
|
|
||||||
.gvaIcon-arrow-double-right:before {
|
.gvaIcon-arrow-double-right:before {
|
||||||
content: "\e666";
|
content: '\e666';
|
||||||
}
|
}
|
||||||
|
|
||||||
.gvaIcon-fullscreen-shrink:before {
|
.gvaIcon-fullscreen-shrink:before {
|
||||||
content: "\e676";
|
content: '\e676';
|
||||||
}
|
}
|
||||||
.gvaIcon-customer-service:before {
|
.gvaIcon-customer-service:before {
|
||||||
content: "\e66a";
|
content: '\e66a';
|
||||||
}
|
}
|
||||||
|
|
||||||
.gvaIcon-fullscreen-expand:before {
|
.gvaIcon-fullscreen-expand:before {
|
||||||
content: "\e675";
|
content: '\e675';
|
||||||
}
|
}
|
||||||
|
|
||||||
.gvaIcon-prompt:before {
|
.gvaIcon-prompt:before {
|
||||||
content: "\e67b";
|
content: '\e67b';
|
||||||
}
|
}
|
||||||
|
|
||||||
.gvaIcon-refresh:before {
|
.gvaIcon-refresh:before {
|
||||||
content: "\e67c";
|
content: '\e67c';
|
||||||
}
|
}
|
||||||
|
|
||||||
.gvaIcon-search:before {
|
.gvaIcon-search:before {
|
||||||
content: "\e67d";
|
content: '\e67d';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,53 +1,50 @@
|
||||||
|
|
||||||
@use '@/style/iconfont.css';
|
@use '@/style/iconfont.css';
|
||||||
|
|
||||||
.html-grey{
|
.html-grey {
|
||||||
filter: grayscale(100%);
|
filter: grayscale(100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.html-weakenss{
|
.html-weakenss {
|
||||||
filter: invert(80%);
|
filter: invert(80%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.gva-table-box {
|
.gva-table-box {
|
||||||
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2;
|
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2;
|
||||||
.el-table{
|
.el-table {
|
||||||
@apply border-x border-t border-b-0 rounded border-table-border border-solid -mx-[1px];
|
@apply border-x border-t border-b-0 rounded border-table-border border-solid -mx-[1px];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.gva-btn-list {
|
.gva-btn-list {
|
||||||
@apply mb-3 flex items-center;
|
@apply mb-3 flex items-center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#nprogress .bar {
|
#nprogress .bar {
|
||||||
background: #29d !important;
|
background: #29d !important;
|
||||||
}
|
}
|
||||||
.gva-customer-icon{
|
.gva-customer-icon {
|
||||||
@apply w-4 h-4;
|
@apply w-4 h-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
@apply hidden;
|
@apply hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.gva-search-box {
|
.gva-search-box {
|
||||||
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2;
|
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gva-form-box {
|
.gva-form-box {
|
||||||
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2;
|
@apply p-4 bg-white text-slate-700 dark:text-slate-400 dark:bg-slate-900 rounded my-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content{
|
.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
|
||||||
background: var(--el-color-primary-bg) !important;
|
background: var(--el-color-primary-bg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-dropdown{
|
.el-dropdown {
|
||||||
|
outline: none;
|
||||||
|
* {
|
||||||
outline: none;
|
outline: none;
|
||||||
*{
|
}
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/* Document
|
/* Document
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Correct the line height in all browsers.
|
* 1. Correct the line height in all browsers.
|
||||||
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||||
|
|
@ -14,11 +13,9 @@ html {
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Sections
|
/* Sections
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the margin in all browsers.
|
* Remove the margin in all browsers.
|
||||||
*/
|
*/
|
||||||
|
|
@ -27,7 +24,6 @@ body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the `main` element consistently in IE.
|
* Render the `main` element consistently in IE.
|
||||||
*/
|
*/
|
||||||
|
|
@ -36,7 +32,6 @@ main {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Correct the font size and margin on `h1` elements within `section` and
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
* `article` contexts in Chrome, Firefox, and Safari.
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
|
@ -47,11 +42,9 @@ h1 {
|
||||||
margin: 0.67em 0;
|
margin: 0.67em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Grouping content
|
/* Grouping content
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Add the correct box sizing in Firefox.
|
* 1. Add the correct box sizing in Firefox.
|
||||||
* 2. Show the overflow in Edge and IE.
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
|
@ -66,7 +59,6 @@ hr {
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
* 2. Correct the odd `em` font sizing in all browsers.
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
|
@ -79,11 +71,9 @@ pre {
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Text-level semantics
|
/* Text-level semantics
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the gray background on active links in IE 10.
|
* Remove the gray background on active links in IE 10.
|
||||||
*/
|
*/
|
||||||
|
|
@ -92,7 +82,6 @@ a {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Remove the bottom border in Chrome 57-
|
* 1. Remove the bottom border in Chrome 57-
|
||||||
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
|
@ -107,7 +96,6 @@ abbr[title] {
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the correct font weight in Chrome, Edge, and Safari.
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
*/
|
*/
|
||||||
|
|
@ -117,7 +105,6 @@ strong {
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Correct the inheritance and scaling of font size in all browsers.
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
* 2. Correct the odd `em` font sizing in all browsers.
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
|
@ -132,7 +119,6 @@ samp {
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the correct font size in all browsers.
|
* Add the correct font size in all browsers.
|
||||||
*/
|
*/
|
||||||
|
|
@ -141,7 +127,6 @@ small {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevent `sub` and `sup` elements from affecting the line height in
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
* all browsers.
|
* all browsers.
|
||||||
|
|
@ -163,11 +148,9 @@ sup {
|
||||||
top: -0.5em;
|
top: -0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Embedded content
|
/* Embedded content
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the border on images inside links in IE 10.
|
* Remove the border on images inside links in IE 10.
|
||||||
*/
|
*/
|
||||||
|
|
@ -176,11 +159,9 @@ img {
|
||||||
border-style: none;
|
border-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Forms
|
/* Forms
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Change the font styles in all browsers.
|
* 1. Change the font styles in all browsers.
|
||||||
* 2. Remove the margin in Firefox and Safari.
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
|
@ -201,7 +182,6 @@ textarea {
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the overflow in IE.
|
* Show the overflow in IE.
|
||||||
* 1. Show the overflow in Edge.
|
* 1. Show the overflow in Edge.
|
||||||
|
|
@ -213,7 +193,6 @@ input {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
* 1. Remove the inheritance of text transform in Firefox.
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
|
@ -225,44 +204,40 @@ select {
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Correct the inability to style clickable types in iOS and Safari.
|
* Correct the inability to style clickable types in iOS and Safari.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
button,
|
button,
|
||||||
[type="button"],
|
[type='button'],
|
||||||
[type="reset"],
|
[type='reset'],
|
||||||
[type="submit"] {
|
[type='submit'] {
|
||||||
-webkit-appearance: button;
|
-webkit-appearance: button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the inner border and padding in Firefox.
|
* Remove the inner border and padding in Firefox.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
button::-moz-focus-inner,
|
||||||
[type="button"]::-moz-focus-inner,
|
[type='button']::-moz-focus-inner,
|
||||||
[type="reset"]::-moz-focus-inner,
|
[type='reset']::-moz-focus-inner,
|
||||||
[type="submit"]::-moz-focus-inner {
|
[type='submit']::-moz-focus-inner {
|
||||||
border-style: none;
|
border-style: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore the focus styles unset by the previous rule.
|
* Restore the focus styles unset by the previous rule.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
button:-moz-focusring,
|
button:-moz-focusring,
|
||||||
[type="button"]:-moz-focusring,
|
[type='button']:-moz-focusring,
|
||||||
[type="reset"]:-moz-focusring,
|
[type='reset']:-moz-focusring,
|
||||||
[type="submit"]:-moz-focusring {
|
[type='submit']:-moz-focusring {
|
||||||
outline: 1px dotted ButtonText;
|
outline: 1px dotted ButtonText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Correct the padding in Firefox.
|
* Correct the padding in Firefox.
|
||||||
*/
|
*/
|
||||||
|
|
@ -271,7 +246,6 @@ fieldset {
|
||||||
padding: 0.35em 0.75em 0.625em;
|
padding: 0.35em 0.75em 0.625em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Correct the text wrapping in Edge and IE.
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
|
@ -294,7 +268,6 @@ legend {
|
||||||
/* 1 */
|
/* 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
*/
|
*/
|
||||||
|
|
@ -303,7 +276,6 @@ progress {
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the default vertical scrollbar in IE 10+.
|
* Remove the default vertical scrollbar in IE 10+.
|
||||||
*/
|
*/
|
||||||
|
|
@ -312,53 +284,48 @@ textarea {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Add the correct box sizing in IE 10.
|
* 1. Add the correct box sizing in IE 10.
|
||||||
* 2. Remove the padding in IE 10.
|
* 2. Remove the padding in IE 10.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[type="checkbox"],
|
[type='checkbox'],
|
||||||
[type="radio"] {
|
[type='radio'] {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
/* 1 */
|
/* 1 */
|
||||||
padding: 0;
|
padding: 0;
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Correct the cursor style of increment and decrement buttons in Chrome.
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[type="number"]::-webkit-inner-spin-button,
|
[type='number']::-webkit-inner-spin-button,
|
||||||
[type="number"]::-webkit-outer-spin-button {
|
[type='number']::-webkit-outer-spin-button {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Correct the odd appearance in Chrome and Safari.
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
* 2. Correct the outline style in Safari.
|
* 2. Correct the outline style in Safari.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[type="search"] {
|
[type='search'] {
|
||||||
-webkit-appearance: textfield;
|
-webkit-appearance: textfield;
|
||||||
/* 1 */
|
/* 1 */
|
||||||
outline-offset: -2px;
|
outline-offset: -2px;
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the inner padding in Chrome and Safari on macOS.
|
* Remove the inner padding in Chrome and Safari on macOS.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[type="search"]::-webkit-search-decoration {
|
[type='search']::-webkit-search-decoration {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1. Correct the inability to style clickable types in iOS and Safari.
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
* 2. Change font properties to `inherit` in Safari.
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
|
@ -371,11 +338,9 @@ textarea {
|
||||||
/* 2 */
|
/* 2 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Interactive
|
/* Interactive
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add the correct display in Edge, IE 10+, and Firefox.
|
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||||
*/
|
*/
|
||||||
|
|
@ -384,7 +349,6 @@ details {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add the correct display in all browsers.
|
* Add the correct display in all browsers.
|
||||||
*/
|
*/
|
||||||
|
|
@ -393,11 +357,9 @@ summary {
|
||||||
display: list-item;
|
display: list-item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Misc
|
/* Misc
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the correct display in IE 10+.
|
* Add the correct display in IE 10+.
|
||||||
*/
|
*/
|
||||||
|
|
@ -406,7 +368,6 @@ template {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the correct display in IE 10.
|
* Add the correct display in IE 10.
|
||||||
*/
|
*/
|
||||||
|
|
@ -433,7 +394,8 @@ table,
|
||||||
th,
|
th,
|
||||||
td {
|
td {
|
||||||
border: none;
|
border: none;
|
||||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB',
|
||||||
|
'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
|
|
@ -486,8 +448,8 @@ input::-moz-placeholder {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=submit],
|
input[type='submit'],
|
||||||
input[type=button] {
|
input[type='button'] {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ const viewModules = import.meta.glob('../view/**/*.vue')
|
||||||
const pluginModules = import.meta.glob('../plugin/**/*.vue')
|
const pluginModules = import.meta.glob('../plugin/**/*.vue')
|
||||||
|
|
||||||
export const asyncRouterHandle = (asyncRouter) => {
|
export const asyncRouterHandle = (asyncRouter) => {
|
||||||
asyncRouter.forEach(item => {
|
asyncRouter.forEach((item) => {
|
||||||
if (item.component && typeof item.component === 'string') {
|
if (item.component && typeof item.component === 'string') {
|
||||||
item.meta.path = "/src/"+item.component
|
item.meta.path = '/src/' + item.component
|
||||||
if (item.component.split('/')[0] === 'view') {
|
if (item.component.split('/')[0] === 'view') {
|
||||||
item.component = dynamicImport(viewModules, item.component)
|
item.component = dynamicImport(viewModules, item.component)
|
||||||
} else if (item.component.split('/')[0] === 'plugin') {
|
} else if (item.component.split('/')[0] === 'plugin') {
|
||||||
|
|
@ -17,10 +17,7 @@ export const asyncRouterHandle = (asyncRouter) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function dynamicImport(
|
function dynamicImport(dynamicViewsModules, component) {
|
||||||
dynamicViewsModules,
|
|
||||||
component
|
|
||||||
) {
|
|
||||||
const keys = Object.keys(dynamicViewsModules)
|
const keys = Object.keys(dynamicViewsModules)
|
||||||
const matchKeys = keys.filter((key) => {
|
const matchKeys = keys.filter((key) => {
|
||||||
const k = key.replace('../', '')
|
const k = key.replace('../', '')
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
// using ES6 modules
|
// using ES6 modules
|
||||||
import mitt from 'mitt'
|
import mitt from 'mitt'
|
||||||
|
|
||||||
export const emitter = mitt()
|
export const emitter = mitt()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
|
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
|
||||||
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
|
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
|
||||||
// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
|
// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
|
||||||
Date.prototype.Format = function(fmt) {
|
Date.prototype.Format = function (fmt) {
|
||||||
const o = {
|
const o = {
|
||||||
'M+': this.getMonth() + 1, // 月份
|
'M+': this.getMonth() + 1, // 月份
|
||||||
'd+': this.getDate(), // 日
|
'd+': this.getDate(), // 日
|
||||||
|
|
@ -11,11 +11,21 @@ Date.prototype.Format = function(fmt) {
|
||||||
'm+': this.getMinutes(), // 分
|
'm+': this.getMinutes(), // 分
|
||||||
's+': this.getSeconds(), // 秒
|
's+': this.getSeconds(), // 秒
|
||||||
'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
|
'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
|
||||||
'S': this.getMilliseconds() // 毫秒
|
S: this.getMilliseconds() // 毫秒
|
||||||
|
}
|
||||||
|
if (/(y+)/.test(fmt)) {
|
||||||
|
fmt = fmt.replace(
|
||||||
|
RegExp.$1,
|
||||||
|
(this.getFullYear() + '').substr(4 - RegExp.$1.length)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length)) }
|
|
||||||
for (const k in o) {
|
for (const k in o) {
|
||||||
if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))) }
|
if (new RegExp('(' + k + ')').test(fmt)) {
|
||||||
|
fmt = fmt.replace(
|
||||||
|
RegExp.$1,
|
||||||
|
RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return fmt
|
return fmt
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useDictionaryStore } from '@/pinia/modules/dictionary'
|
import { useDictionaryStore } from '@/pinia/modules/dictionary'
|
||||||
import { getSysParam } from '@/api/sysParams'
|
import { getSysParam } from '@/api/sysParams'
|
||||||
// 获取字典方法 使用示例 getDict('sex').then(res) 或者 async函数下 const res = await getDict('sex')
|
// 获取字典方法 使用示例 getDict('sex').then(res) 或者 async函数下 const res = await getDict('sex')
|
||||||
export const getDict = async(type) => {
|
export const getDict = async (type) => {
|
||||||
const dictionaryStore = useDictionaryStore()
|
const dictionaryStore = useDictionaryStore()
|
||||||
await dictionaryStore.getDictionary(type)
|
await dictionaryStore.getDictionary(type)
|
||||||
return dictionaryStore.dictionaryMap[type]
|
return dictionaryStore.dictionaryMap[type]
|
||||||
|
|
@ -18,7 +18,7 @@ export const showDictLabel = (
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
const dictMap = {}
|
const dictMap = {}
|
||||||
dict.forEach(item => {
|
dict.forEach((item) => {
|
||||||
if (Reflect.has(item, keyCode) && Reflect.has(item, valueCode)) {
|
if (Reflect.has(item, keyCode) && Reflect.has(item, valueCode)) {
|
||||||
dictMap[item[keyCode]] = item[valueCode]
|
dictMap[item[keyCode]] = item[valueCode]
|
||||||
}
|
}
|
||||||
|
|
@ -26,10 +26,9 @@ export const showDictLabel = (
|
||||||
return Reflect.has(dictMap, code) ? dictMap[code] : ''
|
return Reflect.has(dictMap, code) ? dictMap[code] : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getParams = async (key) => {
|
||||||
export const getParams = async (key)=>{
|
const res = await getSysParam({ key })
|
||||||
const res = await getSysParam({key})
|
if (res.code === 0) {
|
||||||
if(res.code === 0){
|
|
||||||
return res.data.value
|
return res.data.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
export const downloadImage = (imgsrc, name) => { // 下载图片地址和图片名
|
export const downloadImage = (imgsrc, name) => {
|
||||||
|
// 下载图片地址和图片名
|
||||||
var image = new Image()
|
var image = new Image()
|
||||||
image.setAttribute('crossOrigin', 'anonymous')
|
image.setAttribute('crossOrigin', 'anonymous')
|
||||||
image.onload = function() {
|
image.onload = function () {
|
||||||
var canvas = document.createElement('canvas')
|
var canvas = document.createElement('canvas')
|
||||||
canvas.width = image.width
|
canvas.width = image.width
|
||||||
canvas.height = image.height
|
canvas.height = image.height
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,17 @@
|
||||||
export function addEventListen(
|
export function addEventListen(target, event, handler, capture = false) {
|
||||||
target,
|
|
||||||
event,
|
|
||||||
handler,
|
|
||||||
capture = false
|
|
||||||
) {
|
|
||||||
if (
|
if (
|
||||||
target.addEventListener &&
|
target.addEventListener &&
|
||||||
typeof target.addEventListener === 'function'
|
typeof target.addEventListener === 'function'
|
||||||
) {
|
) {
|
||||||
target.addEventListener(event, handler, capture);
|
target.addEventListener(event, handler, capture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeEventListen(
|
export function removeEventListen(target, event, handler, capture = false) {
|
||||||
target,
|
|
||||||
event,
|
|
||||||
handler,
|
|
||||||
capture = false
|
|
||||||
) {
|
|
||||||
if (
|
if (
|
||||||
target.removeEventListener &&
|
target.removeEventListener &&
|
||||||
typeof target.removeEventListener === 'function'
|
typeof target.removeEventListener === 'function'
|
||||||
) {
|
) {
|
||||||
target.removeEventListener(event, handler, capture);
|
target.removeEventListener(event, handler, capture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { formatTimeToStr } from '@/utils/date'
|
import { formatTimeToStr } from '@/utils/date'
|
||||||
import { getDict } from '@/utils/dictionary'
|
import { getDict } from '@/utils/dictionary'
|
||||||
import {ref} from "vue";
|
import { ref } from 'vue'
|
||||||
|
|
||||||
export const formatBoolean = (bool) => {
|
export const formatBoolean = (bool) => {
|
||||||
if (bool !== null) {
|
if (bool !== null) {
|
||||||
|
|
@ -19,30 +19,32 @@ export const formatDate = (time) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const filterDict = (value, options) => {
|
export const filterDict = (value, options) => {
|
||||||
const rowLabel = options && options.filter(item => item.value === value)
|
const rowLabel = options && options.filter((item) => item.value === value)
|
||||||
return rowLabel && rowLabel[0] && rowLabel[0].label
|
return rowLabel && rowLabel[0] && rowLabel[0].label
|
||||||
}
|
}
|
||||||
|
|
||||||
export const filterDataSource = (dataSource, value) => {
|
export const filterDataSource = (dataSource, value) => {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return value.map(item => {
|
return value.map((item) => {
|
||||||
const rowLabel = dataSource && dataSource.find(i => i.value === item)
|
const rowLabel = dataSource && dataSource.find((i) => i.value === item)
|
||||||
return rowLabel?.label
|
return rowLabel?.label
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const rowLabel = dataSource && dataSource.find(item => item.value === value)
|
const rowLabel = dataSource && dataSource.find((item) => item.value === value)
|
||||||
return rowLabel?.label
|
return rowLabel?.label
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getDictFunc = async(type) => {
|
export const getDictFunc = async (type) => {
|
||||||
const dicts = await getDict(type)
|
const dicts = await getDict(type)
|
||||||
return dicts
|
return dicts
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = import.meta.env.VITE_BASE_PATH + ':' + import.meta.env.VITE_SERVER_PORT + '/'
|
const path =
|
||||||
|
import.meta.env.VITE_BASE_PATH + ':' + import.meta.env.VITE_SERVER_PORT + '/'
|
||||||
export const ReturnArrImg = (arr) => {
|
export const ReturnArrImg = (arr) => {
|
||||||
const imgArr = []
|
const imgArr = []
|
||||||
if (arr instanceof Array) { // 如果是数组类型
|
if (arr instanceof Array) {
|
||||||
|
// 如果是数组类型
|
||||||
for (const arrKey in arr) {
|
for (const arrKey in arr) {
|
||||||
if (arr[arrKey].slice(0, 4) !== 'http') {
|
if (arr[arrKey].slice(0, 4) !== 'http') {
|
||||||
imgArr.push(path + arr[arrKey])
|
imgArr.push(path + arr[arrKey])
|
||||||
|
|
@ -50,7 +52,8 @@ export const ReturnArrImg = (arr) => {
|
||||||
imgArr.push(arr[arrKey])
|
imgArr.push(arr[arrKey])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // 如果不是数组类型
|
} else {
|
||||||
|
// 如果不是数组类型
|
||||||
if (arr.slice(0, 4) !== 'http') {
|
if (arr.slice(0, 4) !== 'http') {
|
||||||
imgArr.push(path + arr)
|
imgArr.push(path + arr)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -65,65 +68,69 @@ export const returnArrImg = ReturnArrImg
|
||||||
export const onDownloadFile = (url) => {
|
export const onDownloadFile = (url) => {
|
||||||
window.open(path + url)
|
window.open(path + url)
|
||||||
}
|
}
|
||||||
const colorToHex = u=>{
|
const colorToHex = (u) => {
|
||||||
let e = u.replace("#", "").match(/../g);
|
let e = u.replace('#', '').match(/../g)
|
||||||
for (let t = 0; t < 3; t++)
|
for (let t = 0; t < 3; t++) e[t] = parseInt(e[t], 16)
|
||||||
e[t] = parseInt(e[t], 16);
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
const hexToColor = (u,e,t)=>{
|
const hexToColor = (u, e, t) => {
|
||||||
let a = [u.toString(16), e.toString(16), t.toString(16)];
|
let a = [u.toString(16), e.toString(16), t.toString(16)]
|
||||||
for (let n = 0; n < 3; n++)
|
for (let n = 0; n < 3; n++) a[n].length === 1 && (a[n] = `0${a[n]}`)
|
||||||
a[n].length === 1 && (a[n] = `0${a[n]}`);
|
return `#${a.join('')}`
|
||||||
return `#${a.join("")}`
|
|
||||||
}
|
}
|
||||||
const generateAllColors = (u,e)=> {
|
const generateAllColors = (u, e) => {
|
||||||
let t = colorToHex(u);
|
let t = colorToHex(u)
|
||||||
const target = [10, 10, 30];
|
const target = [10, 10, 30]
|
||||||
for (let a = 0; a < 3; a++)
|
for (let a = 0; a < 3; a++) t[a] = Math.floor(t[a] * (1 - e) + target[a] * e)
|
||||||
t[a] = Math.floor(t[a] * (1 - e) + target[a] * e);
|
|
||||||
return hexToColor(t[0], t[1], t[2])
|
return hexToColor(t[0], t[1], t[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
const generateAllLightColors = (u, e) => {
|
const generateAllLightColors = (u, e) => {
|
||||||
let t = colorToHex(u);
|
let t = colorToHex(u)
|
||||||
const target = [240, 248, 255]; // RGB for blue white color
|
const target = [240, 248, 255] // RGB for blue white color
|
||||||
for (let a = 0; a < 3; a++)
|
for (let a = 0; a < 3; a++) t[a] = Math.floor(t[a] * (1 - e) + target[a] * e)
|
||||||
t[a] = Math.floor(t[a] * (1 - e) + target[a] * e);
|
return hexToColor(t[0], t[1], t[2])
|
||||||
return hexToColor(t[0], t[1], t[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function addOpacityToColor(u, opacity) {
|
function addOpacityToColor(u, opacity) {
|
||||||
let t = colorToHex(u);
|
let t = colorToHex(u)
|
||||||
return `rgba(${t[0]}, ${t[1]}, ${ t[2]}, ${opacity})`;
|
return `rgba(${t[0]}, ${t[1]}, ${t[2]}, ${opacity})`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const setBodyPrimaryColor = (primaryColor, darkMode) => {
|
||||||
export const setBodyPrimaryColor = (primaryColor, darkMode) =>{
|
|
||||||
|
|
||||||
let fmtColorFunc = generateAllColors
|
let fmtColorFunc = generateAllColors
|
||||||
if (darkMode === 'light') {
|
if (darkMode === 'light') {
|
||||||
fmtColorFunc = generateAllLightColors
|
fmtColorFunc = generateAllLightColors
|
||||||
}
|
}
|
||||||
|
|
||||||
document.documentElement.style.setProperty('--el-color-primary', primaryColor)
|
document.documentElement.style.setProperty('--el-color-primary', primaryColor)
|
||||||
document.documentElement.style.setProperty('--el-color-primary-bg', addOpacityToColor(primaryColor, 0.4))
|
document.documentElement.style.setProperty(
|
||||||
|
'--el-color-primary-bg',
|
||||||
|
addOpacityToColor(primaryColor, 0.4)
|
||||||
|
)
|
||||||
for (let times = 1; times <= 2; times++) {
|
for (let times = 1; times <= 2; times++) {
|
||||||
document.documentElement.style.setProperty(`--el-color-primary-dark-${times}`, fmtColorFunc(primaryColor, times / 10))
|
document.documentElement.style.setProperty(
|
||||||
|
`--el-color-primary-dark-${times}`,
|
||||||
|
fmtColorFunc(primaryColor, times / 10)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
for (let times = 1; times <= 10; times++) {
|
for (let times = 1; times <= 10; times++) {
|
||||||
document.documentElement.style.setProperty(`--el-color-primary-light-${times}`, fmtColorFunc(primaryColor, times / 10))
|
document.documentElement.style.setProperty(
|
||||||
|
`--el-color-primary-light-${times}`,
|
||||||
|
fmtColorFunc(primaryColor, times / 10)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
document.documentElement.style.setProperty(`--el-menu-hover-bg-color`, addOpacityToColor(primaryColor, 0.2))
|
document.documentElement.style.setProperty(
|
||||||
|
`--el-menu-hover-bg-color`,
|
||||||
|
addOpacityToColor(primaryColor, 0.2)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const baseUrl = ref(import.meta.env.VITE_BASE_API)
|
const baseUrl = ref(import.meta.env.VITE_BASE_API)
|
||||||
|
|
||||||
export const getBaseUrl = () => {
|
export const getBaseUrl = () => {
|
||||||
return baseUrl.value === "/" ? "" : baseUrl.value
|
return baseUrl.value === '/' ? '' : baseUrl.value
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CreateUUID = () => {
|
export const CreateUUID = () => {
|
||||||
|
|
@ -132,8 +139,8 @@ export const CreateUUID = () => {
|
||||||
d += performance.now()
|
d += performance.now()
|
||||||
}
|
}
|
||||||
return '00000000-0000-0000-0000-000000000000'.replace(/0/g, (c) => {
|
return '00000000-0000-0000-0000-000000000000'.replace(/0/g, (c) => {
|
||||||
const r = (d + Math.random() * 16) % 16 | 0 // d是随机种子
|
const r = (d + Math.random() * 16) % 16 | 0 // d是随机种子
|
||||||
d = Math.floor(d / 16)
|
d = Math.floor(d / 16)
|
||||||
return (c === '0' ? r : (r & 0x3 | 0x8)).toString(16)
|
return (c === '0' ? r : (r & 0x3) | 0x8).toString(16)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export default class ImageCompress {
|
||||||
// 压缩
|
// 压缩
|
||||||
const fileType = this.file.type
|
const fileType = this.file.type
|
||||||
const fileSize = this.file.size / 1024
|
const fileSize = this.file.size / 1024
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.readAsDataURL(this.file)
|
reader.readAsDataURL(this.file)
|
||||||
reader.onload = () => {
|
reader.onload = () => {
|
||||||
|
|
@ -26,7 +26,7 @@ export default class ImageCompress {
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
||||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
|
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
|
||||||
|
|
||||||
const newImgData = canvas.toDataURL(fileType, 0.90)
|
const newImgData = canvas.toDataURL(fileType, 0.9)
|
||||||
|
|
||||||
// 压缩宽高后的图像大小
|
// 压缩宽高后的图像大小
|
||||||
const newImgSize = this.fileSizeKB(newImgData)
|
const newImgSize = this.fileSizeKB(newImgData)
|
||||||
|
|
@ -69,7 +69,7 @@ export default class ImageCompress {
|
||||||
|
|
||||||
fileSizeKB(dataURL) {
|
fileSizeKB(dataURL) {
|
||||||
let sizeKB = 0
|
let sizeKB = 0
|
||||||
sizeKB = Math.round((dataURL.split(',')[1].length * 3 / 4) / 1024)
|
sizeKB = Math.round((dataURL.split(',')[1].length * 3) / 4 / 1024)
|
||||||
return sizeKB
|
return sizeKB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,21 +93,30 @@ export default class ImageCompress {
|
||||||
|
|
||||||
const path = import.meta.env.VITE_FILE_API
|
const path = import.meta.env.VITE_FILE_API
|
||||||
export const getUrl = (url) => {
|
export const getUrl = (url) => {
|
||||||
if (url && url.slice(0, 4) !== 'http'){
|
if (url && url.slice(0, 4) !== 'http') {
|
||||||
if (path === "/"){
|
if (path === '/') {
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
if (url.slice(0, 1) === "/"){
|
if (url.slice(0, 1) === '/') {
|
||||||
return path + url
|
return path + url
|
||||||
}
|
}
|
||||||
return path + "/" + url
|
return path + '/' + url
|
||||||
}else{
|
} else {
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isVideoExt = (url) => url.endsWith('.mp4') || url.endsWith('.mov') || url.endsWith('.webm') || url.endsWith('.ogg');
|
export const isVideoExt = (url) =>
|
||||||
|
url.endsWith('.mp4') ||
|
||||||
|
url.endsWith('.mov') ||
|
||||||
|
url.endsWith('.webm') ||
|
||||||
|
url.endsWith('.ogg')
|
||||||
|
|
||||||
export const isVideoMime = (type) => type == 'video/mp4' || type == 'video/webm' || type == 'video/ogg';
|
export const isVideoMime = (type) =>
|
||||||
|
type == 'video/mp4' || type == 'video/webm' || type == 'video/ogg'
|
||||||
|
|
||||||
export const isImageMime = (type) => type == 'image/jpeg' || type == 'image/png' || type == 'image/webp' || type == 'image/svg+xml';
|
export const isImageMime = (type) =>
|
||||||
|
type == 'image/jpeg' ||
|
||||||
|
type == 'image/png' ||
|
||||||
|
type == 'image/webp' ||
|
||||||
|
type == 'image/svg+xml'
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,11 @@ const service = axios.create({
|
||||||
let activeAxios = 0
|
let activeAxios = 0
|
||||||
let timer
|
let timer
|
||||||
let loadingInstance
|
let loadingInstance
|
||||||
const showLoading = (option = {
|
const showLoading = (
|
||||||
target: null,
|
option = {
|
||||||
}) => {
|
target: null
|
||||||
|
}
|
||||||
|
) => {
|
||||||
const loadDom = document.getElementById('gva-base-load-dom')
|
const loadDom = document.getElementById('gva-base-load-dom')
|
||||||
activeAxios++
|
activeAxios++
|
||||||
if (timer) {
|
if (timer) {
|
||||||
|
|
@ -36,7 +38,7 @@ const closeLoading = () => {
|
||||||
}
|
}
|
||||||
// http request 拦截器
|
// http request 拦截器
|
||||||
service.interceptors.request.use(
|
service.interceptors.request.use(
|
||||||
config => {
|
(config) => {
|
||||||
if (!config.donNotShowLoading) {
|
if (!config.donNotShowLoading) {
|
||||||
showLoading(config.loadingOption)
|
showLoading(config.loadingOption)
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +51,7 @@ service.interceptors.request.use(
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
},
|
},
|
||||||
error => {
|
(error) => {
|
||||||
if (!error.config.donNotShowLoading) {
|
if (!error.config.donNotShowLoading) {
|
||||||
closeLoading()
|
closeLoading()
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +66,7 @@ service.interceptors.request.use(
|
||||||
|
|
||||||
// http response 拦截器
|
// http response 拦截器
|
||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
response => {
|
(response) => {
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
if (!response.config.donNotShowLoading) {
|
if (!response.config.donNotShowLoading) {
|
||||||
closeLoading()
|
closeLoading()
|
||||||
|
|
@ -86,67 +88,81 @@ service.interceptors.response.use(
|
||||||
return response.data.msg ? response.data : response
|
return response.data.msg ? response.data : response
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error => {
|
(error) => {
|
||||||
if (!error.config.donNotShowLoading) {
|
if (!error.config.donNotShowLoading) {
|
||||||
closeLoading()
|
closeLoading()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!error.response) {
|
if (!error.response) {
|
||||||
ElMessageBox.confirm(`
|
ElMessageBox.confirm(
|
||||||
|
`
|
||||||
<p>检测到请求错误</p>
|
<p>检测到请求错误</p>
|
||||||
<p>${error}</p>
|
<p>${error}</p>
|
||||||
`, '请求报错', {
|
`,
|
||||||
dangerouslyUseHTMLString: true,
|
'请求报错',
|
||||||
distinguishCancelAndClose: true,
|
{
|
||||||
confirmButtonText: '稍后重试',
|
dangerouslyUseHTMLString: true,
|
||||||
cancelButtonText: '取消'
|
distinguishCancelAndClose: true,
|
||||||
})
|
confirmButtonText: '稍后重试',
|
||||||
|
cancelButtonText: '取消'
|
||||||
|
}
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (error.response.status) {
|
switch (error.response.status) {
|
||||||
case 500:
|
case 500:
|
||||||
ElMessageBox.confirm(`
|
ElMessageBox.confirm(
|
||||||
|
`
|
||||||
<p>检测到接口错误${error}</p>
|
<p>检测到接口错误${error}</p>
|
||||||
<p>错误码<span style="color:red"> 500 </span>:此类错误内容常见于后台panic,请先查看后台日志,如果影响您正常使用可强制登出清理缓存</p>
|
<p>错误码<span style="color:red"> 500 </span>:此类错误内容常见于后台panic,请先查看后台日志,如果影响您正常使用可强制登出清理缓存</p>
|
||||||
`, '接口报错', {
|
`,
|
||||||
dangerouslyUseHTMLString: true,
|
'接口报错',
|
||||||
distinguishCancelAndClose: true,
|
{
|
||||||
confirmButtonText: '清理缓存',
|
dangerouslyUseHTMLString: true,
|
||||||
cancelButtonText: '取消'
|
distinguishCancelAndClose: true,
|
||||||
|
confirmButtonText: '清理缓存',
|
||||||
|
cancelButtonText: '取消'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
userStore.ClearStorage()
|
||||||
|
router.push({ name: 'Login', replace: true })
|
||||||
})
|
})
|
||||||
.then(() => {
|
|
||||||
const userStore = useUserStore()
|
|
||||||
userStore.ClearStorage()
|
|
||||||
router.push({ name: 'Login', replace: true })
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
case 404:
|
case 404:
|
||||||
ElMessageBox.confirm(`
|
ElMessageBox.confirm(
|
||||||
|
`
|
||||||
<p>检测到接口错误${error}</p>
|
<p>检测到接口错误${error}</p>
|
||||||
<p>错误码<span style="color:red"> 404 </span>:此类错误多为接口未注册(或未重启)或者请求路径(方法)与api路径(方法)不符--如果为自动化代码请检查是否存在空格</p>
|
<p>错误码<span style="color:red"> 404 </span>:此类错误多为接口未注册(或未重启)或者请求路径(方法)与api路径(方法)不符--如果为自动化代码请检查是否存在空格</p>
|
||||||
`, '接口报错', {
|
`,
|
||||||
dangerouslyUseHTMLString: true,
|
'接口报错',
|
||||||
distinguishCancelAndClose: true,
|
{
|
||||||
confirmButtonText: '我知道了',
|
dangerouslyUseHTMLString: true,
|
||||||
cancelButtonText: '取消'
|
distinguishCancelAndClose: true,
|
||||||
})
|
confirmButtonText: '我知道了',
|
||||||
|
cancelButtonText: '取消'
|
||||||
|
}
|
||||||
|
)
|
||||||
break
|
break
|
||||||
case 401:
|
case 401:
|
||||||
ElMessageBox.confirm(`
|
ElMessageBox.confirm(
|
||||||
|
`
|
||||||
<p>无效的令牌</p>
|
<p>无效的令牌</p>
|
||||||
<p>错误码:<span style="color:red"> 401 </span>错误信息:${error}</p>
|
<p>错误码:<span style="color:red"> 401 </span>错误信息:${error}</p>
|
||||||
`, '身份信息', {
|
`,
|
||||||
dangerouslyUseHTMLString: true,
|
'身份信息',
|
||||||
distinguishCancelAndClose: true,
|
{
|
||||||
confirmButtonText: '重新登录',
|
dangerouslyUseHTMLString: true,
|
||||||
cancelButtonText: '取消'
|
distinguishCancelAndClose: true,
|
||||||
|
confirmButtonText: '重新登录',
|
||||||
|
cancelButtonText: '取消'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
userStore.ClearStorage()
|
||||||
|
router.push({ name: 'Login', replace: true })
|
||||||
})
|
})
|
||||||
.then(() => {
|
|
||||||
const userStore = useUserStore()
|
|
||||||
userStore.ClearStorage()
|
|
||||||
router.push({ name: 'Login', replace: true })
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,29 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export const toUpperCase = (str) => {
|
export const toUpperCase = (str) => {
|
||||||
if (str[0]) {
|
if (str[0]) {
|
||||||
return str.replace(str[0], str[0].toUpperCase())
|
return str.replace(str[0], str[0].toUpperCase())
|
||||||
} else {
|
} else {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const toLowerCase = (str) => {
|
export const toLowerCase = (str) => {
|
||||||
if (str[0]) {
|
if (str[0]) {
|
||||||
return str.replace(str[0], str[0].toLowerCase())
|
return str.replace(str[0], str[0].toLowerCase())
|
||||||
} else {
|
} else {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 驼峰转换下划线
|
// 驼峰转换下划线
|
||||||
export const toSQLLine = (str) => {
|
export const toSQLLine = (str) => {
|
||||||
if (str === 'ID') return 'ID'
|
if (str === 'ID') return 'ID'
|
||||||
return str.replace(/([A-Z])/g, "_$1").toLowerCase();
|
return str.replace(/([A-Z])/g, '_$1').toLowerCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下划线转换驼峰
|
// 下划线转换驼峰
|
||||||
export const toHump = (name) => {
|
export const toHump = (name) => {
|
||||||
return name.replace(/\_(\w)/g, function(all, letter) {
|
return name.replace(/\_(\w)/g, function (all, letter) {
|
||||||
return letter.toUpperCase();
|
return letter.toUpperCase()
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,13 @@
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<div>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col
|
<el-col :span="8" :offset="8">
|
||||||
:span="8"
|
|
||||||
:offset="8"
|
|
||||||
>
|
|
||||||
<a href="https://github.com/flipped-aurora/gin-vue-admin">
|
<a href="https://github.com/flipped-aurora/gin-vue-admin">
|
||||||
<img
|
<img
|
||||||
class="org-img dom-center"
|
class="org-img dom-center"
|
||||||
src="@/assets/logo.png"
|
src="@/assets/logo.png"
|
||||||
alt="gin-vue-admin"
|
alt="gin-vue-admin"
|
||||||
>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
@ -28,7 +25,7 @@
|
||||||
class="dom-center"
|
class="dom-center"
|
||||||
src="https://img.shields.io/github/watchers/flipped-aurora/gin-vue-admin.svg?label=Watch"
|
src="https://img.shields.io/github/watchers/flipped-aurora/gin-vue-admin.svg?label=Watch"
|
||||||
alt=""
|
alt=""
|
||||||
>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
|
|
@ -37,7 +34,7 @@
|
||||||
class="dom-center"
|
class="dom-center"
|
||||||
src="https://img.shields.io/github/stars/flipped-aurora/gin-vue-admin.svg?style=social"
|
src="https://img.shields.io/github/stars/flipped-aurora/gin-vue-admin.svg?style=social"
|
||||||
alt=""
|
alt=""
|
||||||
>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
|
|
@ -46,7 +43,7 @@
|
||||||
class="dom-center"
|
class="dom-center"
|
||||||
src="https://img.shields.io/github/forks/flipped-aurora/gin-vue-admin.svg?label=Fork"
|
src="https://img.shields.io/github/forks/flipped-aurora/gin-vue-admin.svg?label=Fork"
|
||||||
alt=""
|
alt=""
|
||||||
>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
@ -58,34 +55,27 @@
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<div>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col
|
<el-col :span="8" :offset="8">
|
||||||
:span="8"
|
|
||||||
:offset="8"
|
|
||||||
>
|
|
||||||
<a href="https://github.com/flipped-aurora">
|
<a href="https://github.com/flipped-aurora">
|
||||||
<img
|
<img
|
||||||
class="org-img dom-center"
|
class="org-img dom-center"
|
||||||
src="@/assets/flipped-aurora.png"
|
src="@/assets/flipped-aurora.png"
|
||||||
alt="flipped-aurora"
|
alt="flipped-aurora"
|
||||||
>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mt-4">
|
<div
|
||||||
<div
|
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mt-4"
|
||||||
v-for="(item, index) in members"
|
>
|
||||||
:key="index"
|
<div v-for="(item, index) in members" :key="index" :span="8">
|
||||||
:span="8"
|
|
||||||
>
|
|
||||||
<a :href="item.html_url" class="flex items-center">
|
<a :href="item.html_url" class="flex items-center">
|
||||||
<img
|
<img class="w-8 h-8 rounded-full" :src="item.avatar_url" />
|
||||||
class="w-8 h-8 rounded-full"
|
|
||||||
:src="item.avatar_url"
|
|
||||||
>
|
|
||||||
<el-link
|
<el-link
|
||||||
class=" text-blue-700 ml-2 text-xl font-bold font-sans "
|
class="text-blue-700 ml-2 text-xl font-bold font-sans"
|
||||||
style=""
|
style=""
|
||||||
>{{ item.login }}</el-link>
|
>{{ item.login }}</el-link
|
||||||
|
>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -100,7 +90,7 @@
|
||||||
<div>
|
<div>
|
||||||
<el-timeline>
|
<el-timeline>
|
||||||
<el-timeline-item
|
<el-timeline-item
|
||||||
v-for="(item,index) in dataTimeline"
|
v-for="(item, index) in dataTimeline"
|
||||||
:key="index"
|
:key="index"
|
||||||
:timestamp="item.from"
|
:timestamp="item.from"
|
||||||
placement="top"
|
placement="top"
|
||||||
|
|
@ -112,12 +102,7 @@
|
||||||
</el-timeline-item>
|
</el-timeline-item>
|
||||||
</el-timeline>
|
</el-timeline>
|
||||||
</div>
|
</div>
|
||||||
<el-button
|
<el-button class="load-more" type="primary" link @click="loadMore">
|
||||||
class="load-more"
|
|
||||||
type="primary"
|
|
||||||
link
|
|
||||||
@click="loadMore"
|
|
||||||
>
|
|
||||||
Load more
|
Load more
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
@ -127,72 +112,70 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { Commits, Members } from '@/api/github'
|
import { Commits, Members } from '@/api/github'
|
||||||
import { formatTimeToStr } from '@/utils/date'
|
import { formatTimeToStr } from '@/utils/date'
|
||||||
const page = ref(0)
|
const page = ref(0)
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'About'
|
name: 'About'
|
||||||
})
|
})
|
||||||
|
|
||||||
const loadMore = () => {
|
const loadMore = () => {
|
||||||
page.value++
|
page.value++
|
||||||
loadCommits()
|
loadCommits()
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataTimeline = ref([])
|
const dataTimeline = ref([])
|
||||||
const loadCommits = () => {
|
const loadCommits = () => {
|
||||||
Commits(page.value).then(({ data }) => {
|
Commits(page.value).then(({ data }) => {
|
||||||
data.forEach((element) => {
|
data.forEach((element) => {
|
||||||
if (element.commit.message) {
|
if (element.commit.message) {
|
||||||
dataTimeline.value.push({
|
dataTimeline.value.push({
|
||||||
from: formatTimeToStr(element.commit.author.date, 'yyyy-MM-dd'),
|
from: formatTimeToStr(element.commit.author.date, 'yyyy-MM-dd'),
|
||||||
title: element.commit.author.name,
|
title: element.commit.author.name,
|
||||||
showDayAndMonth: true,
|
showDayAndMonth: true,
|
||||||
message: element.commit.message,
|
message: element.commit.message
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const members = ref([])
|
const members = ref([])
|
||||||
const loadMembers = () => {
|
const loadMembers = () => {
|
||||||
Members().then(({ data }) => {
|
Members().then(({ data }) => {
|
||||||
members.value = data
|
members.value = data
|
||||||
members.value.sort()
|
members.value.sort()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
loadCommits()
|
|
||||||
loadMembers()
|
|
||||||
|
|
||||||
|
loadCommits()
|
||||||
|
loadMembers()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.load-more {
|
.load-more {
|
||||||
margin-left: 120px;
|
margin-left: 120px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-img {
|
.avatar-img {
|
||||||
float: left;
|
float: left;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
-webkit-border-radius: 50%;
|
-webkit-border-radius: 50%;
|
||||||
-moz-border-radius: 50%;
|
-moz-border-radius: 50%;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.org-img {
|
.org-img {
|
||||||
height: 150px;
|
height: 150px;
|
||||||
width: 150px;
|
width: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dom-center {
|
||||||
.dom-center {
|
margin-left: 50%;
|
||||||
margin-left: 50%;
|
transform: translateX(-50%);
|
||||||
transform: translateX(-50%);
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -5,36 +5,39 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-carousel class="-mt-2">
|
<el-carousel class="-mt-2">
|
||||||
<el-carousel-item class="cursor-pointer lg:h-40" v-for="(item , index) in banners" :key="index" @click="openLink(item.link)">
|
<el-carousel-item
|
||||||
|
class="cursor-pointer lg:h-40"
|
||||||
|
v-for="(item, index) in banners"
|
||||||
|
:key="index"
|
||||||
|
@click="openLink(item.link)"
|
||||||
|
>
|
||||||
<el-image class="h-full w-full" :src="item.img" fit="fill"></el-image>
|
<el-image class="h-full w-full" :src="item.img" fit="fill"></el-image>
|
||||||
</el-carousel-item>
|
</el-carousel-item>
|
||||||
</el-carousel>
|
</el-carousel>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import banner from "@/assets/banner.jpg"
|
import banner from '@/assets/banner.jpg'
|
||||||
import banner2 from "@/assets/banner2.jpg"
|
import banner2 from '@/assets/banner2.jpg'
|
||||||
|
|
||||||
const openLink = (link) => {
|
const openLink = (link) => {
|
||||||
window.open(link, '_blank')
|
window.open(link, '_blank')
|
||||||
}
|
|
||||||
|
|
||||||
const banners = [
|
|
||||||
{
|
|
||||||
img: banner,
|
|
||||||
link: "https://gin-vue-admin.com/empower/index.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
img: banner2,
|
|
||||||
link: "https://plugin.gin-vue-admin.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
img: "https://qmplusimg.henrongyi.top/gvaDemo/k8s.jpg",
|
|
||||||
link: "https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=42"
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
const banners = [
|
||||||
|
{
|
||||||
|
img: banner,
|
||||||
|
link: 'https://gin-vue-admin.com/empower/index.html'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: banner2,
|
||||||
|
link: 'https://plugin.gin-vue-admin.com'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
img: 'https://qmplusimg.henrongyi.top/gvaDemo/k8s.jpg',
|
||||||
|
link: 'https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=42'
|
||||||
|
}
|
||||||
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,8 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="bg-white dark:bg-slate-900 text-gray-800 dark:text-gray-400 rounded shadow" :class="[
|
class="bg-white dark:bg-slate-900 text-gray-800 dark:text-gray-400 rounded shadow"
|
||||||
customClass || '',
|
:class="[customClass || '', withoutPadding ? 'p-0' : 'p-4']"
|
||||||
withoutPadding ? 'p-0' : 'p-4'
|
|
||||||
]"
|
|
||||||
>
|
>
|
||||||
<div v-if="title" class="flex justify-between items-center">
|
<div v-if="title" class="flex justify-between items-center">
|
||||||
<div class="text-base font-bold">
|
<div class="text-base font-bold">
|
||||||
|
|
@ -25,27 +23,24 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
defineProps({
|
defineProps({
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
showAction: {
|
showAction: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
customClass: {
|
customClass: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
withoutPadding: {
|
withoutPadding: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -10,174 +10,181 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import Chart from "@/components/charts/index.vue";
|
import Chart from '@/components/charts/index.vue'
|
||||||
import useChartOption from '@/hooks/charts';
|
import useChartOption from '@/hooks/charts'
|
||||||
import { graphic } from 'echarts'
|
import { graphic } from 'echarts'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useAppStore } from '@/pinia'
|
import { useAppStore } from '@/pinia'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { config } = storeToRefs(appStore)
|
const { config } = storeToRefs(appStore)
|
||||||
defineProps({
|
defineProps({
|
||||||
height: {
|
height: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '128px',
|
default: '128px'
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
const dotColor = computed(() => {
|
const dotColor = computed(() => {
|
||||||
console.log(appStore.theme)
|
console.log(appStore.theme)
|
||||||
return appStore.theme === 'dark' ? '#333' : '#E5E8EF'
|
return appStore.theme === 'dark' ? '#333' : '#E5E8EF'
|
||||||
})
|
})
|
||||||
const graphicFactory = (side) => {
|
const graphicFactory = (side) => {
|
||||||
return {
|
return {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
bottom: '8',
|
bottom: '8',
|
||||||
...side,
|
...side,
|
||||||
style: {
|
style: {
|
||||||
text: '',
|
text: '',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fill: '#4E5969',
|
fill: '#4E5969',
|
||||||
fontSize: 12,
|
fontSize: 12
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
const xAxis = ref(["2024-1", "2024-2", "2024-3", "2024-4", "2024-5", "2024-6", "2024-7", "2024-8"]);
|
const xAxis = ref([
|
||||||
const chartsData = ref([12,22,32,45,32,78,89,92]);
|
'2024-1',
|
||||||
const graphicElements = ref([
|
'2024-2',
|
||||||
graphicFactory({ left: '5%' }),
|
'2024-3',
|
||||||
graphicFactory({ right: 0 }),
|
'2024-4',
|
||||||
]);
|
'2024-5',
|
||||||
const { chartOption } = useChartOption(() => {
|
'2024-6',
|
||||||
return {
|
'2024-7',
|
||||||
grid: {
|
'2024-8'
|
||||||
left: '40',
|
])
|
||||||
right: '0',
|
const chartsData = ref([12, 22, 32, 45, 32, 78, 89, 92])
|
||||||
top: '10',
|
const graphicElements = ref([
|
||||||
bottom: '30',
|
graphicFactory({ left: '5%' }),
|
||||||
},
|
graphicFactory({ right: 0 })
|
||||||
xAxis: {
|
])
|
||||||
type: 'category',
|
const { chartOption } = useChartOption(() => {
|
||||||
offset: 2,
|
return {
|
||||||
data: xAxis.value,
|
grid: {
|
||||||
boundaryGap: false,
|
left: '40',
|
||||||
axisLabel: {
|
right: '0',
|
||||||
color: '#4E5969',
|
top: '10',
|
||||||
formatter(value, idx) {
|
bottom: '30'
|
||||||
if (idx === 0) return '';
|
},
|
||||||
if (idx === xAxis.value.length - 1) return '';
|
xAxis: {
|
||||||
return `${value}`;
|
type: 'category',
|
||||||
|
offset: 2,
|
||||||
|
data: xAxis.value,
|
||||||
|
boundaryGap: false,
|
||||||
|
axisLabel: {
|
||||||
|
color: '#4E5969',
|
||||||
|
formatter(value, idx) {
|
||||||
|
if (idx === 0) return ''
|
||||||
|
if (idx === xAxis.value.length - 1) return ''
|
||||||
|
return `${value}`
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
axisLine: {
|
||||||
axisLine: {
|
show: false
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
axisTick: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
show: true,
|
|
||||||
interval: (idx) => {
|
|
||||||
if (idx === 0) return false;
|
|
||||||
if (idx === xAxis.value.length - 1) return false;
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
lineStyle: {
|
axisTick: {
|
||||||
color: dotColor.value,
|
show: false
|
||||||
},
|
},
|
||||||
},
|
splitLine: {
|
||||||
axisPointer: {
|
show: true,
|
||||||
show: true,
|
interval: (idx) => {
|
||||||
lineStyle: {
|
if (idx === 0) return false
|
||||||
color: `${config.value.primaryColor}FF`,
|
if (idx === xAxis.value.length - 1) return false
|
||||||
width: 2,
|
return true
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
color: dotColor.value
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
axisPointer: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: `${config.value.primaryColor}FF`,
|
||||||
|
width: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
yAxis: {
|
||||||
yAxis: {
|
type: 'value',
|
||||||
type: 'value',
|
axisLine: {
|
||||||
axisLine: {
|
show: false
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
axisLabel: {
|
|
||||||
formatter(value, idx) {
|
|
||||||
if (idx === 0) return value;
|
|
||||||
return `${value}k`;
|
|
||||||
},
|
},
|
||||||
},
|
axisLabel: {
|
||||||
splitLine: {
|
formatter(value, idx) {
|
||||||
show: true,
|
if (idx === 0) return value
|
||||||
lineStyle: {
|
return `${value}k`
|
||||||
type: 'dashed',
|
}
|
||||||
color: dotColor.value,
|
|
||||||
},
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed',
|
||||||
|
color: dotColor.value
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
tooltip: {
|
||||||
tooltip: {
|
trigger: 'axis',
|
||||||
trigger: 'axis',
|
formatter(params) {
|
||||||
formatter(params) {
|
const [firstElement] = params
|
||||||
const [firstElement] = params
|
return `<div>
|
||||||
return `<div>
|
|
||||||
<p class="tooltip-title">${firstElement.axisValueLabel}</p>
|
<p class="tooltip-title">${firstElement.axisValueLabel}</p>
|
||||||
<div class="content-panel"><span>总内容量</span><span class="tooltip-value">${(
|
<div class="content-panel"><span>总内容量</span><span class="tooltip-value">${(
|
||||||
Number(firstElement.value) * 10000
|
Number(firstElement.value) * 10000
|
||||||
).toLocaleString()}</span></div>
|
).toLocaleString()}</span></div>
|
||||||
</div>`;
|
</div>`
|
||||||
|
},
|
||||||
|
className: 'echarts-tooltip-diy'
|
||||||
},
|
},
|
||||||
className: 'echarts-tooltip-diy',
|
graphic: {
|
||||||
},
|
elements: graphicElements.value
|
||||||
graphic: {
|
},
|
||||||
elements: graphicElements.value,
|
series: [
|
||||||
},
|
{
|
||||||
series: [
|
data: chartsData.value,
|
||||||
{
|
type: 'line',
|
||||||
data: chartsData.value,
|
smooth: true,
|
||||||
type: 'line',
|
// symbol: 'circle',
|
||||||
smooth: true,
|
symbolSize: 12,
|
||||||
// symbol: 'circle',
|
emphasis: {
|
||||||
symbolSize: 12,
|
focus: 'series',
|
||||||
emphasis: {
|
itemStyle: {
|
||||||
focus: 'series',
|
borderWidth: 2
|
||||||
itemStyle: {
|
}
|
||||||
borderWidth: 2,
|
|
||||||
},
|
},
|
||||||
},
|
lineStyle: {
|
||||||
lineStyle: {
|
width: 3,
|
||||||
width: 3,
|
color: new graphic.LinearGradient(0, 0, 1, 0, [
|
||||||
color: new graphic.LinearGradient(0, 0, 1, 0, [
|
{
|
||||||
{
|
offset: 0,
|
||||||
offset: 0,
|
color: `${config.value.primaryColor}80`
|
||||||
color: `${config.value.primaryColor}80`,
|
},
|
||||||
},
|
{
|
||||||
{
|
offset: 0.5,
|
||||||
offset: 0.5,
|
color: `${config.value.primaryColor}92`
|
||||||
color: `${config.value.primaryColor}92`,
|
},
|
||||||
},
|
{
|
||||||
{
|
offset: 1,
|
||||||
offset: 1,
|
color: `${config.value.primaryColor}FF`
|
||||||
color: `${config.value.primaryColor}FF`,
|
}
|
||||||
},
|
])
|
||||||
]),
|
},
|
||||||
},
|
showSymbol: false,
|
||||||
showSymbol: false,
|
areaStyle: {
|
||||||
areaStyle: {
|
opacity: 0.8,
|
||||||
opacity: 0.8,
|
color: new graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
color: new graphic.LinearGradient(0, 0, 0, 1, [
|
{
|
||||||
{
|
offset: 0,
|
||||||
offset: 0,
|
color: `${config.value.primaryColor}20`
|
||||||
color: `${config.value.primaryColor}20`,
|
},
|
||||||
},
|
{
|
||||||
{
|
offset: 1,
|
||||||
offset: 1,
|
color: `${config.value.primaryColor}08`
|
||||||
color: `${config.value.primaryColor}08`,
|
}
|
||||||
},
|
])
|
||||||
]),
|
}
|
||||||
},
|
}
|
||||||
},
|
]
|
||||||
],
|
}
|
||||||
};
|
})
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -11,131 +11,128 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import Chart from "@/components/charts/index.vue";
|
import Chart from '@/components/charts/index.vue'
|
||||||
import useChartOption from '@/hooks/charts';
|
import useChartOption from '@/hooks/charts'
|
||||||
import { graphic } from 'echarts'
|
import { graphic } from 'echarts'
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue'
|
||||||
import { storeToRefs } from "pinia"
|
import { storeToRefs } from 'pinia'
|
||||||
import { useAppStore } from '@/pinia'
|
import { useAppStore } from '@/pinia'
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { config } = storeToRefs(appStore)
|
const { config } = storeToRefs(appStore)
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
height: {
|
height: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '128px',
|
default: '128px'
|
||||||
},
|
},
|
||||||
data : {
|
data: {
|
||||||
type : Array,
|
type: Array,
|
||||||
default : () => []
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const graphicFactory = (side) => {
|
||||||
|
return {
|
||||||
|
type: 'text',
|
||||||
|
bottom: '8',
|
||||||
|
...side,
|
||||||
|
style: {
|
||||||
|
text: '',
|
||||||
|
textAlign: 'center',
|
||||||
|
fill: '#4E5969',
|
||||||
|
fontSize: 12
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
const graphicElements = ref([
|
||||||
const graphicFactory = (side) => {
|
graphicFactory({ left: '5%' }),
|
||||||
return {
|
graphicFactory({ right: 0 })
|
||||||
type: 'text',
|
])
|
||||||
bottom: '8',
|
const { chartOption } = useChartOption(() => {
|
||||||
...side,
|
return {
|
||||||
style: {
|
grid: {
|
||||||
text: '',
|
left: '40',
|
||||||
textAlign: 'center',
|
right: '0',
|
||||||
fill: '#4E5969',
|
top: '10',
|
||||||
fontSize: 12,
|
bottom: '30'
|
||||||
},
|
},
|
||||||
};
|
xAxis: {
|
||||||
}
|
type: 'category',
|
||||||
const graphicElements = ref([
|
offset: 2,
|
||||||
graphicFactory({ left: '5%' }),
|
|
||||||
graphicFactory({ right: 0 }),
|
|
||||||
]);
|
|
||||||
const { chartOption } = useChartOption(() => {
|
|
||||||
return {
|
|
||||||
grid: {
|
|
||||||
left: '40',
|
|
||||||
right: '0',
|
|
||||||
top: '10',
|
|
||||||
bottom: '30',
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
offset: 2,
|
|
||||||
show : false,
|
|
||||||
boundaryGap: false,
|
|
||||||
axisLine: {
|
|
||||||
show: false,
|
show: false,
|
||||||
|
boundaryGap: false,
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
axisTick: {
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
show: false,
|
show: false,
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
splitLine: {
|
graphic: {
|
||||||
show: false,
|
elements: graphicElements.value
|
||||||
},
|
},
|
||||||
|
series: [
|
||||||
},
|
{
|
||||||
yAxis: {
|
data: prop.data,
|
||||||
type: 'value',
|
type: 'line',
|
||||||
show: false,
|
smooth: true,
|
||||||
axisLine: {
|
symbolSize: 12,
|
||||||
show: false,
|
emphasis: {
|
||||||
},
|
focus: 'series',
|
||||||
axisLabel: {
|
itemStyle: {
|
||||||
show: false
|
borderWidth: 2
|
||||||
},
|
}
|
||||||
splitLine: {
|
|
||||||
show: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
graphic: {
|
|
||||||
elements: graphicElements.value,
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
data: prop.data,
|
|
||||||
type: 'line',
|
|
||||||
smooth: true,
|
|
||||||
symbolSize: 12,
|
|
||||||
emphasis: {
|
|
||||||
focus: 'series',
|
|
||||||
itemStyle: {
|
|
||||||
borderWidth: 2,
|
|
||||||
},
|
},
|
||||||
},
|
lineStyle: {
|
||||||
lineStyle: {
|
width: 3,
|
||||||
width: 3,
|
color: new graphic.LinearGradient(0, 0, 1, 0, [
|
||||||
color: new graphic.LinearGradient(0, 0, 1, 0, [
|
{
|
||||||
{
|
offset: 0,
|
||||||
offset: 0,
|
color: `${config.value.primaryColor}32`
|
||||||
color: `${config.value.primaryColor}32`,
|
},
|
||||||
},
|
{
|
||||||
{
|
offset: 0.5,
|
||||||
offset: 0.5,
|
color: `${config.value.primaryColor}64`
|
||||||
color: `${config.value.primaryColor}64`,
|
},
|
||||||
},
|
{
|
||||||
{
|
offset: 1,
|
||||||
offset: 1,
|
color: `${config.value.primaryColor}FF`
|
||||||
color: `${config.value.primaryColor}FF`,
|
}
|
||||||
},
|
])
|
||||||
]),
|
},
|
||||||
},
|
showSymbol: false,
|
||||||
showSymbol: false,
|
areaStyle: {
|
||||||
areaStyle: {
|
opacity: 0.8,
|
||||||
opacity: 0.8,
|
color: new graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
color: new graphic.LinearGradient(0, 0, 0, 1, [
|
{
|
||||||
{
|
offset: 0,
|
||||||
offset: 0,
|
color: `${config.value.primaryColor}20`
|
||||||
color: `${config.value.primaryColor}20`,
|
},
|
||||||
},
|
{
|
||||||
{
|
offset: 1,
|
||||||
offset: 1,
|
color: `${config.value.primaryColor}08`
|
||||||
color: `${config.value.primaryColor}08`,
|
}
|
||||||
},
|
])
|
||||||
]),
|
}
|
||||||
},
|
}
|
||||||
},
|
]
|
||||||
],
|
}
|
||||||
};
|
})
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
</div>
|
</div>
|
||||||
<slot v-else name="title" />
|
<slot v-else name="title" />
|
||||||
</div>
|
</div>
|
||||||
<div class=" w-full relative">
|
<div class="w-full relative">
|
||||||
<div v-if="type !== 4">
|
<div v-if="type !== 4">
|
||||||
<div class="mt-4 text-gray-600 text-3xl font-mono">
|
<div class="mt-4 text-gray-600 text-3xl font-mono">
|
||||||
<el-statistic :value="268500" />
|
<el-statistic :value="268500" />
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
+80% <el-icon><TopRight /></el-icon>
|
+80% <el-icon><TopRight /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class=" absolute top-0 right-2 w-[50%] h-20">
|
<div class="absolute top-0 right-2 w-[50%] h-20">
|
||||||
<charts-people-number v-if="type === 1" :data="data[0]" height="100%" />
|
<charts-people-number v-if="type === 1" :data="data[0]" height="100%" />
|
||||||
<charts-people-number v-if="type === 2" :data="data[1]" height="100%" />
|
<charts-people-number v-if="type === 2" :data="data[1]" height="100%" />
|
||||||
<charts-people-number v-if="type === 3" :data="data[2]" height="100%" />
|
<charts-people-number v-if="type === 3" :data="data[2]" height="100%" />
|
||||||
|
|
@ -31,28 +31,24 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import chartsPeopleNumber from './charts-people-numbers.vue'
|
||||||
|
import chartsContentNumber from './charts-content-numbers.vue'
|
||||||
|
defineProps({
|
||||||
|
type: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = [
|
||||||
import chartsPeopleNumber from "./charts-people-numbers.vue"
|
|
||||||
import chartsContentNumber from "./charts-content-numbers.vue"
|
|
||||||
defineProps({
|
|
||||||
type :{
|
|
||||||
type : Number,
|
|
||||||
default : 1
|
|
||||||
},
|
|
||||||
title : {
|
|
||||||
type : String,
|
|
||||||
default : ""
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const data = [
|
|
||||||
[12, 22, 32, 45, 32, 78, 89, 92],
|
[12, 22, 32, 45, 32, 78, 89, 92],
|
||||||
[1, 2, 43, 5, 67, 78, 89, 12],
|
[1, 2, 43, 5, 67, 78, 89, 12],
|
||||||
[12, 22, 32, 45, 32, 78, 89, 92],
|
[12, 22, 32, 45, 32, 78, 89, 92]
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
import GvaBanner from "./banner.vue"
|
import GvaBanner from './banner.vue'
|
||||||
import GvaCard from "./card.vue"
|
import GvaCard from './card.vue'
|
||||||
import GvaChart from "./charts.vue"
|
import GvaChart from './charts.vue'
|
||||||
import GvaTable from "./table.vue"
|
import GvaTable from './table.vue'
|
||||||
import GvaNotice from "./notice.vue"
|
import GvaNotice from './notice.vue'
|
||||||
import GvaQuickLink from "./quickLinks.vue"
|
import GvaQuickLink from './quickLinks.vue'
|
||||||
import GvaWiki from "./wiki.vue"
|
import GvaWiki from './wiki.vue'
|
||||||
import GvaPluginTable from "./pluginTable.vue"
|
import GvaPluginTable from './pluginTable.vue'
|
||||||
|
|
||||||
export {
|
export {
|
||||||
GvaBanner,
|
GvaBanner,
|
||||||
GvaCard,
|
GvaCard,
|
||||||
GvaChart,
|
GvaChart,
|
||||||
GvaTable,
|
GvaTable,
|
||||||
GvaNotice,
|
GvaNotice,
|
||||||
GvaQuickLink,
|
GvaQuickLink,
|
||||||
GvaWiki,
|
GvaWiki,
|
||||||
GvaPluginTable
|
GvaPluginTable
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,11 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<div v-for="(item , index) in notices" :key="index" class="flex items-center mb-1.5 gap-3">
|
<div
|
||||||
|
v-for="(item, index) in notices"
|
||||||
|
:key="index"
|
||||||
|
class="flex items-center mb-1.5 gap-3"
|
||||||
|
>
|
||||||
<el-tag :type="item.type" size="small">
|
<el-tag :type="item.type" size="small">
|
||||||
{{ item.typeTitle }}
|
{{ item.typeTitle }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
|
|
@ -21,58 +25,56 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
const notices = [
|
const notices = [
|
||||||
{
|
{
|
||||||
type : 'primary',
|
type: 'primary',
|
||||||
typeTitle : "公告",
|
typeTitle: '公告',
|
||||||
title : "授权费将在从六月一日起结束第一价格梯度,进入第二价格梯度。",
|
title: '授权费将在从六月一日起结束第一价格梯度,进入第二价格梯度。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : 'success',
|
type: 'success',
|
||||||
typeTitle : "通知",
|
typeTitle: '通知',
|
||||||
title : "授权后将进入专属飞书群,获取官方辅助。",
|
title: '授权后将进入专属飞书群,获取官方辅助。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : 'warning',
|
type: 'warning',
|
||||||
typeTitle : "警告",
|
typeTitle: '警告',
|
||||||
title : "授权可获得插件市场极大优惠价格。",
|
title: '授权可获得插件市场极大优惠价格。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : 'danger',
|
type: 'danger',
|
||||||
typeTitle : "违规",
|
typeTitle: '违规',
|
||||||
title : "未授权商用将有可能被资源采集工具爬取并追责。",
|
title: '未授权商用将有可能被资源采集工具爬取并追责。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : 'info',
|
type: 'info',
|
||||||
typeTitle : "信息",
|
typeTitle: '信息',
|
||||||
title : "再次感谢您对开源事业的支持",
|
title: '再次感谢您对开源事业的支持'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : 'primary',
|
type: 'primary',
|
||||||
typeTitle : "公告",
|
typeTitle: '公告',
|
||||||
title : "让创意更有价值。",
|
title: '让创意更有价值。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : 'success',
|
type: 'success',
|
||||||
typeTitle : "通知",
|
typeTitle: '通知',
|
||||||
title : "让劳动更有意义。",
|
title: '让劳动更有意义。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : 'warning',
|
type: 'warning',
|
||||||
typeTitle : "警告",
|
typeTitle: '警告',
|
||||||
title : "让思维更有深度。",
|
title: '让思维更有深度。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : 'danger',
|
type: 'danger',
|
||||||
typeTitle : "错误",
|
typeTitle: '错误',
|
||||||
title : "让生活更有趣味。",
|
title: '让生活更有趣味。'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type : 'info',
|
type: 'info',
|
||||||
typeTitle : "信息",
|
typeTitle: '信息',
|
||||||
title : "让公司更有活力。",
|
title: '让公司更有活力。'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,9 @@
|
||||||
<el-table-column prop="ranking" label="排名" width="80" align="center" />
|
<el-table-column prop="ranking" label="排名" width="80" align="center" />
|
||||||
<el-table-column prop="title" label="插件标题" show-overflow-tooltip>
|
<el-table-column prop="title" label="插件标题" show-overflow-tooltip>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<a class="text-active" :href="row.link" target="_blank">{{ row.title }}</a>
|
<a class="text-active" :href="row.link" target="_blank">{{
|
||||||
|
row.title
|
||||||
|
}}</a>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="click_num" label="关注度" width="100" />
|
<el-table-column prop="click_num" label="关注度" width="100" />
|
||||||
|
|
@ -19,45 +21,46 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const tableData = [
|
const tableData = [
|
||||||
{
|
{
|
||||||
ranking: 1,
|
ranking: 1,
|
||||||
title : "组织管理插件:更方便管理组织,分配资源权限。",
|
title: '组织管理插件:更方便管理组织,分配资源权限。',
|
||||||
click_num : 523,
|
click_num: 523,
|
||||||
hot : 263,
|
hot: 263,
|
||||||
link : "https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=36"
|
link: 'https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=36'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ranking: 2,
|
ranking: 2,
|
||||||
title : "Kubernetes容器管理:,Kubernetes 原生资源管理,提供炫酷的YAML 编辑,Pod 终端,方便运维兄弟管理k8s资源",
|
title:
|
||||||
click_num : 416,
|
'Kubernetes容器管理:,Kubernetes 原生资源管理,提供炫酷的YAML 编辑,Pod 终端,方便运维兄弟管理k8s资源',
|
||||||
hot : 223,
|
click_num: 416,
|
||||||
link : "https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=42"
|
hot: 223,
|
||||||
},
|
link: 'https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=42'
|
||||||
{
|
},
|
||||||
ranking: 3,
|
{
|
||||||
title : "定时任务配置化管理:本插件用于对系统内部的定时任务进行配置化管理,可以配置自定义的函数和HTTP,可以配置cron和remark等等",
|
ranking: 3,
|
||||||
click_num : 337,
|
title:
|
||||||
hot : 176,
|
'定时任务配置化管理:本插件用于对系统内部的定时任务进行配置化管理,可以配置自定义的函数和HTTP,可以配置cron和remark等等',
|
||||||
link : "https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=67"
|
click_num: 337,
|
||||||
},
|
hot: 176,
|
||||||
{
|
link: 'https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=67'
|
||||||
ranking: 4,
|
},
|
||||||
title : "官网CMS系统:基于Gin-Vue-Admin 和 插件市场客户端开发基座开发的企业官网类(cms)系统",
|
{
|
||||||
click_num : 292,
|
ranking: 4,
|
||||||
hot : 145,
|
title:
|
||||||
link : "https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=69"
|
'官网CMS系统:基于Gin-Vue-Admin 和 插件市场客户端开发基座开发的企业官网类(cms)系统',
|
||||||
},
|
click_num: 292,
|
||||||
{
|
hot: 145,
|
||||||
ranking: 5,
|
link: 'https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=69'
|
||||||
title : "微信支付插件:提供扫码支付功能(需自行对接业务)",
|
},
|
||||||
click_num : 173,
|
{
|
||||||
hot : 110,
|
ranking: 5,
|
||||||
link : "https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=28"
|
title: '微信支付插件:提供扫码支付功能(需自行对接业务)',
|
||||||
},
|
click_num: 173,
|
||||||
]
|
hot: 110,
|
||||||
|
link: 'https://plugin.gin-vue-admin.com/#/layout/newPluginInfo?id=28'
|
||||||
|
}
|
||||||
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -5,21 +5,35 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mt-8 w-full">
|
<div class="mt-8 w-full">
|
||||||
<div class="grid grid-cols-2 md:grid-cols-3 3xl:grid-cols-4">
|
<div class="grid grid-cols-2 md:grid-cols-3 3xl:grid-cols-4">
|
||||||
<div v-for="(item, index ) in shortcuts" :key="index" class="flex flex-col items-center mb-3 group cursor-pointer" @click="toPath(item)">
|
<div
|
||||||
<div class="w-8 h-8 rounded bg-gray-200 dark:bg-slate-500 flex items-center justify-center group-hover:bg-blue-400 group-hover:text-white">
|
v-for="(item, index) in shortcuts"
|
||||||
|
:key="index"
|
||||||
|
class="flex flex-col items-center mb-3 group cursor-pointer"
|
||||||
|
@click="toPath(item)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-8 h-8 rounded bg-gray-200 dark:bg-slate-500 flex items-center justify-center group-hover:bg-blue-400 group-hover:text-white"
|
||||||
|
>
|
||||||
<el-icon><component :is="item.icon" /></el-icon>
|
<el-icon><component :is="item.icon" /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs mt-2 text-gray-700 dark:text-gray-300">
|
<div class="text-xs mt-2 text-gray-700 dark:text-gray-300">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 md:grid-cols-3 3xl:grid-cols-4 mt-8">
|
<div class="grid grid-cols-2 md:grid-cols-3 3xl:grid-cols-4 mt-8">
|
||||||
<div v-for="(item, index ) in recentVisits" :key="index" class="flex flex-col items-center mb-3 group cursor-pointer" @click="openLink(item)">
|
<div
|
||||||
<div class="w-8 h-8 rounded bg-gray-200 dark:bg-slate-500 flex items-center justify-center group-hover:bg-blue-400 group-hover:text-white">
|
v-for="(item, index) in recentVisits"
|
||||||
|
:key="index"
|
||||||
|
class="flex flex-col items-center mb-3 group cursor-pointer"
|
||||||
|
@click="openLink(item)"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="w-8 h-8 rounded bg-gray-200 dark:bg-slate-500 flex items-center justify-center group-hover:bg-blue-400 group-hover:text-white"
|
||||||
|
>
|
||||||
<el-icon><component :is="item.icon" /></el-icon>
|
<el-icon><component :is="item.icon" /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs mt-2 text-gray-700 dark:text-gray-300">
|
<div class="text-xs mt-2 text-gray-700 dark:text-gray-300">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -27,65 +41,71 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { Menu,Link,User,Service,Document,Reading,Files,Memo } from '@element-plus/icons-vue'
|
import {
|
||||||
import {useRouter} from "vue-router";
|
Menu,
|
||||||
const router = useRouter()
|
Link,
|
||||||
|
User,
|
||||||
|
Service,
|
||||||
|
Document,
|
||||||
|
Reading,
|
||||||
|
Files,
|
||||||
|
Memo
|
||||||
|
} from '@element-plus/icons-vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
const toPath = (item) => {
|
const toPath = (item) => {
|
||||||
router.push({name: item.path})
|
router.push({ name: item.path })
|
||||||
}
|
}
|
||||||
|
|
||||||
const openLink = (item) => {
|
const openLink = (item) => {
|
||||||
window.open(item.path, '_blank')
|
window.open(item.path, '_blank')
|
||||||
}
|
}
|
||||||
const shortcuts = [
|
const shortcuts = [
|
||||||
{
|
{
|
||||||
icon : Menu,
|
icon: Menu,
|
||||||
title : "菜单管理",
|
title: '菜单管理',
|
||||||
path : "menu",
|
path: 'menu'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon : Link,
|
icon: Link,
|
||||||
title : "API管理",
|
title: 'API管理',
|
||||||
path : "api",
|
path: 'api'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon : Service,
|
icon: Service,
|
||||||
title : "角色管理",
|
title: '角色管理',
|
||||||
path : "authority",
|
path: 'authority'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon : User,
|
icon: User,
|
||||||
title : "用户管理",
|
title: '用户管理',
|
||||||
path : "user",
|
path: 'user'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon : Files,
|
icon: Files,
|
||||||
title : "自动化包",
|
title: '自动化包',
|
||||||
path: "autoPkg",
|
path: 'autoPkg'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon : Memo,
|
icon: Memo,
|
||||||
title : "自动代码",
|
title: '自动代码',
|
||||||
path: "autoCode",
|
path: 'autoCode'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const recentVisits = [
|
const recentVisits = [
|
||||||
{
|
{
|
||||||
icon : Reading,
|
icon: Reading,
|
||||||
title : "授权购买",
|
title: '授权购买',
|
||||||
path: "https://gin-vue-admin.com/empower/index.html",
|
path: 'https://gin-vue-admin.com/empower/index.html'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon : Document,
|
icon: Document,
|
||||||
title : "插件市场",
|
title: '插件市场',
|
||||||
path: "https://plugin.gin-vue-admin.com/#/layout/home",
|
path: 'https://plugin.gin-vue-admin.com/#/layout/home'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -9,46 +9,44 @@
|
||||||
<el-table-column prop="ranking" label="排名" width="80" align="center" />
|
<el-table-column prop="ranking" label="排名" width="80" align="center" />
|
||||||
<el-table-column prop="title" label="内容标题" show-overflow-tooltip />
|
<el-table-column prop="title" label="内容标题" show-overflow-tooltip />
|
||||||
<el-table-column prop="click_num" label="关注度" width="100" />
|
<el-table-column prop="click_num" label="关注度" width="100" />
|
||||||
<el-table-column prop="hot" label="热度值" width="100" />
|
<el-table-column prop="hot" label="热度值" width="100" />
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const tableData = [
|
const tableData = [
|
||||||
{
|
{
|
||||||
ranking: 1,
|
ranking: 1,
|
||||||
title : "更简洁的使用界面,更快速的操作体验",
|
title: '更简洁的使用界面,更快速的操作体验',
|
||||||
click_num : 523,
|
click_num: 523,
|
||||||
hot : 263
|
hot: 263
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ranking: 2,
|
ranking: 2,
|
||||||
title : "更优质的服务,更便捷的使用体验",
|
title: '更优质的服务,更便捷的使用体验',
|
||||||
click_num : 416,
|
click_num: 416,
|
||||||
hot : 223
|
hot: 223
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ranking: 3,
|
ranking: 3,
|
||||||
title : "更快速的创意实现,更高效的工作效率",
|
title: '更快速的创意实现,更高效的工作效率',
|
||||||
click_num : 337,
|
click_num: 337,
|
||||||
hot : 176
|
hot: 176
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ranking: 4,
|
ranking: 4,
|
||||||
title : "更多的创意资源,更多的创意灵感",
|
title: '更多的创意资源,更多的创意灵感',
|
||||||
click_num : 292,
|
click_num: 292,
|
||||||
hot : 145
|
hot: 145
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ranking: 5,
|
ranking: 5,
|
||||||
title : "更合理的代码结构,更清晰的代码逻辑",
|
title: '更合理的代码结构,更清晰的代码逻辑',
|
||||||
click_num : 173,
|
click_num: 173,
|
||||||
hot : 110
|
hot: 110
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -5,38 +5,41 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="grid grid-cols-2 gap-2">
|
<div class="grid grid-cols-2 gap-2">
|
||||||
<a v-for="item in wikis" :key="item.url" :href="item.url" class="text-sm text-gray-700 dark:text-gray-300 no-underline hover:text-active " target="_blank">
|
<a
|
||||||
|
v-for="item in wikis"
|
||||||
|
:key="item.url"
|
||||||
|
:href="item.url"
|
||||||
|
class="text-sm text-gray-700 dark:text-gray-300 no-underline hover:text-active"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const wikis = [
|
const wikis = [
|
||||||
{
|
{
|
||||||
title: 'Vue3',
|
title: 'Vue3',
|
||||||
url : 'https://v3.cn.vuejs.org/guide/introduction.html'
|
url: 'https://v3.cn.vuejs.org/guide/introduction.html'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'GIN 文档',
|
title: 'GIN 文档',
|
||||||
url : 'https://gin-gonic.com/'
|
url: 'https://gin-gonic.com/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title : "GVA 文档",
|
title: 'GVA 文档',
|
||||||
url : 'https://www.gin-vue-admin.com/'
|
url: 'https://www.gin-vue-admin.com/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title : "插件市场",
|
title: '插件市场',
|
||||||
url : 'https://plugin.gin-vue-admin.com/'
|
url: 'https://plugin.gin-vue-admin.com/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title : "github 仓库",
|
title: 'github 仓库',
|
||||||
url : 'https://github.com/flipped-aurora/gin-vue-admin'
|
url: 'https://github.com/flipped-aurora/gin-vue-admin'
|
||||||
}
|
}
|
||||||
|
]
|
||||||
]
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-7 py-2 gap-4 md:gap-2 gva-container2">
|
<div
|
||||||
|
class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-7 py-2 gap-4 md:gap-2 gva-container2"
|
||||||
|
>
|
||||||
<gva-card custom-class="col-span-1 lg:col-span-2 h-32">
|
<gva-card custom-class="col-span-1 lg:col-span-2 h-32">
|
||||||
<gva-chart :type="1" title="访问人数" />
|
<gva-chart :type="1" title="访问人数" />
|
||||||
</gva-card>
|
</gva-card>
|
||||||
|
|
@ -9,20 +11,37 @@
|
||||||
<gva-card custom-class="col-span-1 lg:col-span-2 h-32">
|
<gva-card custom-class="col-span-1 lg:col-span-2 h-32">
|
||||||
<gva-chart :type="3" title="解决数量" />
|
<gva-chart :type="3" title="解决数量" />
|
||||||
</gva-card>
|
</gva-card>
|
||||||
<gva-card title="快捷功能" show-action custom-class="col-start-1 md:col-start-3 lg:col-start-7 row-span-2 h-38">
|
<gva-card
|
||||||
|
title="快捷功能"
|
||||||
|
show-action
|
||||||
|
custom-class="col-start-1 md:col-start-3 lg:col-start-7 row-span-2 h-38"
|
||||||
|
>
|
||||||
<gva-quick-link />
|
<gva-quick-link />
|
||||||
</gva-card>
|
</gva-card>
|
||||||
<gva-card title="内容数据" custom-class="col-span-1 md:col-span-2 md:row-start-2 lg:col-span-6 col-start-1 row-span-2">
|
<gva-card
|
||||||
|
title="内容数据"
|
||||||
|
custom-class="col-span-1 md:col-span-2 md:row-start-2 lg:col-span-6 col-start-1 row-span-2"
|
||||||
|
>
|
||||||
<gva-chart :type="4" />
|
<gva-chart :type="4" />
|
||||||
</gva-card>
|
</gva-card>
|
||||||
<gva-card title="文档" show-action custom-class="md:row-start-8 md:col-start-3 lg:row-start-3 lg:col-start-7">
|
<gva-card
|
||||||
|
title="文档"
|
||||||
|
show-action
|
||||||
|
custom-class="md:row-start-8 md:col-start-3 lg:row-start-3 lg:col-start-7"
|
||||||
|
>
|
||||||
<gva-wiki />
|
<gva-wiki />
|
||||||
</gva-card>
|
</gva-card>
|
||||||
|
|
||||||
<gva-card title="最新更新" custom-class="col-span-1 md:col-span-3 row-span-2">
|
<gva-card
|
||||||
|
title="最新更新"
|
||||||
|
custom-class="col-span-1 md:col-span-3 row-span-2"
|
||||||
|
>
|
||||||
<gva-table />
|
<gva-table />
|
||||||
</gva-card>
|
</gva-card>
|
||||||
<gva-card title="最新插件" custom-class="col-span-1 md:col-span-3 row-span-2">
|
<gva-card
|
||||||
|
title="最新插件"
|
||||||
|
custom-class="col-span-1 md:col-span-3 row-span-2"
|
||||||
|
>
|
||||||
<gva-plugin-table />
|
<gva-plugin-table />
|
||||||
</gva-card>
|
</gva-card>
|
||||||
|
|
||||||
|
|
@ -30,18 +49,29 @@
|
||||||
<gva-notice />
|
<gva-notice />
|
||||||
</gva-card>
|
</gva-card>
|
||||||
|
|
||||||
<gva-card without-padding custom-class="overflow-hidden lg:h-40 col-span-1 md:col-start-2 md:col-span-1 lg:col-start-7">
|
<gva-card
|
||||||
|
without-padding
|
||||||
|
custom-class="overflow-hidden lg:h-40 col-span-1 md:col-start-2 md:col-span-1 lg:col-start-7"
|
||||||
|
>
|
||||||
<gva-banner />
|
<gva-banner />
|
||||||
</gva-card>
|
</gva-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { GvaPluginTable,GvaTable, GvaChart, GvaWiki , GvaNotice , GvaQuickLink , GvaCard , GvaBanner } from "./components"
|
import {
|
||||||
defineOptions({
|
GvaPluginTable,
|
||||||
name: 'Dashboard'
|
GvaTable,
|
||||||
})
|
GvaChart,
|
||||||
|
GvaWiki,
|
||||||
|
GvaNotice,
|
||||||
|
GvaQuickLink,
|
||||||
|
GvaCard,
|
||||||
|
GvaBanner
|
||||||
|
} from './components'
|
||||||
|
defineOptions({
|
||||||
|
name: 'Dashboard'
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped></style>
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,19 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="w-full h-screen bg-gray-50 flex items-center justify-center">
|
<div class="w-full h-screen bg-gray-50 flex items-center justify-center">
|
||||||
<div class="flex flex-col items-center text-2xl gap-4">
|
<div class="flex flex-col items-center text-2xl gap-4">
|
||||||
<img class="w-1/3" src="../../assets/404.png">
|
<img class="w-1/3" src="../../assets/404.png" />
|
||||||
<p class="text-lg">页面被神秘力量吸走了</p>
|
<p class="text-lg">页面被神秘力量吸走了</p>
|
||||||
<p class="text-lg">常见问题为当前此角色无当前路由,如果确定要使用本路由,请到角色管理进行分配</p>
|
<p class="text-lg">
|
||||||
<p>项目地址:<a href="https://github.com/flipped-aurora/gin-vue-admin" target="_blank" class="text-blue-600 ">https://github.com/flipped-aurora/gin-vue-admin</a></p>
|
常见问题为当前此角色无当前路由,如果确定要使用本路由,请到角色管理进行分配
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
项目地址:<a
|
||||||
|
href="https://github.com/flipped-aurora/gin-vue-admin"
|
||||||
|
target="_blank"
|
||||||
|
class="text-blue-600"
|
||||||
|
>https://github.com/flipped-aurora/gin-vue-admin</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
<el-button @click="toDashboard">返回首页</el-button>
|
<el-button @click="toDashboard">返回首页</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -13,16 +22,16 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useUserStore } from '@/pinia/modules/user'
|
import { useUserStore } from '@/pinia/modules/user'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Error'
|
name: 'Error'
|
||||||
})
|
})
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const toDashboard = () => {
|
const toDashboard = () => {
|
||||||
router.push({ name: userStore.userInfo.authority.defaultRouter })
|
router.push({ name: userStore.userInfo.authority.defaultRouter })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Reload'
|
name: 'Reload'
|
||||||
})
|
})
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
router.go(-1)
|
router.go(-1)
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,8 @@
|
||||||
<div class="break-point">
|
<div class="break-point">
|
||||||
<div class="gva-table-box">
|
<div class="gva-table-box">
|
||||||
<el-divider content-position="left">大文件上传</el-divider>
|
<el-divider content-position="left">大文件上传</el-divider>
|
||||||
<form
|
<form id="fromCont" method="post">
|
||||||
id="fromCont"
|
<div class="fileUpload" @click="inputChange">
|
||||||
method="post"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="fileUpload"
|
|
||||||
@click="inputChange"
|
|
||||||
>
|
|
||||||
选择文件
|
选择文件
|
||||||
<input
|
<input
|
||||||
v-show="false"
|
v-show="false"
|
||||||
|
|
@ -18,7 +12,7 @@
|
||||||
multiple="multiple"
|
multiple="multiple"
|
||||||
type="file"
|
type="file"
|
||||||
@change="choseFile"
|
@change="choseFile"
|
||||||
>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<el-button
|
<el-button
|
||||||
|
|
@ -26,17 +20,12 @@
|
||||||
type="primary"
|
type="primary"
|
||||||
class="uploadBtn"
|
class="uploadBtn"
|
||||||
@click="getFile"
|
@click="getFile"
|
||||||
>上传文件</el-button>
|
>上传文件</el-button
|
||||||
|
>
|
||||||
<div class="el-upload__tip">请上传不超过5MB的文件</div>
|
<div class="el-upload__tip">请上传不超过5MB的文件</div>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<transition
|
<transition name="list" tag="p">
|
||||||
name="list"
|
<div v-if="file" class="list-item">
|
||||||
tag="p"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="file"
|
|
||||||
class="list-item"
|
|
||||||
>
|
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<document />
|
<document />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
|
|
@ -51,186 +40,195 @@
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
<div class="tips">此版本为先行体验功能测试版,样式美化和性能优化正在进行中,上传切片文件和合成的完整文件分别再QMPlusserver目录的breakpointDir文件夹和fileDir文件夹</div>
|
<div class="tips">
|
||||||
|
此版本为先行体验功能测试版,样式美化和性能优化正在进行中,上传切片文件和合成的完整文件分别再QMPlusserver目录的breakpointDir文件夹和fileDir文件夹
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import SparkMD5 from 'spark-md5'
|
import SparkMD5 from 'spark-md5'
|
||||||
import {
|
import {
|
||||||
findFile,
|
findFile,
|
||||||
breakpointContinueFinish,
|
breakpointContinueFinish,
|
||||||
removeChunk,
|
removeChunk,
|
||||||
breakpointContinue
|
breakpointContinue
|
||||||
} from '@/api/breakpoint'
|
} from '@/api/breakpoint'
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'BreakPoint'
|
name: 'BreakPoint'
|
||||||
})
|
})
|
||||||
|
|
||||||
const file = ref(null)
|
const file = ref(null)
|
||||||
const fileMd5 = ref('')
|
const fileMd5 = ref('')
|
||||||
const formDataList = ref([])
|
const formDataList = ref([])
|
||||||
const waitUpLoad = ref([])
|
const waitUpLoad = ref([])
|
||||||
const waitNum = ref(NaN)
|
const waitNum = ref(NaN)
|
||||||
const limitFileSize = ref(false)
|
const limitFileSize = ref(false)
|
||||||
const percentage = ref(0)
|
const percentage = ref(0)
|
||||||
const percentageFlage = ref(true)
|
const percentageFlage = ref(true)
|
||||||
|
|
||||||
// 选中文件的函数
|
// 选中文件的函数
|
||||||
const choseFile = async(e) => {
|
const choseFile = async (e) => {
|
||||||
|
// 点击选择文件后取消 直接return
|
||||||
// 点击选择文件后取消 直接return
|
if (!e.target.files.length) {
|
||||||
if (!e.target.files.length) {
|
return
|
||||||
return
|
}
|
||||||
}
|
const fileR = new FileReader() // 创建一个reader用来读取文件流
|
||||||
const fileR = new FileReader() // 创建一个reader用来读取文件流
|
const fileInput = e.target.files[0] // 获取当前文件
|
||||||
const fileInput = e.target.files[0] // 获取当前文件
|
const maxSize = 5 * 1024 * 1024
|
||||||
const maxSize = 5 * 1024 * 1024
|
file.value = fileInput // file 丢全局方便后面用 可以改进为func传参形式
|
||||||
file.value = fileInput // file 丢全局方便后面用 可以改进为func传参形式
|
percentage.value = 0
|
||||||
percentage.value = 0
|
if (file.value.size < maxSize) {
|
||||||
if (file.value.size < maxSize) {
|
fileR.readAsArrayBuffer(file.value) // 把文件读成ArrayBuffer 主要为了保持跟后端的流一致
|
||||||
fileR.readAsArrayBuffer(file.value) // 把文件读成ArrayBuffer 主要为了保持跟后端的流一致
|
fileR.onload = async (e) => {
|
||||||
fileR.onload = async e => {
|
// 读成arrayBuffer的回调 e 为方法自带参数 相当于 dom的e 流存在e.target.result 中
|
||||||
// 读成arrayBuffer的回调 e 为方法自带参数 相当于 dom的e 流存在e.target.result 中
|
const blob = e.target.result
|
||||||
const blob = e.target.result
|
const spark = new SparkMD5.ArrayBuffer() // 创建md5制造工具 (md5用于检测文件一致性 这里不懂就打电话问我)
|
||||||
const spark = new SparkMD5.ArrayBuffer() // 创建md5制造工具 (md5用于检测文件一致性 这里不懂就打电话问我)
|
spark.append(blob) // 文件流丢进工具
|
||||||
spark.append(blob) // 文件流丢进工具
|
fileMd5.value = spark.end() // 工具结束 产生一个a 总文件的md5
|
||||||
fileMd5.value = spark.end() // 工具结束 产生一个a 总文件的md5
|
const FileSliceCap = 1 * 1024 * 1024 // 分片字节数
|
||||||
const FileSliceCap = 1 * 1024 * 1024 // 分片字节数
|
let start = 0 // 定义分片开始切的地方
|
||||||
let start = 0 // 定义分片开始切的地方
|
let end = 0 // 每片结束切的地方a
|
||||||
let end = 0 // 每片结束切的地方a
|
let i = 0 // 第几片
|
||||||
let i = 0 // 第几片
|
formDataList.value = [] // 分片存储的一个池子 丢全局
|
||||||
formDataList.value = [] // 分片存储的一个池子 丢全局
|
while (end < file.value.size) {
|
||||||
while (end < file.value.size) {
|
// 当结尾数字大于文件总size的时候 结束切片
|
||||||
// 当结尾数字大于文件总size的时候 结束切片
|
start = i * FileSliceCap // 计算每片开始位置
|
||||||
start = i * FileSliceCap // 计算每片开始位置
|
end = (i + 1) * FileSliceCap // 计算每片结束位置
|
||||||
end = (i + 1) * FileSliceCap // 计算每片结束位置
|
var fileSlice = file.value.slice(start, end) // 开始切 file.slice 为 h5方法 对文件切片 参数为 起止字节数
|
||||||
var fileSlice = file.value.slice(start, end) // 开始切 file.slice 为 h5方法 对文件切片 参数为 起止字节数
|
const formData = new window.FormData() // 创建FormData用于存储传给后端的信息
|
||||||
const formData = new window.FormData() // 创建FormData用于存储传给后端的信息
|
formData.append('fileMd5', fileMd5.value) // 存储总文件的Md5 让后端知道自己是谁的切片
|
||||||
formData.append('fileMd5', fileMd5.value) // 存储总文件的Md5 让后端知道自己是谁的切片
|
formData.append('file', fileSlice) // 当前的切片
|
||||||
formData.append('file', fileSlice) // 当前的切片
|
formData.append('chunkNumber', i) // 当前是第几片
|
||||||
formData.append('chunkNumber', i) // 当前是第几片
|
formData.append('fileName', file.value.name) // 当前文件的文件名 用于后端文件切片的命名 formData.appen 为 formData对象添加参数的方法
|
||||||
formData.append('fileName', file.value.name) // 当前文件的文件名 用于后端文件切片的命名 formData.appen 为 formData对象添加参数的方法
|
formDataList.value.push({ key: i, formData }) // 把当前切片信息 自己是第几片 存入我们方才准备好的池子
|
||||||
formDataList.value.push({ key: i, formData }) // 把当前切片信息 自己是第几片 存入我们方才准备好的池子
|
i++
|
||||||
i++
|
}
|
||||||
|
const params = {
|
||||||
|
fileName: file.value.name,
|
||||||
|
fileMd5: fileMd5.value,
|
||||||
|
chunkTotal: formDataList.value.length
|
||||||
|
}
|
||||||
|
const res = await findFile(params)
|
||||||
|
// 全部切完以后 发一个请求给后端 拉当前文件后台存储的切片信息 用于检测有多少上传成功的切片
|
||||||
|
const finishList = res.data.file.ExaFileChunk // 上传成功的切片
|
||||||
|
const IsFinish = res.data.file.IsFinish // 是否是同文件不同命 (文件md5相同 文件名不同 则默认是同一个文件但是不同文件名 此时后台数据库只需要拷贝一下数据库文件即可 不需要上传文件 即秒传功能)
|
||||||
|
if (!IsFinish) {
|
||||||
|
// 当是断点续传时候
|
||||||
|
waitUpLoad.value = formDataList.value.filter((all) => {
|
||||||
|
return !(
|
||||||
|
finishList &&
|
||||||
|
finishList.some((fi) => fi.FileChunkNumber === all.key)
|
||||||
|
) // 找出需要上传的切片
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
waitUpLoad.value = [] // 秒传则没有需要上传的切片
|
||||||
|
ElMessage.success('文件已秒传')
|
||||||
|
}
|
||||||
|
waitNum.value = waitUpLoad.value.length // 记录长度用于百分比展示
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
limitFileSize.value = true
|
||||||
|
ElMessage('请上传小于5M文件')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFile = () => {
|
||||||
|
// 确定按钮
|
||||||
|
if (file.value === null) {
|
||||||
|
ElMessage('请先上传文件')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (percentage.value === 100) {
|
||||||
|
percentageFlage.value = false
|
||||||
|
}
|
||||||
|
sliceFile() // 上传切片
|
||||||
|
}
|
||||||
|
|
||||||
|
const sliceFile = () => {
|
||||||
|
waitUpLoad.value &&
|
||||||
|
waitUpLoad.value.forEach((item) => {
|
||||||
|
// 需要上传的切片
|
||||||
|
item.formData.append('chunkTotal', formDataList.value.length) // 切片总数携带给后台 总有用的
|
||||||
|
const fileR = new FileReader() // 功能同上
|
||||||
|
const fileF = item.formData.get('file')
|
||||||
|
fileR.readAsArrayBuffer(fileF)
|
||||||
|
fileR.onload = (e) => {
|
||||||
|
const spark = new SparkMD5.ArrayBuffer()
|
||||||
|
spark.append(e.target.result)
|
||||||
|
item.formData.append('chunkMd5', spark.end()) // 获取当前切片md5 后端用于验证切片完整性
|
||||||
|
upLoadFileSlice(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => waitNum.value,
|
||||||
|
() => {
|
||||||
|
percentage.value = Math.floor(
|
||||||
|
((formDataList.value.length - waitNum.value) /
|
||||||
|
formDataList.value.length) *
|
||||||
|
100
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const upLoadFileSlice = async (item) => {
|
||||||
|
// 切片上传
|
||||||
|
const fileRe = await breakpointContinue(item.formData)
|
||||||
|
if (fileRe.code !== 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
waitNum.value-- // 百分数增加
|
||||||
|
if (waitNum.value === 0) {
|
||||||
|
// 切片传完以后 合成文件
|
||||||
const params = {
|
const params = {
|
||||||
fileName: file.value.name,
|
fileName: file.value.name,
|
||||||
fileMd5: fileMd5.value,
|
fileMd5: fileMd5.value
|
||||||
chunkTotal: formDataList.value.length
|
|
||||||
}
|
}
|
||||||
const res = await findFile(params)
|
const res = await breakpointContinueFinish(params)
|
||||||
// 全部切完以后 发一个请求给后端 拉当前文件后台存储的切片信息 用于检测有多少上传成功的切片
|
if (res.code === 0) {
|
||||||
const finishList = res.data.file.ExaFileChunk // 上传成功的切片
|
// 合成文件过后 删除缓存切片
|
||||||
const IsFinish = res.data.file.IsFinish // 是否是同文件不同命 (文件md5相同 文件名不同 则默认是同一个文件但是不同文件名 此时后台数据库只需要拷贝一下数据库文件即可 不需要上传文件 即秒传功能)
|
const params = {
|
||||||
if (!IsFinish) {
|
fileName: file.value.name,
|
||||||
// 当是断点续传时候
|
fileMd5: fileMd5.value,
|
||||||
waitUpLoad.value = formDataList.value.filter(all => {
|
filePath: res.data.filePath
|
||||||
return !(
|
}
|
||||||
finishList &&
|
ElMessage.success('上传成功')
|
||||||
finishList.some(fi => fi.FileChunkNumber === all.key)
|
await removeChunk(params)
|
||||||
) // 找出需要上传的切片
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
waitUpLoad.value = [] // 秒传则没有需要上传的切片
|
|
||||||
ElMessage.success('文件已秒传')
|
|
||||||
}
|
}
|
||||||
waitNum.value = waitUpLoad.value.length // 记录长度用于百分比展示
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
limitFileSize.value = true
|
|
||||||
ElMessage('请上传小于5M文件')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getFile = () => {
|
|
||||||
// 确定按钮
|
|
||||||
if (file.value === null) {
|
|
||||||
ElMessage('请先上传文件')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (percentage.value === 100) {
|
|
||||||
percentageFlage.value = false
|
|
||||||
}
|
|
||||||
sliceFile() // 上传切片
|
|
||||||
}
|
|
||||||
|
|
||||||
const sliceFile = () => {
|
|
||||||
waitUpLoad.value &&
|
|
||||||
waitUpLoad.value.forEach(item => {
|
|
||||||
// 需要上传的切片
|
|
||||||
item.formData.append('chunkTotal', formDataList.value.length) // 切片总数携带给后台 总有用的
|
|
||||||
const fileR = new FileReader() // 功能同上
|
|
||||||
const fileF = item.formData.get('file')
|
|
||||||
fileR.readAsArrayBuffer(fileF)
|
|
||||||
fileR.onload = e => {
|
|
||||||
const spark = new SparkMD5.ArrayBuffer()
|
|
||||||
spark.append(e.target.result)
|
|
||||||
item.formData.append('chunkMd5', spark.end()) // 获取当前切片md5 后端用于验证切片完整性
|
|
||||||
upLoadFileSlice(item)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(() => waitNum.value, () => { percentage.value = Math.floor(((formDataList.value.length - waitNum.value) / formDataList.value.length) * 100) })
|
|
||||||
|
|
||||||
const upLoadFileSlice = async(item) => {
|
|
||||||
// 切片上传
|
|
||||||
const fileRe = await breakpointContinue(item.formData)
|
|
||||||
if (fileRe.code !== 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
waitNum.value-- // 百分数增加
|
|
||||||
if (waitNum.value === 0) {
|
|
||||||
// 切片传完以后 合成文件
|
|
||||||
const params = {
|
|
||||||
fileName: file.value.name,
|
|
||||||
fileMd5: fileMd5.value
|
|
||||||
}
|
|
||||||
const res = await breakpointContinueFinish(params)
|
|
||||||
if (res.code === 0) {
|
|
||||||
// 合成文件过后 删除缓存切片
|
|
||||||
const params = {
|
|
||||||
fileName: file.value.name,
|
|
||||||
fileMd5: fileMd5.value,
|
|
||||||
filePath: res.data.filePath,
|
|
||||||
}
|
|
||||||
ElMessage.success('上传成功')
|
|
||||||
await removeChunk(params)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const FileInput = ref(null)
|
const FileInput = ref(null)
|
||||||
const inputChange = () => {
|
const inputChange = () => {
|
||||||
FileInput.value.dispatchEvent(new MouseEvent('click'))
|
FileInput.value.dispatchEvent(new MouseEvent('click'))
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang="scss" scoped>
|
||||||
h3 {
|
h3 {
|
||||||
margin: 40px 0 0;
|
margin: 40px 0 0;
|
||||||
}
|
}
|
||||||
ul {
|
ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
li {
|
li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
color: #42b983;
|
color: #42b983;
|
||||||
}
|
}
|
||||||
#fromCont{
|
#fromCont {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
.fileUpload{
|
.fileUpload {
|
||||||
padding: 3px 10px;
|
padding: 3px 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
|
@ -241,7 +239,7 @@ a {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
input{
|
input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
font-size: 100px;
|
font-size: 100px;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
|
@ -249,47 +247,48 @@ a {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fileName{
|
.fileName {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
margin: 6px 15px 0 15px;
|
margin: 6px 15px 0 15px;
|
||||||
}
|
}
|
||||||
.uploadBtn{
|
.uploadBtn {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -10px;
|
top: -10px;
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
.tips{
|
.tips {
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
}
|
}
|
||||||
.el-divider{
|
.el-divider {
|
||||||
margin: 0 0 30px 0;
|
margin: 0 0 30px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list{
|
.list {
|
||||||
margin-top:15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
.list-item {
|
.list-item {
|
||||||
display: block;
|
display: block;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
line-height: 25px;
|
line-height: 25px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
width: 40%;
|
width: 40%;
|
||||||
.percentage{
|
.percentage {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.list-enter-active, .list-leave-active {
|
.list-enter-active,
|
||||||
transition: all 1s;
|
.list-leave-active {
|
||||||
}
|
transition: all 1s;
|
||||||
.list-enter, .list-leave-to
|
}
|
||||||
|
.list-enter, .list-leave-to
|
||||||
/* .list-leave-active for below version 2.1.8 */ {
|
/* .list-leave-active for below version 2.1.8 */ {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(-30px);
|
transform: translateY(-30px);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<warning-bar title="在资源权限中将此角色的资源权限清空 或者不包含创建者的角色 即可屏蔽此客户资源的显示" />
|
<warning-bar
|
||||||
|
title="在资源权限中将此角色的资源权限清空 或者不包含创建者的角色 即可屏蔽此客户资源的显示"
|
||||||
|
/>
|
||||||
<div class="gva-table-box">
|
<div class="gva-table-box">
|
||||||
<div class="gva-btn-list">
|
<div class="gva-btn-list">
|
||||||
<el-button
|
<el-button type="primary" icon="plus" @click="openDrawer"
|
||||||
type="primary"
|
>新增</el-button
|
||||||
icon="plus"
|
>
|
||||||
@click="openDrawer"
|
|
||||||
>新增</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
<el-table
|
||||||
ref="multipleTable"
|
ref="multipleTable"
|
||||||
|
|
@ -16,15 +16,8 @@
|
||||||
tooltip-effect="dark"
|
tooltip-effect="dark"
|
||||||
row-key="ID"
|
row-key="ID"
|
||||||
>
|
>
|
||||||
<el-table-column
|
<el-table-column type="selection" width="55" />
|
||||||
type="selection"
|
<el-table-column align="left" label="接入日期" width="180">
|
||||||
width="55"
|
|
||||||
/>
|
|
||||||
<el-table-column
|
|
||||||
align="left"
|
|
||||||
label="接入日期"
|
|
||||||
width="180"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>{{ formatDate(scope.row.CreatedAt) }}</span>
|
<span>{{ formatDate(scope.row.CreatedAt) }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -47,24 +40,22 @@
|
||||||
prop="sysUserId"
|
prop="sysUserId"
|
||||||
width="120"
|
width="120"
|
||||||
/>
|
/>
|
||||||
<el-table-column
|
<el-table-column align="left" label="操作" min-width="160">
|
||||||
align="left"
|
|
||||||
label="操作"
|
|
||||||
min-width="160"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
icon="edit"
|
icon="edit"
|
||||||
@click="updateCustomer(scope.row)"
|
@click="updateCustomer(scope.row)"
|
||||||
>变更</el-button>
|
>变更</el-button
|
||||||
|
>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
icon="delete"
|
icon="delete"
|
||||||
@click="deleteCustomer(scope.row)"
|
@click="deleteCustomer(scope.row)"
|
||||||
>删除</el-button>
|
>删除</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
@ -90,29 +81,16 @@
|
||||||
<span class="text-lg">客户</span>
|
<span class="text-lg">客户</span>
|
||||||
<div>
|
<div>
|
||||||
<el-button @click="closeDrawer">取 消</el-button>
|
<el-button @click="closeDrawer">取 消</el-button>
|
||||||
<el-button
|
<el-button type="primary" @click="enterDrawer">确 定</el-button>
|
||||||
type="primary"
|
|
||||||
@click="enterDrawer"
|
|
||||||
>确 定</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<el-form
|
<el-form :inline="true" :model="form" label-width="80px">
|
||||||
:inline="true"
|
|
||||||
:model="form"
|
|
||||||
label-width="80px"
|
|
||||||
>
|
|
||||||
<el-form-item label="客户名">
|
<el-form-item label="客户名">
|
||||||
<el-input
|
<el-input v-model="form.customerName" autocomplete="off" />
|
||||||
v-model="form.customerName"
|
|
||||||
autocomplete="off"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="客户电话">
|
<el-form-item label="客户电话">
|
||||||
<el-input
|
<el-input v-model="form.customerPhoneData" autocomplete="off" />
|
||||||
v-model="form.customerPhoneData"
|
|
||||||
autocomplete="off"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
|
|
@ -120,116 +98,118 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
createExaCustomer,
|
createExaCustomer,
|
||||||
updateExaCustomer,
|
updateExaCustomer,
|
||||||
deleteExaCustomer,
|
deleteExaCustomer,
|
||||||
getExaCustomer,
|
getExaCustomer,
|
||||||
getExaCustomerList
|
getExaCustomerList
|
||||||
} from '@/api/customer'
|
} from '@/api/customer'
|
||||||
import WarningBar from '@/components/warningBar/warningBar.vue'
|
import WarningBar from '@/components/warningBar/warningBar.vue'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { formatDate } from '@/utils/format'
|
import { formatDate } from '@/utils/format'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Customer'
|
name: 'Customer'
|
||||||
})
|
})
|
||||||
|
|
||||||
const form = ref({
|
const form = ref({
|
||||||
customerName: '',
|
|
||||||
customerPhoneData: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const page = ref(1)
|
|
||||||
const total = ref(0)
|
|
||||||
const pageSize = ref(10)
|
|
||||||
const tableData = ref([])
|
|
||||||
|
|
||||||
// 分页
|
|
||||||
const handleSizeChange = (val) => {
|
|
||||||
pageSize.value = val
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCurrentChange = (val) => {
|
|
||||||
page.value = val
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询
|
|
||||||
const getTableData = async() => {
|
|
||||||
const table = await getExaCustomerList({ page: page.value, pageSize: pageSize.value })
|
|
||||||
if (table.code === 0) {
|
|
||||||
tableData.value = table.data.list
|
|
||||||
total.value = table.data.total
|
|
||||||
page.value = table.data.page
|
|
||||||
pageSize.value = table.data.pageSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getTableData()
|
|
||||||
|
|
||||||
const drawerFormVisible = ref(false)
|
|
||||||
const type = ref('')
|
|
||||||
const updateCustomer = async(row) => {
|
|
||||||
const res = await getExaCustomer({ ID: row.ID })
|
|
||||||
type.value = 'update'
|
|
||||||
if (res.code === 0) {
|
|
||||||
form.value = res.data.customer
|
|
||||||
drawerFormVisible.value = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const closeDrawer = () => {
|
|
||||||
drawerFormVisible.value = false
|
|
||||||
form.value = {
|
|
||||||
customerName: '',
|
customerName: '',
|
||||||
customerPhoneData: ''
|
customerPhoneData: ''
|
||||||
}
|
|
||||||
}
|
|
||||||
const deleteCustomer = async(row) => {
|
|
||||||
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}).then(async() => {
|
|
||||||
const res = await deleteExaCustomer({ ID: row.ID })
|
|
||||||
if (res.code === 0) {
|
|
||||||
ElMessage({
|
|
||||||
type: 'success',
|
|
||||||
message: '删除成功'
|
|
||||||
})
|
|
||||||
if (tableData.value.length === 1 && page.value > 1) {
|
|
||||||
page.value--
|
|
||||||
}
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
const enterDrawer = async() => {
|
|
||||||
let res
|
|
||||||
switch (type.value) {
|
|
||||||
case 'create':
|
|
||||||
res = await createExaCustomer(form.value)
|
|
||||||
break
|
|
||||||
case 'update':
|
|
||||||
res = await updateExaCustomer(form.value)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
res = await createExaCustomer(form.value)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.code === 0) {
|
const page = ref(1)
|
||||||
closeDrawer()
|
const total = ref(0)
|
||||||
|
const pageSize = ref(10)
|
||||||
|
const tableData = ref([])
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val
|
||||||
getTableData()
|
getTableData()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
const openDrawer = () => {
|
|
||||||
type.value = 'create'
|
|
||||||
drawerFormVisible.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
page.value = val
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
const getTableData = async () => {
|
||||||
|
const table = await getExaCustomerList({
|
||||||
|
page: page.value,
|
||||||
|
pageSize: pageSize.value
|
||||||
|
})
|
||||||
|
if (table.code === 0) {
|
||||||
|
tableData.value = table.data.list
|
||||||
|
total.value = table.data.total
|
||||||
|
page.value = table.data.page
|
||||||
|
pageSize.value = table.data.pageSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTableData()
|
||||||
|
|
||||||
|
const drawerFormVisible = ref(false)
|
||||||
|
const type = ref('')
|
||||||
|
const updateCustomer = async (row) => {
|
||||||
|
const res = await getExaCustomer({ ID: row.ID })
|
||||||
|
type.value = 'update'
|
||||||
|
if (res.code === 0) {
|
||||||
|
form.value = res.data.customer
|
||||||
|
drawerFormVisible.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const closeDrawer = () => {
|
||||||
|
drawerFormVisible.value = false
|
||||||
|
form.value = {
|
||||||
|
customerName: '',
|
||||||
|
customerPhoneData: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const deleteCustomer = async (row) => {
|
||||||
|
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(async () => {
|
||||||
|
const res = await deleteExaCustomer({ ID: row.ID })
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage({
|
||||||
|
type: 'success',
|
||||||
|
message: '删除成功'
|
||||||
|
})
|
||||||
|
if (tableData.value.length === 1 && page.value > 1) {
|
||||||
|
page.value--
|
||||||
|
}
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const enterDrawer = async () => {
|
||||||
|
let res
|
||||||
|
switch (type.value) {
|
||||||
|
case 'create':
|
||||||
|
res = await createExaCustomer(form.value)
|
||||||
|
break
|
||||||
|
case 'update':
|
||||||
|
res = await updateExaCustomer(form.value)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
res = await createExaCustomer(form.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.code === 0) {
|
||||||
|
closeDrawer()
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const openDrawer = () => {
|
||||||
|
type.value = 'create'
|
||||||
|
drawerFormVisible.value = true
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style></style>
|
<style></style>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<transition
|
<transition mode="out-in" name="el-fade-in-linear">
|
||||||
mode="out-in"
|
|
||||||
name="el-fade-in-linear"
|
|
||||||
>
|
|
||||||
<keep-alive :include="routerStore.keepAliveRouters">
|
<keep-alive :include="routerStore.keepAliveRouters">
|
||||||
<component :is="Component" />
|
<component :is="Component" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
|
|
@ -14,9 +11,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useRouterStore } from '@/pinia/modules/router'
|
import { useRouterStore } from '@/pinia/modules/router'
|
||||||
const routerStore = useRouterStore()
|
const routerStore = useRouterStore()
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Example'
|
name: 'Example'
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-loading.fullscreen.lock="fullscreenLoading">
|
<div v-loading.fullscreen.lock="fullscreenLoading">
|
||||||
<div class="gva-table-box">
|
<div class="gva-table-box">
|
||||||
<warning-bar
|
<warning-bar title="点击“文件名/备注”可以编辑文件名或者备注内容。" />
|
||||||
title="点击“文件名/备注”可以编辑文件名或者备注内容。"
|
|
||||||
/>
|
|
||||||
<div class="gva-btn-list gap-3">
|
<div class="gva-btn-list gap-3">
|
||||||
<upload-common
|
<upload-common :image-common="imageCommon" @on-success="getTableData" />
|
||||||
:image-common="imageCommon"
|
|
||||||
@on-success="getTableData"
|
|
||||||
/>
|
|
||||||
<upload-image
|
<upload-image
|
||||||
:image-url="imageUrl"
|
:image-url="imageUrl"
|
||||||
:file-size="512"
|
:file-size="512"
|
||||||
:max-w-h="1080"
|
:max-w-h="1080"
|
||||||
@on-success="getTableData"
|
@on-success="getTableData"
|
||||||
/>
|
/>
|
||||||
<el-button
|
<el-button type="primary" icon="upload" @click="importUrlFunc">
|
||||||
type="primary"
|
|
||||||
icon="upload"
|
|
||||||
@click="importUrlFunc"
|
|
||||||
>
|
|
||||||
导入URL
|
导入URL
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-input
|
<el-input
|
||||||
|
|
@ -27,33 +18,18 @@
|
||||||
class="w-72"
|
class="w-72"
|
||||||
placeholder="请输入文件名或备注"
|
placeholder="请输入文件名或备注"
|
||||||
/>
|
/>
|
||||||
<el-button
|
<el-button type="primary" icon="search" @click="getTableData"
|
||||||
type="primary"
|
>查询</el-button
|
||||||
icon="search"
|
>
|
||||||
@click="getTableData"
|
|
||||||
>查询</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table :data="tableData">
|
<el-table :data="tableData">
|
||||||
<el-table-column
|
<el-table-column align="left" label="预览" width="100">
|
||||||
align="left"
|
|
||||||
label="预览"
|
|
||||||
width="100"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<CustomPic
|
<CustomPic pic-type="file" :pic-src="scope.row.url" preview />
|
||||||
pic-type="file"
|
|
||||||
:pic-src="scope.row.url"
|
|
||||||
preview
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column align="left" label="日期" prop="UpdatedAt" width="180">
|
||||||
align="left"
|
|
||||||
label="日期"
|
|
||||||
prop="UpdatedAt"
|
|
||||||
width="180"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div>{{ formatDate(scope.row.UpdatedAt) }}</div>
|
<div>{{ formatDate(scope.row.UpdatedAt) }}</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -65,50 +41,37 @@
|
||||||
width="180"
|
width="180"
|
||||||
>
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div
|
<div class="name" @click="editFileNameFunc(scope.row)">
|
||||||
class="name"
|
{{ scope.row.name }}
|
||||||
@click="editFileNameFunc(scope.row)"
|
</div>
|
||||||
>{{ scope.row.name }}</div>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column align="left" label="链接" prop="url" min-width="300" />
|
||||||
align="left"
|
<el-table-column align="left" label="标签" prop="tag" width="100">
|
||||||
label="链接"
|
|
||||||
prop="url"
|
|
||||||
min-width="300"
|
|
||||||
/>
|
|
||||||
<el-table-column
|
|
||||||
align="left"
|
|
||||||
label="标签"
|
|
||||||
prop="tag"
|
|
||||||
width="100"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag
|
<el-tag
|
||||||
:type="scope.row.tag === 'jpg' ? 'info' : 'success'"
|
:type="scope.row.tag === 'jpg' ? 'info' : 'success'"
|
||||||
disable-transitions
|
disable-transitions
|
||||||
>{{ scope.row.tag }}
|
>{{ scope.row.tag }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column align="left" label="操作" width="160">
|
||||||
align="left"
|
|
||||||
label="操作"
|
|
||||||
width="160"
|
|
||||||
>
|
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button
|
<el-button
|
||||||
icon="download"
|
icon="download"
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
@click="downloadFile(scope.row)"
|
@click="downloadFile(scope.row)"
|
||||||
>下载</el-button>
|
>下载</el-button
|
||||||
|
>
|
||||||
<el-button
|
<el-button
|
||||||
icon="delete"
|
icon="delete"
|
||||||
type="primary"
|
type="primary"
|
||||||
link
|
link
|
||||||
@click="deleteFileFunc(scope.row)"
|
@click="deleteFileFunc(scope.row)"
|
||||||
>删除</el-button>
|
>删除</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
@ -129,175 +92,189 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {getFileList, deleteFile, editFileName, importURL} from '@/api/fileUploadAndDownload'
|
import {
|
||||||
import { downloadImage } from '@/utils/downloadImg'
|
getFileList,
|
||||||
import CustomPic from '@/components/customPic/index.vue'
|
deleteFile,
|
||||||
import UploadImage from '@/components/upload/image.vue'
|
editFileName,
|
||||||
import UploadCommon from '@/components/upload/common.vue'
|
importURL
|
||||||
import {CreateUUID, formatDate} from '@/utils/format'
|
} from '@/api/fileUploadAndDownload'
|
||||||
import WarningBar from '@/components/warningBar/warningBar.vue'
|
import { downloadImage } from '@/utils/downloadImg'
|
||||||
|
import CustomPic from '@/components/customPic/index.vue'
|
||||||
|
import UploadImage from '@/components/upload/image.vue'
|
||||||
|
import UploadCommon from '@/components/upload/common.vue'
|
||||||
|
import { CreateUUID, formatDate } from '@/utils/format'
|
||||||
|
import WarningBar from '@/components/warningBar/warningBar.vue'
|
||||||
|
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Upload',
|
name: 'Upload'
|
||||||
})
|
|
||||||
|
|
||||||
const path = ref(import.meta.env.VITE_BASE_API)
|
|
||||||
|
|
||||||
const imageUrl = ref('')
|
|
||||||
const imageCommon = ref('')
|
|
||||||
|
|
||||||
const page = ref(1)
|
|
||||||
const total = ref(0)
|
|
||||||
const pageSize = ref(10)
|
|
||||||
const search = ref({})
|
|
||||||
const tableData = ref([])
|
|
||||||
|
|
||||||
// 分页
|
|
||||||
const handleSizeChange = (val) => {
|
|
||||||
pageSize.value = val
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCurrentChange = (val) => {
|
|
||||||
page.value = val
|
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询
|
|
||||||
const getTableData = async() => {
|
|
||||||
const table = await getFileList({ page: page.value, pageSize: pageSize.value, ...search.value })
|
|
||||||
if (table.code === 0) {
|
|
||||||
tableData.value = table.data.list
|
|
||||||
total.value = table.data.total
|
|
||||||
page.value = table.data.page
|
|
||||||
pageSize.value = table.data.pageSize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getTableData()
|
|
||||||
|
|
||||||
const deleteFileFunc = async(row) => {
|
|
||||||
ElMessageBox.confirm('此操作将永久删除文件, 是否继续?', '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning',
|
|
||||||
})
|
})
|
||||||
.then(async() => {
|
|
||||||
const res = await deleteFile(row)
|
const path = ref(import.meta.env.VITE_BASE_API)
|
||||||
if (res.code === 0) {
|
|
||||||
ElMessage({
|
const imageUrl = ref('')
|
||||||
type: 'success',
|
const imageCommon = ref('')
|
||||||
message: '删除成功!',
|
|
||||||
})
|
const page = ref(1)
|
||||||
if (tableData.value.length === 1 && page.value > 1) {
|
const total = ref(0)
|
||||||
page.value--
|
const pageSize = ref(10)
|
||||||
|
const search = ref({})
|
||||||
|
const tableData = ref([])
|
||||||
|
|
||||||
|
// 分页
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
pageSize.value = val
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
page.value = val
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
const getTableData = async () => {
|
||||||
|
const table = await getFileList({
|
||||||
|
page: page.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
|
...search.value
|
||||||
|
})
|
||||||
|
if (table.code === 0) {
|
||||||
|
tableData.value = table.data.list
|
||||||
|
total.value = table.data.total
|
||||||
|
page.value = table.data.page
|
||||||
|
pageSize.value = table.data.pageSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getTableData()
|
||||||
|
|
||||||
|
const deleteFileFunc = async (row) => {
|
||||||
|
ElMessageBox.confirm('此操作将永久删除文件, 是否继续?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
.then(async () => {
|
||||||
|
const res = await deleteFile(row)
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage({
|
||||||
|
type: 'success',
|
||||||
|
message: '删除成功!'
|
||||||
|
})
|
||||||
|
if (tableData.value.length === 1 && page.value > 1) {
|
||||||
|
page.value--
|
||||||
|
}
|
||||||
|
getTableData()
|
||||||
}
|
}
|
||||||
getTableData()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
ElMessage({
|
|
||||||
type: 'info',
|
|
||||||
message: '已取消删除',
|
|
||||||
})
|
})
|
||||||
})
|
.catch(() => {
|
||||||
}
|
ElMessage({
|
||||||
|
type: 'info',
|
||||||
const downloadFile = (row) => {
|
message: '已取消删除'
|
||||||
if (row.url.indexOf('http://') > -1 || row.url.indexOf('https://') > -1) {
|
|
||||||
downloadImage(row.url, row.name)
|
|
||||||
} else {
|
|
||||||
downloadImage(path.value + '/' + row.url, row.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 编辑文件名或者备注
|
|
||||||
* @param row
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
const editFileNameFunc = async(row) => {
|
|
||||||
ElMessageBox.prompt('请输入文件名或者备注', '编辑', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
inputPattern: /\S/,
|
|
||||||
inputErrorMessage: '不能为空',
|
|
||||||
inputValue: row.name
|
|
||||||
}).then(async({ value }) => {
|
|
||||||
row.name = value
|
|
||||||
// console.log(row)
|
|
||||||
const res = await editFileName(row)
|
|
||||||
if (res.code === 0) {
|
|
||||||
ElMessage({
|
|
||||||
type: 'success',
|
|
||||||
message: '编辑成功!',
|
|
||||||
})
|
|
||||||
await getTableData()
|
|
||||||
}
|
|
||||||
}).catch(() => {
|
|
||||||
ElMessage({
|
|
||||||
type: 'info',
|
|
||||||
message: '取消修改'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导入URL
|
|
||||||
*/
|
|
||||||
const importUrlFunc = () => {
|
|
||||||
ElMessageBox.prompt('格式:文件名|链接或者仅链接。', '导入', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
inputType: 'textarea',
|
|
||||||
inputPlaceholder: '我的图片|https://my-oss.com/my.png\nhttps://my-oss.com/my_1.png',
|
|
||||||
inputPattern: /\S/,
|
|
||||||
inputErrorMessage: '不能为空',
|
|
||||||
}).then(async({ value }) => {
|
|
||||||
let data = value.split('\n')
|
|
||||||
let importData = []
|
|
||||||
data.forEach(item => {
|
|
||||||
let oneData = item.trim().split('|')
|
|
||||||
let url, name
|
|
||||||
if (oneData.length > 1) {
|
|
||||||
name = oneData[0].trim()
|
|
||||||
url = oneData[1]
|
|
||||||
} else {
|
|
||||||
url = oneData[0].trim()
|
|
||||||
let str = url.substring(url.lastIndexOf('/') + 1)
|
|
||||||
name = str.substring(0, str.lastIndexOf('.'))
|
|
||||||
}
|
|
||||||
if (url) {
|
|
||||||
importData.push({
|
|
||||||
name: name,
|
|
||||||
url: url,
|
|
||||||
tag: url.substring(url.lastIndexOf(".") + 1),
|
|
||||||
key: CreateUUID()
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const res = await importURL(importData)
|
|
||||||
if (res.code === 0) {
|
|
||||||
ElMessage({
|
|
||||||
type: 'success',
|
|
||||||
message: '导入成功!',
|
|
||||||
})
|
})
|
||||||
await getTableData()
|
}
|
||||||
|
|
||||||
|
const downloadFile = (row) => {
|
||||||
|
if (row.url.indexOf('http://') > -1 || row.url.indexOf('https://') > -1) {
|
||||||
|
downloadImage(row.url, row.name)
|
||||||
|
} else {
|
||||||
|
downloadImage(path.value + '/' + row.url, row.name)
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
}
|
||||||
ElMessage({
|
|
||||||
type: 'info',
|
/**
|
||||||
message: '取消导入',
|
* 编辑文件名或者备注
|
||||||
|
* @param row
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
const editFileNameFunc = async (row) => {
|
||||||
|
ElMessageBox.prompt('请输入文件名或者备注', '编辑', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
inputPattern: /\S/,
|
||||||
|
inputErrorMessage: '不能为空',
|
||||||
|
inputValue: row.name
|
||||||
})
|
})
|
||||||
})
|
.then(async ({ value }) => {
|
||||||
}
|
row.name = value
|
||||||
|
// console.log(row)
|
||||||
|
const res = await editFileName(row)
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage({
|
||||||
|
type: 'success',
|
||||||
|
message: '编辑成功!'
|
||||||
|
})
|
||||||
|
await getTableData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
ElMessage({
|
||||||
|
type: 'info',
|
||||||
|
message: '取消修改'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入URL
|
||||||
|
*/
|
||||||
|
const importUrlFunc = () => {
|
||||||
|
ElMessageBox.prompt('格式:文件名|链接或者仅链接。', '导入', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
inputType: 'textarea',
|
||||||
|
inputPlaceholder:
|
||||||
|
'我的图片|https://my-oss.com/my.png\nhttps://my-oss.com/my_1.png',
|
||||||
|
inputPattern: /\S/,
|
||||||
|
inputErrorMessage: '不能为空'
|
||||||
|
})
|
||||||
|
.then(async ({ value }) => {
|
||||||
|
let data = value.split('\n')
|
||||||
|
let importData = []
|
||||||
|
data.forEach((item) => {
|
||||||
|
let oneData = item.trim().split('|')
|
||||||
|
let url, name
|
||||||
|
if (oneData.length > 1) {
|
||||||
|
name = oneData[0].trim()
|
||||||
|
url = oneData[1]
|
||||||
|
} else {
|
||||||
|
url = oneData[0].trim()
|
||||||
|
let str = url.substring(url.lastIndexOf('/') + 1)
|
||||||
|
name = str.substring(0, str.lastIndexOf('.'))
|
||||||
|
}
|
||||||
|
if (url) {
|
||||||
|
importData.push({
|
||||||
|
name: name,
|
||||||
|
url: url,
|
||||||
|
tag: url.substring(url.lastIndexOf('.') + 1),
|
||||||
|
key: CreateUUID()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await importURL(importData)
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage({
|
||||||
|
type: 'success',
|
||||||
|
message: '导入成功!'
|
||||||
|
})
|
||||||
|
await getTableData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
ElMessage({
|
||||||
|
type: 'info',
|
||||||
|
message: '取消导入'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.name {
|
.name {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,74 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="rounded-lg flex items-center justify-evenly w-full h-full relative md:w-screen md:h-screen md:bg-[#194bfb] overflow-hidden">
|
<div
|
||||||
<div class="rounded-md w-full h-full flex items-center justify-center overflow-hidden">
|
class="rounded-lg flex items-center justify-evenly w-full h-full relative md:w-screen md:h-screen md:bg-[#194bfb] overflow-hidden"
|
||||||
<div class="oblique h-[130%] w-3/5 bg-white dark:bg-slate-900 transform -rotate-12 absolute -ml-80" />
|
>
|
||||||
|
<div
|
||||||
|
class="rounded-md w-full h-full flex items-center justify-center overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="oblique h-[130%] w-3/5 bg-white dark:bg-slate-900 transform -rotate-12 absolute -ml-80"
|
||||||
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="!page.showForm"
|
v-if="!page.showForm"
|
||||||
:class="[page.showReadme ?'slide-out-right' :'slide-in-fwd-top' ]"
|
:class="[page.showReadme ? 'slide-out-right' : 'slide-in-fwd-top']"
|
||||||
>
|
>
|
||||||
<div class=" text-lg">
|
<div class="text-lg">
|
||||||
<div class="font-sans text-4xl font-bold text-center mb-4 dark:text-white">GIN-VUE-ADMIN</div>
|
<div
|
||||||
|
class="font-sans text-4xl font-bold text-center mb-4 dark:text-white"
|
||||||
|
>
|
||||||
|
GIN-VUE-ADMIN
|
||||||
|
</div>
|
||||||
<p class="text-gray-600 dark:text-gray-300 mb-2">初始化须知</p>
|
<p class="text-gray-600 dark:text-gray-300 mb-2">初始化须知</p>
|
||||||
<p class="text-gray-600 dark:text-gray-300 mb-2">1.您需有用一定的VUE和GOLANG基础</p>
|
<p class="text-gray-600 dark:text-gray-300 mb-2">
|
||||||
<p class="text-gray-600 dark:text-gray-300 mb-2">2.请您确认是否已经阅读过<a
|
1.您需有用一定的VUE和GOLANG基础
|
||||||
class="text-blue-600 font-bold"
|
</p>
|
||||||
href="https://www.gin-vue-admin.com"
|
<p class="text-gray-600 dark:text-gray-300 mb-2">
|
||||||
target="_blank"
|
2.请您确认是否已经阅读过<a
|
||||||
>官方文档</a> <a
|
class="text-blue-600 font-bold"
|
||||||
class="text-blue-600 font-bold"
|
href="https://www.gin-vue-admin.com"
|
||||||
href="https://www.bilibili.com/video/BV1kv4y1g7nT?p=2"
|
target="_blank"
|
||||||
target="_blank"
|
>官方文档</a
|
||||||
>初始化视频</a></p>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300 mb-2">3.请您确认是否了解后续的配置流程</p>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300 mb-2">4.如果您使用mysql数据库,请确认数据库引擎为<span class="text-red-600 font-bold text-3xl ml-2 ">innoDB</span></p>
|
|
||||||
<p class="text-gray-600 dark:text-gray-300 mb-2">注:开发组不为文档中书写过的内容提供无偿服务</p>
|
|
||||||
<p class="flex items-center justify-between mt-8">
|
|
||||||
<el-button
|
|
||||||
type="primary"
|
|
||||||
size="large"
|
|
||||||
@click="goDoc"
|
|
||||||
>
|
>
|
||||||
|
<a
|
||||||
|
class="text-blue-600 font-bold"
|
||||||
|
href="https://www.bilibili.com/video/BV1kv4y1g7nT?p=2"
|
||||||
|
target="_blank"
|
||||||
|
>初始化视频</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mb-2">
|
||||||
|
3.请您确认是否了解后续的配置流程
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mb-2">
|
||||||
|
4.如果您使用mysql数据库,请确认数据库引擎为<span
|
||||||
|
class="text-red-600 font-bold text-3xl ml-2"
|
||||||
|
>innoDB</span
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-600 dark:text-gray-300 mb-2">
|
||||||
|
注:开发组不为文档中书写过的内容提供无偿服务
|
||||||
|
</p>
|
||||||
|
<p class="flex items-center justify-between mt-8">
|
||||||
|
<el-button type="primary" size="large" @click="goDoc">
|
||||||
阅读文档
|
阅读文档
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button type="primary" size="large" @click="showNext">
|
||||||
type="primary"
|
|
||||||
size="large"
|
|
||||||
@click="showNext"
|
|
||||||
>
|
|
||||||
我已确认
|
我已确认
|
||||||
</el-button>
|
</el-button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="page.showForm "
|
v-if="page.showForm"
|
||||||
:class="[ page.showForm ? 'slide-in-left' : 'slide-out-right' ]"
|
:class="[page.showForm ? 'slide-in-left' : 'slide-out-right']"
|
||||||
class="w-96"
|
class="w-96"
|
||||||
>
|
>
|
||||||
<el-form
|
<el-form ref="formRef" :model="form" label-width="100px" size="large">
|
||||||
ref="formRef"
|
|
||||||
:model="form"
|
|
||||||
label-width="100px"
|
|
||||||
size="large"
|
|
||||||
>
|
|
||||||
<el-form-item label="管理员密码">
|
<el-form-item label="管理员密码">
|
||||||
<el-input v-model="form.adminPassword" placeholder="admin账号的默认密码"></el-input>
|
<el-input
|
||||||
|
v-model="form.adminPassword"
|
||||||
|
placeholder="admin账号的默认密码"
|
||||||
|
></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="数据库类型">
|
<el-form-item label="数据库类型">
|
||||||
<el-select
|
<el-select
|
||||||
|
|
@ -61,79 +77,35 @@
|
||||||
class="w-full"
|
class="w-full"
|
||||||
@change="changeDB"
|
@change="changeDB"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option key="mysql" label="mysql" value="mysql" />
|
||||||
key="mysql"
|
<el-option key="pgsql" label="pgsql" value="pgsql" />
|
||||||
label="mysql"
|
<el-option key="oracle" label="oracle" value="oracle" />
|
||||||
value="mysql"
|
<el-option key="mssql" label="mssql" value="mssql" />
|
||||||
/>
|
<el-option key="sqlite" label="sqlite" value="sqlite" />
|
||||||
<el-option
|
|
||||||
key="pgsql"
|
|
||||||
label="pgsql"
|
|
||||||
value="pgsql"
|
|
||||||
/>
|
|
||||||
<el-option
|
|
||||||
key="oracle"
|
|
||||||
label="oracle"
|
|
||||||
value="oracle"
|
|
||||||
/>
|
|
||||||
<el-option
|
|
||||||
key="mssql"
|
|
||||||
label="mssql"
|
|
||||||
value="mssql"
|
|
||||||
/>
|
|
||||||
<el-option
|
|
||||||
key="sqlite"
|
|
||||||
label="sqlite"
|
|
||||||
value="sqlite"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item v-if="form.dbType !== 'sqlite'" label="host">
|
||||||
v-if="form.dbType !== 'sqlite'"
|
<el-input v-model="form.host" placeholder="请输入数据库链接" />
|
||||||
label="host"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="form.host"
|
|
||||||
placeholder="请输入数据库链接"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item v-if="form.dbType !== 'sqlite'" label="port">
|
||||||
v-if="form.dbType !== 'sqlite'"
|
<el-input v-model="form.port" placeholder="请输入数据库端口" />
|
||||||
label="port"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="form.port"
|
|
||||||
placeholder="请输入数据库端口"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item v-if="form.dbType !== 'sqlite'" label="userName">
|
||||||
v-if="form.dbType !== 'sqlite'"
|
|
||||||
label="userName"
|
|
||||||
>
|
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.userName"
|
v-model="form.userName"
|
||||||
placeholder="请输入数据库用户名"
|
placeholder="请输入数据库用户名"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item v-if="form.dbType !== 'sqlite'" label="password">
|
||||||
v-if="form.dbType !== 'sqlite'"
|
|
||||||
label="password"
|
|
||||||
>
|
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.password"
|
v-model="form.password"
|
||||||
placeholder="请输入数据库密码(没有则为空)"
|
placeholder="请输入数据库密码(没有则为空)"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="dbName">
|
<el-form-item label="dbName">
|
||||||
<el-input
|
<el-input v-model="form.dbName" placeholder="请输入数据库名称" />
|
||||||
v-model="form.dbName"
|
|
||||||
placeholder="请输入数据库名称"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<el-form-item v-if="form.dbType === 'sqlite'" label="dbPath">
|
||||||
v-if="form.dbType === 'sqlite'"
|
|
||||||
label="dbPath"
|
|
||||||
>
|
|
||||||
<el-input
|
<el-input
|
||||||
v-model="form.dbPath"
|
v-model="form.dbPath"
|
||||||
placeholder="请输入sqlite数据库文件存放路径"
|
placeholder="请输入sqlite数据库文件存放路径"
|
||||||
|
|
@ -141,255 +113,249 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<div style="text-align: right">
|
<div style="text-align: right">
|
||||||
<el-button
|
<el-button type="primary" @click="onSubmit">立即初始化</el-button>
|
||||||
type="primary"
|
|
||||||
@click="onSubmit"
|
|
||||||
>立即初始化</el-button>
|
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hidden md:block w-1/2 h-full float-right bg-[#194bfb]"><img
|
<div class="hidden md:block w-1/2 h-full float-right bg-[#194bfb]">
|
||||||
class="h-full"
|
<img class="h-full" src="@/assets/login_right_banner.jpg" alt="banner" />
|
||||||
src="@/assets/login_right_banner.jpg"
|
</div>
|
||||||
alt="banner"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { initDB } from '@/api/initdb'
|
import { initDB } from '@/api/initdb'
|
||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import { ElLoading, ElMessage } from 'element-plus'
|
import { ElLoading, ElMessage } from 'element-plus'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Init',
|
name: 'Init'
|
||||||
})
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const page = reactive({
|
|
||||||
showReadme: false,
|
|
||||||
showForm: false
|
|
||||||
})
|
|
||||||
|
|
||||||
const showNext = () => {
|
|
||||||
page.showReadme = false
|
|
||||||
setTimeout(() => {
|
|
||||||
page.showForm = true
|
|
||||||
}, 20)
|
|
||||||
}
|
|
||||||
|
|
||||||
const goDoc = () => {
|
|
||||||
window.open('https://www.gin-vue-admin.com/guide/start-quickly/env.html')
|
|
||||||
}
|
|
||||||
|
|
||||||
const out = ref(false)
|
|
||||||
|
|
||||||
const form = reactive({
|
|
||||||
adminPassword: '123456',
|
|
||||||
dbType: 'mysql',
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: '3306',
|
|
||||||
userName: 'root',
|
|
||||||
password: '',
|
|
||||||
dbName: 'gva',
|
|
||||||
dbPath: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
const changeDB = (val) => {
|
|
||||||
switch (val) {
|
|
||||||
case 'mysql':
|
|
||||||
Object.assign(form, {
|
|
||||||
adminPassword:'123456',
|
|
||||||
reAdminPassword:'',
|
|
||||||
dbType: 'mysql',
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: '3306',
|
|
||||||
userName: 'root',
|
|
||||||
password: '',
|
|
||||||
dbName: 'gva',
|
|
||||||
dbPath: ''
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'pgsql':
|
|
||||||
Object.assign(form, {
|
|
||||||
adminPassword:'123456',
|
|
||||||
dbType: 'pgsql',
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: '5432',
|
|
||||||
userName: 'postgres',
|
|
||||||
password: '',
|
|
||||||
dbName: 'gva',
|
|
||||||
dbPath: ''
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'oracle':
|
|
||||||
Object.assign(form, {
|
|
||||||
adminPassword:'123456',
|
|
||||||
dbType: 'oracle',
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: '1521',
|
|
||||||
userName: 'oracle',
|
|
||||||
password: '',
|
|
||||||
dbName: 'gva',
|
|
||||||
dbPath: ''
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'mssql':
|
|
||||||
Object.assign(form, {
|
|
||||||
adminPassword:'123456',
|
|
||||||
dbType: 'mssql',
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: '1433',
|
|
||||||
userName: 'mssql',
|
|
||||||
password: '',
|
|
||||||
dbName: 'gva',
|
|
||||||
dbPath: ''
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'sqlite':
|
|
||||||
Object.assign(form, {
|
|
||||||
adminPassword:'123456',
|
|
||||||
dbType: 'sqlite',
|
|
||||||
host: '',
|
|
||||||
port: '',
|
|
||||||
userName: '',
|
|
||||||
password: '',
|
|
||||||
dbName: 'gva',
|
|
||||||
dbPath: ''
|
|
||||||
})
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
Object.assign(form, {
|
|
||||||
adminPassword:'123456',
|
|
||||||
dbType: 'mysql',
|
|
||||||
host: '127.0.0.1',
|
|
||||||
port: '3306',
|
|
||||||
userName: 'root',
|
|
||||||
password: '',
|
|
||||||
dbName: 'gva',
|
|
||||||
dbPath: ''
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onSubmit = async() => {
|
|
||||||
if (form.adminPassword.length < 6) {
|
|
||||||
ElMessage({
|
|
||||||
type: 'error',
|
|
||||||
message: '密码长度不能小于6位',
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const loading = ElLoading.service({
|
|
||||||
lock: true,
|
|
||||||
text: '正在初始化数据库,请稍候',
|
|
||||||
spinner: 'loading',
|
|
||||||
background: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
})
|
})
|
||||||
try {
|
|
||||||
const res = await initDB(form)
|
const router = useRouter()
|
||||||
if (res.code === 0) {
|
|
||||||
out.value = true
|
const page = reactive({
|
||||||
ElMessage({
|
showReadme: false,
|
||||||
type: 'success',
|
showForm: false
|
||||||
message: res.msg,
|
})
|
||||||
})
|
|
||||||
router.push({ name: 'Login' })
|
const showNext = () => {
|
||||||
}
|
page.showReadme = false
|
||||||
loading.close()
|
setTimeout(() => {
|
||||||
} catch (_) {
|
page.showForm = true
|
||||||
loading.close()
|
}, 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
const goDoc = () => {
|
||||||
|
window.open('https://www.gin-vue-admin.com/guide/start-quickly/env.html')
|
||||||
|
}
|
||||||
|
|
||||||
|
const out = ref(false)
|
||||||
|
|
||||||
|
const form = reactive({
|
||||||
|
adminPassword: '123456',
|
||||||
|
dbType: 'mysql',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: '3306',
|
||||||
|
userName: 'root',
|
||||||
|
password: '',
|
||||||
|
dbName: 'gva',
|
||||||
|
dbPath: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const changeDB = (val) => {
|
||||||
|
switch (val) {
|
||||||
|
case 'mysql':
|
||||||
|
Object.assign(form, {
|
||||||
|
adminPassword: '123456',
|
||||||
|
reAdminPassword: '',
|
||||||
|
dbType: 'mysql',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: '3306',
|
||||||
|
userName: 'root',
|
||||||
|
password: '',
|
||||||
|
dbName: 'gva',
|
||||||
|
dbPath: ''
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'pgsql':
|
||||||
|
Object.assign(form, {
|
||||||
|
adminPassword: '123456',
|
||||||
|
dbType: 'pgsql',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: '5432',
|
||||||
|
userName: 'postgres',
|
||||||
|
password: '',
|
||||||
|
dbName: 'gva',
|
||||||
|
dbPath: ''
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'oracle':
|
||||||
|
Object.assign(form, {
|
||||||
|
adminPassword: '123456',
|
||||||
|
dbType: 'oracle',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: '1521',
|
||||||
|
userName: 'oracle',
|
||||||
|
password: '',
|
||||||
|
dbName: 'gva',
|
||||||
|
dbPath: ''
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'mssql':
|
||||||
|
Object.assign(form, {
|
||||||
|
adminPassword: '123456',
|
||||||
|
dbType: 'mssql',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: '1433',
|
||||||
|
userName: 'mssql',
|
||||||
|
password: '',
|
||||||
|
dbName: 'gva',
|
||||||
|
dbPath: ''
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'sqlite':
|
||||||
|
Object.assign(form, {
|
||||||
|
adminPassword: '123456',
|
||||||
|
dbType: 'sqlite',
|
||||||
|
host: '',
|
||||||
|
port: '',
|
||||||
|
userName: '',
|
||||||
|
password: '',
|
||||||
|
dbName: 'gva',
|
||||||
|
dbPath: ''
|
||||||
|
})
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
Object.assign(form, {
|
||||||
|
adminPassword: '123456',
|
||||||
|
dbType: 'mysql',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: '3306',
|
||||||
|
userName: 'root',
|
||||||
|
password: '',
|
||||||
|
dbName: 'gva',
|
||||||
|
dbPath: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const onSubmit = async () => {
|
||||||
|
if (form.adminPassword.length < 6) {
|
||||||
|
ElMessage({
|
||||||
|
type: 'error',
|
||||||
|
message: '密码长度不能小于6位'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ElLoading.service({
|
||||||
|
lock: true,
|
||||||
|
text: '正在初始化数据库,请稍候',
|
||||||
|
spinner: 'loading',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
})
|
||||||
|
try {
|
||||||
|
const res = await initDB(form)
|
||||||
|
if (res.code === 0) {
|
||||||
|
out.value = true
|
||||||
|
ElMessage({
|
||||||
|
type: 'success',
|
||||||
|
message: res.msg
|
||||||
|
})
|
||||||
|
router.push({ name: 'Login' })
|
||||||
|
}
|
||||||
|
loading.close()
|
||||||
|
} catch (_) {
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.slide-in-fwd-top {
|
||||||
.slide-in-fwd-top {
|
-webkit-animation: slide-in-fwd-top 0.4s
|
||||||
-webkit-animation: slide-in-fwd-top 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94)
|
cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
||||||
both;
|
animation: slide-in-fwd-top 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
||||||
animation: slide-in-fwd-top 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
|
||||||
}
|
|
||||||
.slide-out-right {
|
|
||||||
-webkit-animation: slide-out-right 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53)
|
|
||||||
both;
|
|
||||||
animation: slide-out-right 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
|
|
||||||
}
|
|
||||||
.slide-in-left {
|
|
||||||
-webkit-animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94)
|
|
||||||
both;
|
|
||||||
animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
|
||||||
}
|
|
||||||
@-webkit-keyframes slide-in-fwd-top {
|
|
||||||
0% {
|
|
||||||
transform: translateZ(-1400px) translateY(-800px);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
}
|
||||||
100% {
|
.slide-out-right {
|
||||||
transform: translateZ(0) translateY(0);
|
-webkit-animation: slide-out-right 0.5s
|
||||||
opacity: 1;
|
cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
|
||||||
|
animation: slide-out-right 0.5s cubic-bezier(0.55, 0.085, 0.68, 0.53) both;
|
||||||
}
|
}
|
||||||
}
|
.slide-in-left {
|
||||||
@keyframes slide-in-fwd-top {
|
-webkit-animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94)
|
||||||
0% {
|
both;
|
||||||
transform: translateZ(-1400px) translateY(-800px);
|
animation: slide-in-left 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
||||||
opacity: 0;
|
|
||||||
}
|
}
|
||||||
100% {
|
@-webkit-keyframes slide-in-fwd-top {
|
||||||
transform: translateZ(0) translateY(0);
|
0% {
|
||||||
opacity: 1;
|
transform: translateZ(-1400px) translateY(-800px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateZ(0) translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
@keyframes slide-in-fwd-top {
|
||||||
@-webkit-keyframes slide-out-right {
|
0% {
|
||||||
0% {
|
transform: translateZ(-1400px) translateY(-800px);
|
||||||
transform: translateX(0);
|
opacity: 0;
|
||||||
opacity: 1;
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateZ(0) translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
100% {
|
@-webkit-keyframes slide-out-right {
|
||||||
transform: translateX(1000px);
|
0% {
|
||||||
opacity: 0;
|
transform: translateX(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(1000px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
@keyframes slide-out-right {
|
||||||
@keyframes slide-out-right {
|
0% {
|
||||||
0% {
|
transform: translateX(0);
|
||||||
transform: translateX(0);
|
opacity: 1;
|
||||||
opacity: 1;
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(1000px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
100% {
|
@-webkit-keyframes slide-in-left {
|
||||||
transform: translateX(1000px);
|
0% {
|
||||||
opacity: 0;
|
transform: translateX(-1000px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
@keyframes slide-in-left {
|
||||||
@-webkit-keyframes slide-in-left {
|
0% {
|
||||||
0% {
|
transform: translateX(-1000px);
|
||||||
transform: translateX(-1000px);
|
opacity: 0;
|
||||||
opacity: 0;
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
100% {
|
@media (max-width: 750px) {
|
||||||
transform: translateX(0);
|
.form {
|
||||||
opacity: 1;
|
width: 94vw !important;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@keyframes slide-in-left {
|
|
||||||
0% {
|
|
||||||
transform: translateX(-1000px);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media (max-width: 750px) {
|
|
||||||
.form {
|
|
||||||
width: 94vw !important;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
<template #title>
|
<template #title>
|
||||||
<div
|
<div
|
||||||
v-if="!isCollapse"
|
v-if="!isCollapse"
|
||||||
class="flex items-center "
|
class="flex items-center"
|
||||||
:style="{
|
:style="{
|
||||||
height : sideHeight,
|
height: sideHeight
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<el-icon v-if="routerInfo.meta.icon">
|
<el-icon v-if="routerInfo.meta.icon">
|
||||||
|
|
@ -29,39 +29,38 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { inject,computed } from 'vue'
|
import { inject, computed } from 'vue'
|
||||||
import { useAppStore } from '@/pinia'
|
import { useAppStore } from '@/pinia'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { config } = storeToRefs(appStore)
|
const { config } = storeToRefs(appStore)
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'AsyncSubmenu',
|
name: 'AsyncSubmenu'
|
||||||
})
|
})
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
routerInfo: {
|
routerInfo: {
|
||||||
default: function() {
|
default: function () {
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
type: Object
|
type: Object
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const isCollapse = inject('isCollapse', {
|
const isCollapse = inject('isCollapse', {
|
||||||
default: false,
|
default: false
|
||||||
})
|
})
|
||||||
|
|
||||||
const sideHeight = computed(() => {
|
|
||||||
return config.value.layout_side_item_height + 'px'
|
|
||||||
})
|
|
||||||
|
|
||||||
|
const sideHeight = computed(() => {
|
||||||
|
return config.value.layout_side_item_height + 'px'
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.gva-sub-menu{
|
.gva-sub-menu {
|
||||||
.el-sub-menu__title{
|
.el-sub-menu__title {
|
||||||
height: v-bind('sideHeight') !important;
|
height: v-bind('sideHeight') !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
v-if="!routerInfo.hidden"
|
v-if="!routerInfo.hidden"
|
||||||
:router-info="routerInfo"
|
:router-info="routerInfo"
|
||||||
>
|
>
|
||||||
<template v-if="routerInfo.children&&routerInfo.children.length">
|
<template v-if="routerInfo.children && routerInfo.children.length">
|
||||||
<AsideComponent
|
<AsideComponent
|
||||||
v-for="item in routerInfo.children"
|
v-for="item in routerInfo.children"
|
||||||
:key="item.name"
|
:key="item.name"
|
||||||
|
|
@ -14,35 +14,34 @@
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import MenuItem from './menuItem.vue'
|
import MenuItem from './menuItem.vue'
|
||||||
import AsyncSubmenu from './asyncSubmenu.vue'
|
import AsyncSubmenu from './asyncSubmenu.vue'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'AsideComponent',
|
name: 'AsideComponent'
|
||||||
})
|
})
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
routerInfo: {
|
routerInfo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => null,
|
default: () => null
|
||||||
},
|
},
|
||||||
mode :{
|
mode: {
|
||||||
type : String,
|
type: String,
|
||||||
default: "vertical"
|
default: 'vertical'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const menuComponent = computed(() => {
|
|
||||||
if (props.routerInfo.children && props.routerInfo.children.filter(item => !item.hidden).length) {
|
|
||||||
return AsyncSubmenu
|
|
||||||
} else {
|
|
||||||
return MenuItem
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
|
const menuComponent = computed(() => {
|
||||||
|
if (
|
||||||
|
props.routerInfo.children &&
|
||||||
|
props.routerInfo.children.filter((item) => !item.hidden).length
|
||||||
|
) {
|
||||||
|
return AsyncSubmenu
|
||||||
|
} else {
|
||||||
|
return MenuItem
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
:index="routerInfo.name"
|
:index="routerInfo.name"
|
||||||
class="dark:text-slate-300 overflow-hidden"
|
class="dark:text-slate-300 overflow-hidden"
|
||||||
:style="{
|
:style="{
|
||||||
height : sideHeight,
|
height: sideHeight
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<el-icon v-if="routerInfo.meta.icon">
|
<el-icon v-if="routerInfo.meta.icon">
|
||||||
|
|
@ -15,33 +15,29 @@
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { useAppStore } from '@/pinia'
|
import { useAppStore } from '@/pinia'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { config } = storeToRefs(appStore)
|
const { config } = storeToRefs(appStore)
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'MenuItem',
|
name: 'MenuItem'
|
||||||
})
|
})
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
routerInfo: {
|
routerInfo: {
|
||||||
default: function() {
|
default: function () {
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
type: Object
|
type: Object
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const sideHeight = computed(() => {
|
|
||||||
return config.value.layout_side_item_height + 'px'
|
|
||||||
})
|
|
||||||
|
|
||||||
|
const sideHeight = computed(() => {
|
||||||
|
return config.value.layout_side_item_height + 'px'
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full">
|
<div class="h-full">
|
||||||
<div v-if="mode==='head'" class="bg-white h-[calc(100%-4px)] text-slate-700 dark:text-slate-300 mx-2 dark:bg-slate-900 flex items-center w-[calc(100vw-600px)] overflow-auto">
|
<div
|
||||||
|
v-if="mode === 'head'"
|
||||||
|
class="bg-white h-[calc(100%-4px)] text-slate-700 dark:text-slate-300 mx-2 dark:bg-slate-900 flex items-center w-[calc(100vw-600px)] overflow-auto"
|
||||||
|
>
|
||||||
<el-menu
|
<el-menu
|
||||||
:default-active="routerStore.topActive"
|
:default-active="routerStore.topActive"
|
||||||
mode="horizontal"
|
mode="horizontal"
|
||||||
class="border-r-0 border-b-0 w-full flex gap-1 items-center box-border h-[calc(100%-1px)]"
|
class="border-r-0 border-b-0 w-full flex gap-1 items-center box-border h-[calc(100%-1px)]"
|
||||||
unique-opened
|
unique-opened
|
||||||
@select="(index, _, ele)=>selectMenuItem(index, _, ele,true)"
|
@select="(index, _, ele) => selectMenuItem(index, _, ele, true)"
|
||||||
>
|
>
|
||||||
<template v-for="item in routerStore.topMenu">
|
<template v-for="item in routerStore.topMenu">
|
||||||
<aside-component
|
<aside-component
|
||||||
|
|
@ -19,11 +22,11 @@
|
||||||
</el-menu>
|
</el-menu>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="mode==='normal'"
|
v-if="mode === 'normal'"
|
||||||
class="relative h-full bg-white text-slate-700 dark:text-slate-300 dark:bg-slate-900 border-r shadow dark:shadow-gray-700"
|
class="relative h-full bg-white text-slate-700 dark:text-slate-300 dark:bg-slate-900 border-r shadow dark:shadow-gray-700"
|
||||||
:class="isCollapse ? '' : ' px-2'"
|
:class="isCollapse ? '' : ' px-2'"
|
||||||
:style="{
|
:style="{
|
||||||
width: layoutSideWidth + 'px',
|
width: layoutSideWidth + 'px'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
|
|
@ -33,7 +36,7 @@
|
||||||
:default-active="active"
|
:default-active="active"
|
||||||
class="border-r-0 w-full"
|
class="border-r-0 w-full"
|
||||||
unique-opened
|
unique-opened
|
||||||
@select="(index, _, ele)=>selectMenuItem(index, _, ele,false)"
|
@select="(index, _, ele) => selectMenuItem(index, _, ele, false)"
|
||||||
>
|
>
|
||||||
<template v-for="item in routerStore.leftMenu">
|
<template v-for="item in routerStore.leftMenu">
|
||||||
<aside-component
|
<aside-component
|
||||||
|
|
@ -60,79 +63,79 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import AsideComponent from "@/view/layout/aside/asideComponent/index.vue";
|
import AsideComponent from '@/view/layout/aside/asideComponent/index.vue'
|
||||||
import { ref, provide, watchEffect, computed } from "vue";
|
import { ref, provide, watchEffect, computed } from 'vue'
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useRouterStore } from "@/pinia/modules/router";
|
import { useRouterStore } from '@/pinia/modules/router'
|
||||||
import { useAppStore } from "@/pinia";
|
import { useAppStore } from '@/pinia'
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from 'pinia'
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore()
|
||||||
const { device, config } = storeToRefs(appStore);
|
const { device, config } = storeToRefs(appStore)
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "GvaAside",
|
name: 'GvaAside'
|
||||||
});
|
})
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
mode:{
|
mode: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "normal",
|
default: 'normal'
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute()
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
const routerStore = useRouterStore();
|
const routerStore = useRouterStore()
|
||||||
const isCollapse = ref(false);
|
const isCollapse = ref(false)
|
||||||
const active = ref("");
|
const active = ref('')
|
||||||
const layoutSideWidth = computed(() => {
|
const layoutSideWidth = computed(() => {
|
||||||
if (!isCollapse.value) {
|
if (!isCollapse.value) {
|
||||||
return config.value.layout_side_width;
|
return config.value.layout_side_width
|
||||||
} else {
|
|
||||||
return config.value.layout_side_collapsed_width;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
watchEffect(() => {
|
|
||||||
active.value = route.meta.activeName || route.name;
|
|
||||||
});
|
|
||||||
|
|
||||||
watchEffect(() => {
|
|
||||||
if (device.value === "mobile") {
|
|
||||||
isCollapse.value = true;
|
|
||||||
} else {
|
|
||||||
isCollapse.value = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
provide("isCollapse", isCollapse);
|
|
||||||
|
|
||||||
const selectMenuItem = (index, _, ele,top) => {
|
|
||||||
const query = {};
|
|
||||||
const params = {};
|
|
||||||
routerStore.routeMap[index]?.parameters &&
|
|
||||||
routerStore.routeMap[index]?.parameters.forEach((item) => {
|
|
||||||
if (item.type === "query") {
|
|
||||||
query[item.key] = item.value;
|
|
||||||
} else {
|
} else {
|
||||||
params[item.key] = item.value;
|
return config.value.layout_side_collapsed_width
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
if (index === route.name) return;
|
|
||||||
if (index.indexOf("http://") > -1 || index.indexOf("https://") > -1) {
|
watchEffect(() => {
|
||||||
window.open(index);
|
active.value = route.meta.activeName || route.name
|
||||||
} else {
|
})
|
||||||
if(!top){
|
|
||||||
router.push({ name: index, query, params });
|
watchEffect(() => {
|
||||||
return
|
if (device.value === 'mobile') {
|
||||||
|
isCollapse.value = true
|
||||||
|
} else {
|
||||||
|
isCollapse.value = false
|
||||||
}
|
}
|
||||||
if (!routerStore.setLeftMenu(index)){
|
})
|
||||||
router.push({ name: index, query, params });
|
|
||||||
|
provide('isCollapse', isCollapse)
|
||||||
|
|
||||||
|
const selectMenuItem = (index, _, ele, top) => {
|
||||||
|
const query = {}
|
||||||
|
const params = {}
|
||||||
|
routerStore.routeMap[index]?.parameters &&
|
||||||
|
routerStore.routeMap[index]?.parameters.forEach((item) => {
|
||||||
|
if (item.type === 'query') {
|
||||||
|
query[item.key] = item.value
|
||||||
|
} else {
|
||||||
|
params[item.key] = item.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (index === route.name) return
|
||||||
|
if (index.indexOf('http://') > -1 || index.indexOf('https://') > -1) {
|
||||||
|
window.open(index)
|
||||||
|
} else {
|
||||||
|
if (!top) {
|
||||||
|
router.push({ name: index, query, params })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!routerStore.setLeftMenu(index)) {
|
||||||
|
router.push({ name: index, query, params })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const toggleCollapse = () => {
|
const toggleCollapse = () => {
|
||||||
isCollapse.value = !isCollapse.value;
|
isCollapse.value = !isCollapse.value
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="bg-white h-[calc(100%-4px)] text-slate-700 dark:text-slate-300 mx-2 dark:bg-slate-900 flex items-center w-[calc(100vw-600px)] overflow-auto">
|
<div
|
||||||
|
class="bg-white h-[calc(100%-4px)] text-slate-700 dark:text-slate-300 mx-2 dark:bg-slate-900 flex items-center w-[calc(100vw-600px)] overflow-auto"
|
||||||
|
>
|
||||||
<el-menu
|
<el-menu
|
||||||
:default-active="active"
|
:default-active="active"
|
||||||
mode="horizontal"
|
mode="horizontal"
|
||||||
|
|
@ -20,72 +22,70 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import AsideComponent from "@/view/layout/aside/asideComponent/index.vue";
|
import AsideComponent from '@/view/layout/aside/asideComponent/index.vue'
|
||||||
import { ref, provide, watchEffect } from "vue";
|
import { ref, provide, watchEffect } from 'vue'
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useRouterStore } from "@/pinia/modules/router";
|
import { useRouterStore } from '@/pinia/modules/router'
|
||||||
import { useAppStore } from "@/pinia";
|
import { useAppStore } from '@/pinia'
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from 'pinia'
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore()
|
||||||
const { device } = storeToRefs(appStore);
|
const { device } = storeToRefs(appStore)
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "GvaAside",
|
name: 'GvaAside'
|
||||||
});
|
})
|
||||||
const route = useRoute();
|
const route = useRoute()
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
const routerStore = useRouterStore();
|
const routerStore = useRouterStore()
|
||||||
const isCollapse = ref(false);
|
const isCollapse = ref(false)
|
||||||
const active = ref("");
|
const active = ref('')
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
active.value = route.meta.activeName || route.name;
|
active.value = route.meta.activeName || route.name
|
||||||
});
|
})
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (device.value === "mobile") {
|
if (device.value === 'mobile') {
|
||||||
isCollapse.value = true;
|
isCollapse.value = true
|
||||||
} else {
|
} else {
|
||||||
isCollapse.value = false;
|
isCollapse.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('isCollapse', isCollapse)
|
||||||
|
|
||||||
|
const selectMenuItem = (index) => {
|
||||||
|
const query = {}
|
||||||
|
const params = {}
|
||||||
|
routerStore.routeMap[index]?.parameters &&
|
||||||
|
routerStore.routeMap[index]?.parameters.forEach((item) => {
|
||||||
|
if (item.type === 'query') {
|
||||||
|
query[item.key] = item.value
|
||||||
|
} else {
|
||||||
|
params[item.key] = item.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (index === route.name) return
|
||||||
|
if (index.indexOf('http://') > -1 || index.indexOf('https://') > -1) {
|
||||||
|
window.open(index)
|
||||||
|
} else {
|
||||||
|
router.push({ name: index, query, params })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
provide("isCollapse", isCollapse);
|
|
||||||
|
|
||||||
const selectMenuItem = (index) => {
|
|
||||||
const query = {};
|
|
||||||
const params = {};
|
|
||||||
routerStore.routeMap[index]?.parameters &&
|
|
||||||
routerStore.routeMap[index]?.parameters.forEach((item) => {
|
|
||||||
if (item.type === "query") {
|
|
||||||
query[item.key] = item.value;
|
|
||||||
} else {
|
|
||||||
params[item.key] = item.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (index === route.name) return;
|
|
||||||
if (index.indexOf("http://") > -1 || index.indexOf("https://") > -1) {
|
|
||||||
window.open(index);
|
|
||||||
} else {
|
|
||||||
router.push({ name: index, query, params });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.el-menu--horizontal.el-menu,
|
.el-menu--horizontal.el-menu,
|
||||||
.el-menu--horizontal > .el-menu-item.is-active{
|
.el-menu--horizontal > .el-menu-item.is-active {
|
||||||
border-bottom : none !important;
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
.el-menu-item.is-active {
|
||||||
|
|
||||||
.el-menu-item.is-active{
|
|
||||||
background-color: var(--el-color-primary-light-8) !important;
|
background-color: var(--el-color-primary-light-8) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark{
|
.dark {
|
||||||
.el-menu-item.is-active{
|
.el-menu-item.is-active {
|
||||||
background-color: var(--el-color-primary-bg) !important;
|
background-color: var(--el-color-primary-bg) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,34 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<normal-mode v-if="config.side_mode === 'normal' || (device === 'mobile' && config.side_mode == 'head' ) || (device === 'mobile' && config.side_mode == 'combination' )" />
|
<normal-mode
|
||||||
<head-mode v-if="config.side_mode === 'head' && device !== 'mobile'"/>
|
v-if="
|
||||||
<combination-mode v-if="config.side_mode === 'combination' && device !== 'mobile'" :mode="mode"/>
|
config.side_mode === 'normal' ||
|
||||||
|
(device === 'mobile' && config.side_mode == 'head') ||
|
||||||
|
(device === 'mobile' && config.side_mode == 'combination')
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<head-mode v-if="config.side_mode === 'head' && device !== 'mobile'" />
|
||||||
|
<combination-mode
|
||||||
|
v-if="config.side_mode === 'combination' && device !== 'mobile'"
|
||||||
|
:mode="mode"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import NormalMode from "./normalMode.vue"
|
import NormalMode from './normalMode.vue'
|
||||||
import HeadMode from "./headMode.vue"
|
import HeadMode from './headMode.vue'
|
||||||
import CombinationMode from "./combinationMode.vue"
|
import CombinationMode from './combinationMode.vue'
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
mode:{
|
mode: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'normal'
|
default: 'normal'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from 'pinia'
|
||||||
import { useAppStore } from "@/pinia";
|
import { useAppStore } from '@/pinia'
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore()
|
||||||
const { config, device } = storeToRefs(appStore);
|
const { config, device } = storeToRefs(appStore)
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
class="relative h-full bg-white text-slate-700 dark:text-slate-300 dark:bg-slate-900 border-r shadow dark:shadow-gray-700"
|
class="relative h-full bg-white text-slate-700 dark:text-slate-300 dark:bg-slate-900 border-r shadow dark:shadow-gray-700"
|
||||||
:class="isCollapse ? '' : ' px-2'"
|
:class="isCollapse ? '' : ' px-2'"
|
||||||
:style="{
|
:style="{
|
||||||
width: layoutSideWidth + 'px',
|
width: layoutSideWidth + 'px'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
|
|
@ -39,67 +39,67 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import AsideComponent from "@/view/layout/aside/asideComponent/index.vue";
|
import AsideComponent from '@/view/layout/aside/asideComponent/index.vue'
|
||||||
import { ref, provide, watchEffect, computed } from "vue";
|
import { ref, provide, watchEffect, computed } from 'vue'
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useRouterStore } from "@/pinia/modules/router";
|
import { useRouterStore } from '@/pinia/modules/router'
|
||||||
import { useAppStore } from "@/pinia";
|
import { useAppStore } from '@/pinia'
|
||||||
import { storeToRefs } from "pinia";
|
import { storeToRefs } from 'pinia'
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore()
|
||||||
const { device, config } = storeToRefs(appStore);
|
const { device, config } = storeToRefs(appStore)
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "GvaAside",
|
name: 'GvaAside'
|
||||||
});
|
})
|
||||||
const route = useRoute();
|
const route = useRoute()
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
const routerStore = useRouterStore();
|
const routerStore = useRouterStore()
|
||||||
const isCollapse = ref(false);
|
const isCollapse = ref(false)
|
||||||
const active = ref("");
|
const active = ref('')
|
||||||
const layoutSideWidth = computed(() => {
|
const layoutSideWidth = computed(() => {
|
||||||
if (!isCollapse.value) {
|
if (!isCollapse.value) {
|
||||||
return config.value.layout_side_width;
|
return config.value.layout_side_width
|
||||||
} else {
|
} else {
|
||||||
return config.value.layout_side_collapsed_width;
|
return config.value.layout_side_collapsed_width
|
||||||
|
}
|
||||||
|
})
|
||||||
|
watchEffect(() => {
|
||||||
|
active.value = route.meta.activeName || route.name
|
||||||
|
})
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (device.value === 'mobile') {
|
||||||
|
isCollapse.value = true
|
||||||
|
} else {
|
||||||
|
isCollapse.value = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('isCollapse', isCollapse)
|
||||||
|
|
||||||
|
const selectMenuItem = (index) => {
|
||||||
|
const query = {}
|
||||||
|
const params = {}
|
||||||
|
routerStore.routeMap[index]?.parameters &&
|
||||||
|
routerStore.routeMap[index]?.parameters.forEach((item) => {
|
||||||
|
if (item.type === 'query') {
|
||||||
|
query[item.key] = item.value
|
||||||
|
} else {
|
||||||
|
params[item.key] = item.value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (index === route.name) return
|
||||||
|
if (index.indexOf('http://') > -1 || index.indexOf('https://') > -1) {
|
||||||
|
window.open(index)
|
||||||
|
} else {
|
||||||
|
router.push({ name: index, query, params })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
watchEffect(() => {
|
|
||||||
active.value = route.meta.activeName || route.name;
|
|
||||||
});
|
|
||||||
|
|
||||||
watchEffect(() => {
|
const toggleCollapse = () => {
|
||||||
if (device.value === "mobile") {
|
isCollapse.value = !isCollapse.value
|
||||||
isCollapse.value = true;
|
|
||||||
} else {
|
|
||||||
isCollapse.value = false;
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
provide("isCollapse", isCollapse);
|
|
||||||
|
|
||||||
const selectMenuItem = (index) => {
|
|
||||||
const query = {};
|
|
||||||
const params = {};
|
|
||||||
routerStore.routeMap[index]?.parameters &&
|
|
||||||
routerStore.routeMap[index]?.parameters.forEach((item) => {
|
|
||||||
if (item.type === "query") {
|
|
||||||
query[item.key] = item.value;
|
|
||||||
} else {
|
|
||||||
params[item.key] = item.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (index === route.name) return;
|
|
||||||
if (index.indexOf("http://") > -1 || index.indexOf("https://") > -1) {
|
|
||||||
window.open(index);
|
|
||||||
} else {
|
|
||||||
router.push({ name: index, query, params });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleCollapse = () => {
|
|
||||||
isCollapse.value = !isCollapse.value;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss"></style>
|
<style lang="scss"></style>
|
||||||
|
|
|
||||||
|
|
@ -4,53 +4,66 @@
|
||||||
!-->
|
!-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex justify-between fixed top-0 left-0 right-0 z-10 h-16 bg-white text-slate-700 dark:text-slate-300 dark:bg-slate-900 shadow dark:shadow-gray-700 items-center px-2">
|
<div
|
||||||
<div
|
class="flex justify-between fixed top-0 left-0 right-0 z-10 h-16 bg-white text-slate-700 dark:text-slate-300 dark:bg-slate-900 shadow dark:shadow-gray-700 items-center px-2"
|
||||||
class="flex items-center cursor-pointer flex-1"
|
>
|
||||||
>
|
<div class="flex items-center cursor-pointer flex-1">
|
||||||
<div class="flex items-center cursor-pointer min-w-48" @click="router.push({ path: '/' })">
|
<div
|
||||||
|
class="flex items-center cursor-pointer min-w-48"
|
||||||
|
@click="router.push({ path: '/' })"
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
alt
|
alt
|
||||||
class="h-12 bg-white rounded-full"
|
class="h-12 bg-white rounded-full"
|
||||||
:src="$GIN_VUE_ADMIN.appLogo"
|
:src="$GIN_VUE_ADMIN.appLogo"
|
||||||
>
|
/>
|
||||||
<div
|
<div
|
||||||
v-if="!isMobile"
|
v-if="!isMobile"
|
||||||
class="inline-flex font-bold text-2xl ml-2"
|
class="inline-flex font-bold text-2xl ml-2"
|
||||||
:class="(config.side_mode === 'head' || config.side_mode === 'combination') &&'min-w-fit'"
|
:class="
|
||||||
|
(config.side_mode === 'head' ||
|
||||||
|
config.side_mode === 'combination') &&
|
||||||
|
'min-w-fit'
|
||||||
|
"
|
||||||
>
|
>
|
||||||
{{ $GIN_VUE_ADMIN.appName }}
|
{{ $GIN_VUE_ADMIN.appName }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-breadcrumb v-show="!isMobile" v-if="config.side_mode !== 'head'&& config.side_mode !== 'combination'" class="ml-4">
|
<el-breadcrumb
|
||||||
|
v-show="!isMobile"
|
||||||
|
v-if="config.side_mode !== 'head' && config.side_mode !== 'combination'"
|
||||||
|
class="ml-4"
|
||||||
|
>
|
||||||
<el-breadcrumb-item
|
<el-breadcrumb-item
|
||||||
v-for="item in matched.slice(1, matched.length)"
|
v-for="item in matched.slice(1, matched.length)"
|
||||||
:key="item.path"
|
:key="item.path"
|
||||||
>
|
>
|
||||||
{{
|
{{ fmtTitle(item.meta.title, route) }}
|
||||||
fmtTitle(item.meta.title, route)
|
|
||||||
}}
|
|
||||||
</el-breadcrumb-item>
|
</el-breadcrumb-item>
|
||||||
</el-breadcrumb>
|
</el-breadcrumb>
|
||||||
<gva-aside v-if="config.side_mode === 'head' && !isMobile" class="flex-1" />
|
<gva-aside
|
||||||
<gva-aside v-if="config.side_mode === 'combination' && !isMobile" mode="head" class="flex-1" />
|
v-if="config.side_mode === 'head' && !isMobile"
|
||||||
|
class="flex-1"
|
||||||
|
/>
|
||||||
|
<gva-aside
|
||||||
|
v-if="config.side_mode === 'combination' && !isMobile"
|
||||||
|
mode="head"
|
||||||
|
class="flex-1"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ml-2 flex items-center">
|
<div class="ml-2 flex items-center">
|
||||||
<tools />
|
<tools />
|
||||||
<el-dropdown>
|
<el-dropdown>
|
||||||
<div
|
<div class="flex justify-center items-center h-full w-full">
|
||||||
class="flex justify-center items-center h-full w-full"
|
|
||||||
>
|
|
||||||
<span
|
<span
|
||||||
class="cursor-pointer flex justify-center items-center text-black dark:text-gray-100"
|
class="cursor-pointer flex justify-center items-center text-black dark:text-gray-100"
|
||||||
>
|
>
|
||||||
<CustomPic />
|
<CustomPic />
|
||||||
<span
|
<span v-show="!isMobile" class="w-16">{{
|
||||||
v-show="!isMobile"
|
userStore.userInfo.nickName
|
||||||
class="w-16"
|
}}</span>
|
||||||
>{{ userStore.userInfo.nickName }}</span>
|
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<arrow-down />
|
<arrow-down />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
|
|
@ -60,33 +73,24 @@
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item>
|
<el-dropdown-item>
|
||||||
<span class="font-bold">
|
<span class="font-bold">
|
||||||
当前角色:{{
|
当前角色:{{ userStore.userInfo.authority.authorityName }}
|
||||||
userStore.userInfo.authority.authorityName
|
|
||||||
}}
|
|
||||||
</span>
|
</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<template v-if="userStore.userInfo.authorities">
|
<template v-if="userStore.userInfo.authorities">
|
||||||
<el-dropdown-item
|
<el-dropdown-item
|
||||||
v-for="item in userStore.userInfo.authorities.filter(
|
v-for="item in userStore.userInfo.authorities.filter(
|
||||||
(i) =>
|
(i) => i.authorityId !== userStore.userInfo.authorityId
|
||||||
i.authorityId !==
|
|
||||||
userStore.userInfo.authorityId
|
|
||||||
)"
|
)"
|
||||||
:key="item.authorityId"
|
:key="item.authorityId"
|
||||||
@click="changeUserAuth(item.authorityId)"
|
@click="changeUserAuth(item.authorityId)"
|
||||||
>
|
>
|
||||||
<span>
|
<span> 切换为:{{ item.authorityName }} </span>
|
||||||
切换为:{{ item.authorityName }}
|
|
||||||
</span>
|
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</template>
|
</template>
|
||||||
<el-dropdown-item icon="avatar" @click="toPerson">
|
<el-dropdown-item icon="avatar" @click="toPerson">
|
||||||
个人信息
|
个人信息
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
<el-dropdown-item
|
<el-dropdown-item icon="reading-lamp" @click="userStore.LoginOut">
|
||||||
icon="reading-lamp"
|
|
||||||
@click="userStore.LoginOut"
|
|
||||||
>
|
|
||||||
登 出
|
登 出
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
|
|
@ -97,44 +101,39 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import tools from "./tools.vue"
|
import tools from './tools.vue'
|
||||||
import CustomPic from '@/components/customPic/index.vue'
|
import CustomPic from '@/components/customPic/index.vue'
|
||||||
import { useUserStore } from "@/pinia/modules/user";
|
import { useUserStore } from '@/pinia/modules/user'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useAppStore } from "@/pinia"
|
import { useAppStore } from '@/pinia'
|
||||||
import { storeToRefs } from "pinia"
|
import { storeToRefs } from 'pinia'
|
||||||
import { computed, } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { setUserAuthority } from '@/api/user'
|
import { setUserAuthority } from '@/api/user'
|
||||||
import { fmtTitle } from "@/utils/fmtRouterTitle";
|
import { fmtTitle } from '@/utils/fmtRouterTitle'
|
||||||
import gvaAside from "@/view/layout/aside/index.vue"
|
import gvaAside from '@/view/layout/aside/index.vue'
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const appStore = useAppStore()
|
const appStore = useAppStore()
|
||||||
const { device , config } = storeToRefs(appStore)
|
const { device, config } = storeToRefs(appStore)
|
||||||
const isMobile = computed(() =>{
|
const isMobile = computed(() => {
|
||||||
return device.value === 'mobile'
|
return device.value === 'mobile'
|
||||||
})
|
})
|
||||||
const toPerson = () => {
|
const toPerson = () => {
|
||||||
router.push({ name: "person" });
|
router.push({ name: 'person' })
|
||||||
};
|
|
||||||
const matched = computed(() => route.meta.matched);
|
|
||||||
|
|
||||||
|
|
||||||
const changeUserAuth = async (id) => {
|
|
||||||
const res = await setUserAuthority({
|
|
||||||
authorityId: id,
|
|
||||||
});
|
|
||||||
if (res.code === 0) {
|
|
||||||
window.sessionStorage.setItem("needCloseAll", "true");
|
|
||||||
window.sessionStorage.setItem("needToHome", "true");
|
|
||||||
window.location.reload();
|
|
||||||
}
|
}
|
||||||
};
|
const matched = computed(() => route.meta.matched)
|
||||||
|
|
||||||
|
|
||||||
|
const changeUserAuth = async (id) => {
|
||||||
|
const res = await setUserAuthority({
|
||||||
|
authorityId: id
|
||||||
|
})
|
||||||
|
if (res.code === 0) {
|
||||||
|
window.sessionStorage.setItem('needCloseAll', 'true')
|
||||||
|
window.sessionStorage.setItem('needToHome', 'true')
|
||||||
|
window.location.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -5,53 +5,46 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center mx-4 gap-4">
|
<div class="flex items-center mx-4 gap-4">
|
||||||
<el-tooltip
|
<el-tooltip class="" effect="dark" content="视频教程" placement="bottom">
|
||||||
class=""
|
|
||||||
effect="dark"
|
|
||||||
content="视频教程"
|
|
||||||
placement="bottom"
|
|
||||||
>
|
|
||||||
<el-dropdown @command="toDoc">
|
<el-dropdown @command="toDoc">
|
||||||
<el-icon class="w-8 h-8 shadow rounded-full border border-gray-200 dark:border-gray-600 cursor-pointer border-solid">
|
<el-icon
|
||||||
<Film />
|
class="w-8 h-8 shadow rounded-full border border-gray-200 dark:border-gray-600 cursor-pointer border-solid"
|
||||||
</el-icon>
|
>
|
||||||
|
<Film />
|
||||||
|
</el-icon>
|
||||||
|
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item v-for="item in videoList" :key="item.link" :command="item.link">{{ item.title }}</el-dropdown-item>
|
<el-dropdown-item
|
||||||
</el-dropdown-menu>
|
v-for="item in videoList"
|
||||||
</template>
|
:key="item.link"
|
||||||
|
:command="item.link"
|
||||||
|
>{{ item.title }}</el-dropdown-item
|
||||||
|
>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip
|
<el-tooltip class="" effect="dark" content="搜索" placement="bottom">
|
||||||
class=""
|
<el-icon
|
||||||
effect="dark"
|
@click="handleCommand"
|
||||||
content="搜索"
|
class="w-8 h-8 shadow rounded-full border border-gray-200 dark:border-gray-600 cursor-pointer border-solid"
|
||||||
placement="bottom"
|
>
|
||||||
>
|
|
||||||
<el-icon @click="handleCommand" class="w-8 h-8 shadow rounded-full border border-gray-200 dark:border-gray-600 cursor-pointer border-solid">
|
|
||||||
<Search />
|
<Search />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip
|
<el-tooltip class="" effect="dark" content="系统设置" placement="bottom">
|
||||||
class=""
|
<el-icon
|
||||||
effect="dark"
|
class="w-8 h-8 shadow rounded-full border border-gray-200 dark:border-gray-600 cursor-pointer border-solid"
|
||||||
content="系统设置"
|
@click="toggleSetting"
|
||||||
placement="bottom"
|
>
|
||||||
>
|
|
||||||
<el-icon class="w-8 h-8 shadow rounded-full border border-gray-200 dark:border-gray-600 cursor-pointer border-solid" @click="toggleSetting">
|
|
||||||
<Setting />
|
<Setting />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip
|
<el-tooltip class="" effect="dark" content="刷新" placement="bottom">
|
||||||
class=""
|
|
||||||
effect="dark"
|
|
||||||
content="刷新"
|
|
||||||
placement="bottom"
|
|
||||||
>
|
|
||||||
<el-icon
|
<el-icon
|
||||||
class="w-8 h-8 shadow rounded-full border border-gray-200 dark:border-gray-600 cursor-pointer border-solid"
|
class="w-8 h-8 shadow rounded-full border border-gray-200 dark:border-gray-600 cursor-pointer border-solid"
|
||||||
:class="showRefreshAnmite ? 'animate-spin' : ''"
|
:class="showRefreshAnmite ? 'animate-spin' : ''"
|
||||||
|
|
@ -67,10 +60,18 @@
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
:disabled="appStore.theme === 'auto'"
|
:disabled="appStore.theme === 'auto'"
|
||||||
>
|
>
|
||||||
<el-icon v-if="appStore.theme === 'dark'" class="w-8 h-8 shadow rounded-full border border-gray-600 cursor-pointer border-solid" @click="appStore.toggleTheme(false )">
|
<el-icon
|
||||||
|
v-if="appStore.theme === 'dark'"
|
||||||
|
class="w-8 h-8 shadow rounded-full border border-gray-600 cursor-pointer border-solid"
|
||||||
|
@click="appStore.toggleTheme(false)"
|
||||||
|
>
|
||||||
<Sunny />
|
<Sunny />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<el-icon v-else class="w-8 h-8 shadow rounded-full border border-gray-200 cursor-pointer border-solid" @click="appStore.toggleTheme(true)">
|
<el-icon
|
||||||
|
v-else
|
||||||
|
class="w-8 h-8 shadow rounded-full border border-gray-200 cursor-pointer border-solid"
|
||||||
|
@click="appStore.toggleTheme(true)"
|
||||||
|
>
|
||||||
<Moon />
|
<Moon />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
@ -81,119 +82,112 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { useAppStore } from '@/pinia'
|
||||||
|
import GvaSetting from '@/view/layout/setting/index.vue'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { emitter } from '@/utils/bus.js'
|
||||||
|
import CommandMenu from '@/components/commandMenu/index.vue'
|
||||||
|
import { toDoc } from '@/utils/doc'
|
||||||
|
|
||||||
import { useAppStore } from "@/pinia"
|
const appStore = useAppStore()
|
||||||
import GvaSetting from "@/view/layout/setting/index.vue"
|
const showSettingDrawer = ref(false)
|
||||||
import { ref } from "vue"
|
const showRefreshAnmite = ref(false)
|
||||||
import { emitter } from "@/utils/bus.js";
|
const toggleRefresh = () => {
|
||||||
import CommandMenu from "@/components/commandMenu/index.vue";
|
showRefreshAnmite.value = true
|
||||||
import {toDoc} from "@/utils/doc";
|
emitter.emit('reload')
|
||||||
|
setTimeout(() => {
|
||||||
const appStore = useAppStore()
|
showRefreshAnmite.value = false
|
||||||
const showSettingDrawer = ref(false)
|
}, 1000)
|
||||||
const showRefreshAnmite = ref(false)
|
|
||||||
const toggleRefresh = () =>{
|
|
||||||
showRefreshAnmite.value = true
|
|
||||||
emitter.emit('reload')
|
|
||||||
setTimeout(() => {
|
|
||||||
showRefreshAnmite.value = false
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleSetting = () => {
|
|
||||||
showSettingDrawer.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const first = ref("");
|
|
||||||
const command = ref();
|
|
||||||
|
|
||||||
const handleCommand = () => {
|
|
||||||
command.value.open();
|
|
||||||
};
|
|
||||||
const initPage = () => {
|
|
||||||
// 判断当前用户的操作系统
|
|
||||||
if (window.localStorage.getItem("osType") === "WIN") {
|
|
||||||
first.value = "Ctrl";
|
|
||||||
} else {
|
|
||||||
first.value = "⌘";
|
|
||||||
}
|
}
|
||||||
// 当用户同时按下ctrl和k键的时候
|
|
||||||
const handleKeyDown = (e) => {
|
const toggleSetting = () => {
|
||||||
if (e.ctrlKey && e.key === "k") {
|
showSettingDrawer.value = true
|
||||||
// 阻止浏览器默认事件
|
}
|
||||||
e.preventDefault();
|
|
||||||
handleCommand();
|
const first = ref('')
|
||||||
|
const command = ref()
|
||||||
|
|
||||||
|
const handleCommand = () => {
|
||||||
|
command.value.open()
|
||||||
|
}
|
||||||
|
const initPage = () => {
|
||||||
|
// 判断当前用户的操作系统
|
||||||
|
if (window.localStorage.getItem('osType') === 'WIN') {
|
||||||
|
first.value = 'Ctrl'
|
||||||
|
} else {
|
||||||
|
first.value = '⌘'
|
||||||
}
|
}
|
||||||
};
|
// 当用户同时按下ctrl和k键的时候
|
||||||
window.addEventListener("keydown", handleKeyDown);
|
const handleKeyDown = (e) => {
|
||||||
};
|
if (e.ctrlKey && e.key === 'k') {
|
||||||
|
// 阻止浏览器默认事件
|
||||||
initPage();
|
e.preventDefault()
|
||||||
|
handleCommand()
|
||||||
|
}
|
||||||
const videoList = [
|
}
|
||||||
{
|
window.addEventListener('keydown', handleKeyDown)
|
||||||
title:"1.clone项目和安装依赖",
|
|
||||||
link:"https://www.bilibili.com/video/BV1jx4y1s7xx",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"2.初始化项目",
|
|
||||||
link:"https://www.bilibili.com/video/BV1sr421K7sv",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"3.开启调试工具+创建初始化包",
|
|
||||||
link:"https://www.bilibili.com/video/BV1iH4y1c7Na",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"4.手动使用自动化创建功能",
|
|
||||||
link:"https://www.bilibili.com/video/BV1UZ421T7fV",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"5.使用已有表格创建业务",
|
|
||||||
link:"https://www.bilibili.com/video/BV1NE4m1977s",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"6.使用AI创建业务和创建数据源模式的可选项",
|
|
||||||
link:"https://www.bilibili.com/video/BV17i421a7DE",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"7.创建自己的后端方法",
|
|
||||||
link:"https://www.bilibili.com/video/BV1Yw4m1k7fg",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"8.新增一个前端页面",
|
|
||||||
link:"https://www.bilibili.com/video/BV12y411i7oE",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"9.配置一个前端二级页面",
|
|
||||||
link:"https://www.bilibili.com/video/BV1ZM4m1y7i3",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"10.配置一个前端菜单参数",
|
|
||||||
link:"https://www.bilibili.com/video/BV1WS42197DZ",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"11.菜单参数实战+动态菜单标题+菜单高亮配置",
|
|
||||||
link:"https://www.bilibili.com/video/BV1NE4m1979c",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"12.增加菜单可控按钮",
|
|
||||||
link:"https://www.bilibili.com/video/BV1Sw4m1k746",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"14.新增客户角色和其相关配置教学",
|
|
||||||
link:"https://www.bilibili.com/video/BV1Ki421a7X2",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title:"15.发布项目上线",
|
|
||||||
link:"https://www.bilibili.com/video/BV1Lx4y1s77D",
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
|
||||||
|
initPage()
|
||||||
|
|
||||||
|
const videoList = [
|
||||||
|
{
|
||||||
|
title: '1.clone项目和安装依赖',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1jx4y1s7xx'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '2.初始化项目',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1sr421K7sv'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '3.开启调试工具+创建初始化包',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1iH4y1c7Na'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '4.手动使用自动化创建功能',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1UZ421T7fV'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '5.使用已有表格创建业务',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1NE4m1977s'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '6.使用AI创建业务和创建数据源模式的可选项',
|
||||||
|
link: 'https://www.bilibili.com/video/BV17i421a7DE'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '7.创建自己的后端方法',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1Yw4m1k7fg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '8.新增一个前端页面',
|
||||||
|
link: 'https://www.bilibili.com/video/BV12y411i7oE'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '9.配置一个前端二级页面',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1ZM4m1y7i3'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '10.配置一个前端菜单参数',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1WS42197DZ'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '11.菜单参数实战+动态菜单标题+菜单高亮配置',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1NE4m1979c'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '12.增加菜单可控按钮',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1Sw4m1k746'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '14.新增客户角色和其相关配置教学',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1Ki421a7X2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '15.发布项目上线',
|
||||||
|
link: 'https://www.bilibili.com/video/BV1Lx4y1s77D'
|
||||||
|
}
|
||||||
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss"></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue