提交 a5e77a08 authored 作者: Administrator's avatar Administrator

更新

上级 e59f1c1e
# 开发环境 # 开发环境
VITE_APP_TITLE = "永信达商城系统" VITE_APP_TITLE = "永信达商城系统"
VITE_APP_PORT = 3003 VITE_APP_PORT = 3003
# 请求接口 # 请求接口
VITE_APP_BASE_URL = "/admin" VITE_APP_BASE_URL = "/admin"
VITE_APP_BASE_IMG = "" VITE_APP_BASE_IMG = ""
\ No newline at end of file
#生产环境 #生产环境
VITE_APP_TITLE = "永信达商城系统" VITE_APP_TITLE = "永信达商城系统"
VITE_APP_PORT = 3002 VITE_APP_PORT = 3002
# 请求接口 # 请求接口
VITE_APP_BASE_URL = "/admin" VITE_APP_BASE_URL = "/admin"
VITE_APP_BASE_IMG = "" VITE_APP_BASE_IMG = ""
\ No newline at end of file
node_modules node_modules
.DS_Store .DS_Store
dist dist
dist-ssr dist-ssr
*.local *.local
/dist /dist
# local env files # local env files
.env.local .env.local
.env.*.local .env.*.local
# Log files # Log files
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
# Editor directories and files # Editor directories and files
.idea .idea
.vscode .vscode
*.suo *.suo
*.ntvs* *.ntvs*
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
module.exports = { module.exports = {
// 字符串使用单引号 // 字符串使用单引号
singleQuote: true, singleQuote: true,
// 每行末尾自动添加分号 // 每行末尾自动添加分号
semi: true, semi: true,
// tab缩进大小,默认为2 // tab缩进大小,默认为2
tabWidth: 2, tabWidth: 2,
}; };
FROM nginx FROM nginx
COPY dist/ /var/www/html/ COPY dist/ /var/www/html/
COPY nginx/default.conf /etc/nginx/conf.d/default.conf COPY nginx/default.conf /etc/nginx/conf.d/default.conf
\ No newline at end of file
# starbos-ui # starbos-ui
#### Description #### Description
星支平台前端框架, 星支平台前端框架,
#### Software Architecture #### Software Architecture
Software architecture description Software architecture description
#### Installation #### Installation
1. xxxx 1. xxxx
2. xxxx 2. xxxx
3. xxxx 3. xxxx
#### Instructions #### Instructions
1. xxxx 1. xxxx
2. xxxx 2. xxxx
3. xxxx 3. xxxx
#### Contribution #### Contribution
1. Fork the repository 1. Fork the repository
2. Create Feat_xxx branch 2. Create Feat_xxx branch
3. Commit your code 3. Commit your code
4. Create Pull Request 4. Create Pull Request
#### Gitee Feature #### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com) 2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp) 4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
# starbos-ui # starbos-ui
#### 介绍 #### 介绍
永信达商城前端框架,基于vite +vue3.0+typescript+element-plus开发 永信达商城前端框架,基于vite +vue3.0+typescript+element-plus开发
## 项目安装 ## 项目安装
``` ```
yarn install yarn install
``` ```
### 项目编译及启动 ### 项目编译及启动
``` ```
yarn dev yarn dev
``` ```
### 编译部署 ### 编译部署
``` ```
yarn build yarn build
``` ```
### 行格式化 ### 行格式化
``` ```
yarn lint yarn lint
``` ```
### 自定义配置 ### 自定义配置
See [Configuration Reference](https://cli.vuejs.org/config/). See [Configuration Reference](https://cli.vuejs.org/config/).
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>永信达后台管理系统</title> <title>永信达后台管理系统</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>
</body> </body>
</html> </html>
<style> <style>
html, html,
body, body,
#app { #app {
padding: 0px; padding: 0px;
margin: 0px; margin: 0px;
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
</style> </style>
server { server {
listen 80; listen 80;
client_max_body_size 100m; client_max_body_size 100m;
#charset koi8-r; #charset koi8-r;
access_log /var/log/nginx/host.access.log main; access_log /var/log/nginx/host.access.log main;
error_log /var/log/nginx/error.log error; error_log /var/log/nginx/error.log error;
location / { location / {
root /var/www/html/; root /var/www/html/;
index index.html index.htm; index index.html index.htm;
if (!-e \$request_filename) { if (!-e \$request_filename) {
rewrite ^(.*)\$ /index.html?s=\$1 last; rewrite ^(.*)\$ /index.html?s=\$1 last;
break; break;
} }
} }
location /admin { location /admin {
proxy_pass http://yongxingda ; proxy_pass http://yongxingda ;
} }
location /wx { location /wx {
proxy_pass http://yongxingda; proxy_pass http://yongxingda;
} }
} }
\ No newline at end of file
{ {
"name": "starbos-ui", "name": "starbos-ui",
"version": "1.0.0", "version": "1.0.0",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vite build", "build": "vite build",
"serve": "vite preview --open", "serve": "vite preview --open",
"tsc": "vue-tsc --noEmit" "tsc": "vue-tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^1.1.4", "@element-plus/icons-vue": "^1.1.4",
"@wangeditor/editor": "^5.1.22", "@wangeditor/editor": "^5.1.22",
"@wangeditor/editor-for-vue": "^5.1.12", "@wangeditor/editor-for-vue": "^5.1.12",
"axios": "^0.24.0", "axios": "^0.24.0",
"echarts": "^5.4.0", "echarts": "^5.4.0",
"element-plus": "^2.2.12", "element-plus": "^2.2.12",
"eslint": "^8.4.1", "eslint": "^8.4.1",
"eslint-plugin-vue": "^8.2.0", "eslint-plugin-vue": "^8.2.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"moment": "^2.29.1", "moment": "^2.29.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"qs": "^6.10.3", "qs": "^6.10.3",
"socket.io-client": "^4.5.0", "socket.io-client": "^4.5.0",
"vue": "^3.2.33", "vue": "^3.2.33",
"vue-demi": "^0.13.1", "vue-demi": "^0.13.1",
"vue-i18n": "^9.1.10", "vue-i18n": "^9.1.10",
"vue-router": "4", "vue-router": "4",
"vue-socket.io": "^3.0.10", "vue-socket.io": "^3.0.10",
"vuex": "^4.0.2" "vuex": "^4.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/lodash": "^4.14.182", "@types/lodash": "^4.14.182",
"@types/node": "^16.11.12", "@types/node": "^16.11.12",
"@types/qs": "^6.9.7", "@types/qs": "^6.9.7",
"@vitejs/plugin-vue": "^2.3.1", "@vitejs/plugin-vue": "^2.3.1",
"node-sass": "^7.0.0", "node-sass": "^7.0.0",
"sass": "^1.44.0", "sass": "^1.44.0",
"sass-loader": "^12.4.0", "sass-loader": "^12.4.0",
"terser": "^5.16.1", "terser": "^5.16.1",
"typescript": "^4.4.3", "typescript": "^4.4.3",
"unplugin-auto-import": "^0.7.1", "unplugin-auto-import": "^0.7.1",
"unplugin-icons": "^0.14.3", "unplugin-icons": "^0.14.3",
"unplugin-vue-components": "^0.19.3", "unplugin-vue-components": "^0.19.3",
"vite": "^2.6.14", "vite": "^2.6.14",
"vite-plugin-inspect": "^0.5.0", "vite-plugin-inspect": "^0.5.0",
"vite-plugin-svg-icons": "^2.0.1", "vite-plugin-svg-icons": "^2.0.1",
"vue-tsc": "^0.3.0" "vue-tsc": "^0.3.0"
}, },
"license": "ISC" "license": "ISC"
} }
module.exports = { module.exports = {
root: true, root: true,
parserOptions: { parserOptions: {
// 对Babel解析器的包装使其与 ESLint 兼容。 // 对Babel解析器的包装使其与 ESLint 兼容。
// parser: 'babel-eslint', // parser: 'babel-eslint',
// 代码是 ECMAScript 模块 // 代码是 ECMAScript 模块
sourceType: "module", sourceType: "module",
}, },
parser: "vue-eslint-parser", parser: "vue-eslint-parser",
env: { env: {
browser: true, browser: true,
node: true, node: true,
es6: true, es6: true,
}, },
extends: [ extends: [
// https://github.com/vuejs/eslint-plugin-vue // https://github.com/vuejs/eslint-plugin-vue
"plugin:vue/vue3-essential", "plugin:vue/vue3-essential",
"plugin:vue/vue3-strongly-recommended", "plugin:vue/vue3-strongly-recommended",
"plugin:vue/vue3-recommended", "plugin:vue/vue3-recommended",
], ],
rules: { rules: {
"no-console": "off", "no-console": "off",
"comma-dangle": [2, "never"], //禁用使用拖尾逗号 "comma-dangle": [2, "never"], //禁用使用拖尾逗号
"vue/html-self-closing": [ "vue/html-self-closing": [
"error", "error",
{ {
html: { html: {
void: "never", void: "never",
normal: "always", normal: "always",
component: "always", component: "always",
}, },
"vue/multi-word-component-names": [ "vue/multi-word-component-names": [
"off", "off",
{ {
ignores: [], ignores: [],
}, },
], //允许组件单词 ], //允许组件单词
}, },
], ],
}, },
}; };
<script lang="ts"> <script lang="ts">
import { ElConfigProvider } from "element-plus"; import { ElConfigProvider } from "element-plus";
import zhCn from "element-plus/lib/locale/lang/zh-cn"; import zhCn from "element-plus/lib/locale/lang/zh-cn";
export default { export default {
components: { components: {
[ElConfigProvider.name]: ElConfigProvider, [ElConfigProvider.name]: ElConfigProvider,
}, },
setup() { setup() {
let locale = zhCn; let locale = zhCn;
return { return {
locale, locale,
}; };
}, },
}; };
</script> </script>
<template> <template>
<el-config-provider :locale="locale"> <el-config-provider :locale="locale">
<router-view></router-view> <router-view></router-view>
</el-config-provider> </el-config-provider>
</template> </template>
<style lang="scss"> <style lang="scss">
.margin-bottom-10 { .margin-bottom-10 {
margin-bottom: 10px; margin-bottom: 10px;
} }
/* 1px边框适配 */ /* 1px边框适配 */
.border-top-1px { .border-top-1px {
position: relative; position: relative;
&::after { &::after {
content: ""; content: "";
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; width: 100%;
border-top: 1px solid #e1e1e1; border-top: 1px solid #e1e1e1;
transform: scaleY(0.5); transform: scaleY(0.5);
} }
} }
.border-bottom-1px { .border-bottom-1px {
position: relative; position: relative;
&::after { &::after {
content: ""; content: "";
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
width: 100%; width: 100%;
border-bottom: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0;
transform: scaleY(0.4); transform: scaleY(0.4);
} }
} }
.border-left-1px { .border-left-1px {
position: relative; position: relative;
&::after { &::after {
content: ""; content: "";
position: absolute; position: absolute;
bottom: 0; bottom: 0;
left: 0; left: 0;
height: 100%; height: 100%;
border-left: 1px solid #e0e0e0; border-left: 1px solid #e0e0e0;
transform: scaleX(0.4); transform: scaleX(0.4);
} }
} }
/* 1px边框适配end */ /* 1px边框适配end */
/* flex布局 */ /* flex布局 */
/* 两端对齐 */ /* 两端对齐 */
.space-between { .space-between {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
/* 垂直居中对齐 */ /* 垂直居中对齐 */
.flex-center-h { .flex-center-h {
display: flex; display: flex;
align-items: center; align-items: center;
} }
/* 垂直水平居中对齐 */ /* 垂直水平居中对齐 */
.flex-center { .flex-center {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
/* 上下贴边 子class 宽度需100% */ /* 上下贴边 子class 宽度需100% */
.align-content { .align-content {
display: flex; display: flex;
flex-flow: wrap; flex-flow: wrap;
align-content: space-between; align-content: space-between;
} }
/* flex布局end */ /* flex布局end */
.font12 { .font12 {
font-size: 12px; font-size: 12px;
} }
.font14 { .font14 {
font-size: 14px; font-size: 14px;
} }
.font16 { .font16 {
font-size: 16px; font-size: 16px;
} }
/* 超出省略... */ /* 超出省略... */
.over1 { .over1 {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
word-break: break-all; word-break: break-all;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 1; -webkit-line-clamp: 1;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
display: -moz-box; display: -moz-box;
-moz-line-clamp: 1 !important; -moz-line-clamp: 1 !important;
-moz-box-orient: vertical; -moz-box-orient: vertical;
} }
.over2 { .over2 {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
word-break: break-all; word-break: break-all;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
display: -moz-box; display: -moz-box;
-moz-line-clamp: 2 !important; -moz-line-clamp: 2 !important;
-moz-box-orient: vertical; -moz-box-orient: vertical;
} }
.over3 { .over3 {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
word-break: break-all; word-break: break-all;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 3; -webkit-line-clamp: 3;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
display: -moz-box; display: -moz-box;
-moz-line-clamp: 3 !important; -moz-line-clamp: 3 !important;
-moz-box-orient: vertical; -moz-box-orient: vertical;
} }
/* 超出省略...end */ /* 超出省略...end */
</style> </style>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 20 20"><path d="M3 5h14V3H3v2zm12 8V7H5v6h10zM3 17h14v-2H3v2z" fill="currentColor"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 20 20"><path d="M3 5h14V3H3v2zm12 8V7H5v6h10zM3 17h14v-2H3v2z" fill="currentColor"></path></svg>
<svg t="1612248825727" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2133" width="128" height="128"><path d="M219.274 937.929c-55.89 0-101.359-45.502-101.359-101.427V251.879c0-57.479 46.708-106.035 101.996-106.035h396.04v56.951H219.91c-23.74 0-45.359 23.392-45.359 49.084v584.623c0 24.686 20.064 44.77 44.722 44.77h584.26c25.918 0 49.515-21.604 49.515-45.332V439.9h56.958v396.04c0 54.329-49.755 101.989-106.473 101.989h-584.26z m17.556-90.656c-9.038 0-17.174-4.225-22.316-11.593-6.02-8.628-7.114-19.995-3-31.177l105.543-213.708c1.945-10.565 6.485-19.543 13.23-26.288l378.709-378.955c9.95-9.95 23.172-15.428 37.237-15.428 14.052 0 27.281 5.478 37.245 15.421l86.067 86.144c9.943 9.943 15.42 23.18 15.42 37.258s-5.477 27.308-15.427 37.244L490.823 725.166c-6.888 6.902-15.804 11.34-27.26 13.572L251.396 843.835c-4.91 2.274-9.82 3.438-14.566 3.438z m28.453-68.798c-1.41 2.87-1.267 6.06 0.328 8.642 1.541 2.493 4.24 3.985 7.21 3.985 1.487 0 3.02-0.363 4.555-1.081l126.928-76.892-61.958-62.047-77.063 127.393z m107.864-176.703l80.432 80.507 269.79-269.961-81.015-79.932-269.207 269.386z m373.079-364.883c-5.43 0-10.546 2.123-14.394 5.985l-47.646 47.631 79.323 81.679 48.769-48.823c7.937-7.937 7.937-20.872-0.007-28.836l-51.617-51.651c-3.869-3.862-8.991-5.985-14.428-5.985zM534.497 790.903v-56.952h252.986v56.952H534.497z m122.518-98.017v-56.952h130.468v56.952H657.015zM240.44 447.844v-56.959h130.467v56.959H240.44z m0-98.024v-56.952h252.985v56.952H240.44z" p-id="2134" fill="#666666"></path></svg> <svg t="1612248825727" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2133" width="128" height="128"><path d="M219.274 937.929c-55.89 0-101.359-45.502-101.359-101.427V251.879c0-57.479 46.708-106.035 101.996-106.035h396.04v56.951H219.91c-23.74 0-45.359 23.392-45.359 49.084v584.623c0 24.686 20.064 44.77 44.722 44.77h584.26c25.918 0 49.515-21.604 49.515-45.332V439.9h56.958v396.04c0 54.329-49.755 101.989-106.473 101.989h-584.26z m17.556-90.656c-9.038 0-17.174-4.225-22.316-11.593-6.02-8.628-7.114-19.995-3-31.177l105.543-213.708c1.945-10.565 6.485-19.543 13.23-26.288l378.709-378.955c9.95-9.95 23.172-15.428 37.237-15.428 14.052 0 27.281 5.478 37.245 15.421l86.067 86.144c9.943 9.943 15.42 23.18 15.42 37.258s-5.477 27.308-15.427 37.244L490.823 725.166c-6.888 6.902-15.804 11.34-27.26 13.572L251.396 843.835c-4.91 2.274-9.82 3.438-14.566 3.438z m28.453-68.798c-1.41 2.87-1.267 6.06 0.328 8.642 1.541 2.493 4.24 3.985 7.21 3.985 1.487 0 3.02-0.363 4.555-1.081l126.928-76.892-61.958-62.047-77.063 127.393z m107.864-176.703l80.432 80.507 269.79-269.961-81.015-79.932-269.207 269.386z m373.079-364.883c-5.43 0-10.546 2.123-14.394 5.985l-47.646 47.631 79.323 81.679 48.769-48.823c7.937-7.937 7.937-20.872-0.007-28.836l-51.617-51.651c-3.869-3.862-8.991-5.985-14.428-5.985zM534.497 790.903v-56.952h252.986v56.952H534.497z m122.518-98.017v-56.952h130.468v56.952H657.015zM240.44 447.844v-56.959h130.467v56.959H240.44z m0-98.024v-56.952h252.985v56.952H240.44z" p-id="2134" fill="#666666"></path></svg>
<svg t="1615363536977" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16426" width="256" height="256"><path d="M938.688 341.312v519.808c0 42.816-34.752 77.568-77.568 77.568H162.88c-42.816 0-77.568-34.752-77.568-77.568V341.312h853.376zM402.112 483.584H389.12a32.32 32.32 0 0 0-31.808 26.496l-0.512 5.76v215.424c0 15.808 11.392 29.056 26.496 31.744l5.76 0.576h12.992a32.32 32.32 0 0 0 31.808-26.56l0.512-5.76V515.84a32.32 32.32 0 0 0-32.32-32.32z m232.704 0H563.84a50.88 50.88 0 0 0-10.88 1.152 32.384 32.384 0 0 0-40.32 25.344L512 515.84v215.424a32.32 32.32 0 0 0 64.128 5.76l0.512-5.76v-74.368h58.24c46.336 0 83.968-38.784 83.968-86.656 0-47.872-37.632-86.656-84.032-86.656z m0 66.624l3.904 0.448a19.84 19.84 0 0 1 15.488 19.584 19.84 19.84 0 0 1-14.912 19.456l-4.48 0.512H576.64v-40h58.24z m226.304-464.896c42.816 0 77.568 34.752 77.568 77.568v121.6H85.312v-121.6c0-42.816 34.752-77.568 77.568-77.568h698.24z" p-id="16427"></path></svg> <svg t="1615363536977" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16426" width="256" height="256"><path d="M938.688 341.312v519.808c0 42.816-34.752 77.568-77.568 77.568H162.88c-42.816 0-77.568-34.752-77.568-77.568V341.312h853.376zM402.112 483.584H389.12a32.32 32.32 0 0 0-31.808 26.496l-0.512 5.76v215.424c0 15.808 11.392 29.056 26.496 31.744l5.76 0.576h12.992a32.32 32.32 0 0 0 31.808-26.56l0.512-5.76V515.84a32.32 32.32 0 0 0-32.32-32.32z m232.704 0H563.84a50.88 50.88 0 0 0-10.88 1.152 32.384 32.384 0 0 0-40.32 25.344L512 515.84v215.424a32.32 32.32 0 0 0 64.128 5.76l0.512-5.76v-74.368h58.24c46.336 0 83.968-38.784 83.968-86.656 0-47.872-37.632-86.656-84.032-86.656z m0 66.624l3.904 0.448a19.84 19.84 0 0 1 15.488 19.584 19.84 19.84 0 0 1-14.912 19.456l-4.48 0.512H576.64v-40h58.24z m226.304-464.896c42.816 0 77.568 34.752 77.568 77.568v121.6H85.312v-121.6c0-42.816 34.752-77.568 77.568-77.568h698.24z" p-id="16427"></path></svg>
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827393750" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4695" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; } <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827393750" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4695" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
</style></defs><path d="M64 64V640H896V64H64zM0 0h960v704H0V0z" p-id="4696"></path><path d="M192 896H768v64H192zM448 640H512v256h-64z" p-id="4697"></path><path d="M479.232 561.604267l309.9904-348.330667-47.803733-42.5472-259.566934 291.669333L303.957333 240.008533 163.208533 438.6048l52.224 37.009067 91.6224-129.28z" p-id="4698"></path></svg> </style></defs><path d="M64 64V640H896V64H64zM0 0h960v704H0V0z" p-id="4696"></path><path d="M192 896H768v64H192zM448 640H512v256h-64z" p-id="4697"></path><path d="M479.232 561.604267l309.9904-348.330667-47.803733-42.5472-259.566934 291.669333L303.957333 240.008533 163.208533 438.6048l52.224 37.009067 91.6224-129.28z" p-id="4698"></path></svg>
\ No newline at end of file
<svg t="1615365233977" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="31529" width="256" height="256"><path d="M375.466667 614.4V341.333333c0-40.96 27.306667-68.266667 68.266666-68.266666h136.533334c40.96 0 68.266667 27.306667 68.266666 68.266666v273.066667h191.146667c6.826667 0 20.48 6.826667 27.306667 6.826667 13.653333 13.653333 13.653333 34.133333 0 47.786666l-327.68 327.68c-13.653333 13.653333-34.133333 13.653333-47.786667 0L163.84 675.84c-6.826667-6.826667-13.653333-20.48-13.653333-27.306667 0-20.48 13.653333-34.133333 34.133333-34.133333H375.466667z m34.133333-477.866667h204.8c20.48 0 34.133333 13.653333 34.133333 34.133334s-13.653333 34.133333-34.133333 34.133333h-204.8c-20.48 0-34.133333-13.653333-34.133333-34.133333s13.653333-34.133333 34.133333-34.133334z m0-136.533333h204.8c20.48 0 34.133333 13.653333 34.133333 34.133333s-13.653333 34.133333-34.133333 34.133334h-204.8C389.12 68.266667 375.466667 54.613333 375.466667 34.133333s13.653333-34.133333 34.133333-34.133333z" p-id="31530"></path></svg> <svg t="1615365233977" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="31529" width="256" height="256"><path d="M375.466667 614.4V341.333333c0-40.96 27.306667-68.266667 68.266666-68.266666h136.533334c40.96 0 68.266667 27.306667 68.266666 68.266666v273.066667h191.146667c6.826667 0 20.48 6.826667 27.306667 6.826667 13.653333 13.653333 13.653333 34.133333 0 47.786666l-327.68 327.68c-13.653333 13.653333-34.133333 13.653333-47.786667 0L163.84 675.84c-6.826667-6.826667-13.653333-20.48-13.653333-27.306667 0-20.48 13.653333-34.133333 34.133333-34.133333H375.466667z m34.133333-477.866667h204.8c20.48 0 34.133333 13.653333 34.133333 34.133334s-13.653333 34.133333-34.133333 34.133333h-204.8c-20.48 0-34.133333-13.653333-34.133333-34.133333s13.653333-34.133333 34.133333-34.133334z m0-136.533333h204.8c20.48 0 34.133333 13.653333 34.133333 34.133333s-13.653333 34.133333-34.133333 34.133334h-204.8C389.12 68.266667 375.466667 54.613333 375.466667 34.133333s13.653333-34.133333 34.133333-34.133333z" p-id="31530"></path></svg>
<svg t="1612242856287" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5203" width="128" height="128"><path d="M422.4 395.392l-27.2-327.68L256.768 194.88 114.688 64 65.472 109.12 207.616 240 69.184 367.168 422.4 395.392zM960 66.752 604.096 91.776l138.112 127.488L600.064 350.08l49.216 45.312 142.016-130.88 138.112 127.552L960 66.752zM423.936 675.392 374.848 630.016l-142.144 130.88L94.592 633.344 64 958.656l355.84-25.024-138.112-127.488L423.936 675.392zM958.528 914.88l-142.016-130.88 138.368-127.104L601.472 628.608l27.328 327.744 138.432-127.232L909.248 960 958.528 914.88z" p-id="5204" fill="#666666"></path></svg> <svg t="1612242856287" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5203" width="128" height="128"><path d="M422.4 395.392l-27.2-327.68L256.768 194.88 114.688 64 65.472 109.12 207.616 240 69.184 367.168 422.4 395.392zM960 66.752 604.096 91.776l138.112 127.488L600.064 350.08l49.216 45.312 142.016-130.88 138.112 127.552L960 66.752zM423.936 675.392 374.848 630.016l-142.144 130.88L94.592 633.344 64 958.656l355.84-25.024-138.112-127.488L423.936 675.392zM958.528 914.88l-142.016-130.88 138.368-127.104L601.472 628.608l27.328 327.744 138.432-127.232L909.248 960 958.528 914.88z" p-id="5204" fill="#666666"></path></svg>
body { body {
font-family: Avenir, Helvetica, Arial, sans-serif; font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
color: #2c3e50; color: #2c3e50;
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
html, html,
body, body,
#app { #app {
padding: 0px; padding: 0px;
margin: 0px; margin: 0px;
height: 100%; height: 100%;
} }
\ No newline at end of file
.router { .router {
margin: 10px 5px; margin: 10px 5px;
} }
.app-container { .app-container {
padding: 20px; padding: 20px;
} }
.filter-container { .filter-container {
padding-bottom: 10px; padding-bottom: 10px;
.filter-item { .filter-item {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
margin-bottom: 10px; margin-bottom: 10px;
margin-right: 10px; margin-right: 10px;
} }
} }
.avatar-uploader .avatar { .avatar-uploader .avatar {
width: 178px; width: 178px;
height: 178px; height: 178px;
display: block; display: block;
} }
.avatar-uploader .el-upload { .avatar-uploader .el-upload {
border: 1px dashed #dcdfe6; border: 1px dashed #dcdfe6;
border-radius: 6px; border-radius: 6px;
cursor: pointer; cursor: pointer;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
transition: 0.2s; transition: 0.2s;
} }
.avatar-uploader .el-upload:hover { .avatar-uploader .el-upload:hover {
/* // border-color: var(--el-color-primary); */ /* // border-color: var(--el-color-primary); */
} }
.el-icon.avatar-uploader-icon { .el-icon.avatar-uploader-icon {
font-size: 28px; font-size: 28px;
color: #8c939d; color: #8c939d;
width: 178px; width: 178px;
height: 178px; height: 178px;
text-align: center; text-align: center;
} }
$color-primary: #007aff; $color-primary: #007aff;
@import "./body.scss"; @import "./body.scss";
@import "./common.scss"; @import "./common.scss";
@import "./layout.scss"; @import "./layout.scss";
\ No newline at end of file
// 设置全局布局样式文件 // 设置全局布局样式文件
@mixin appBaseBox { @mixin appBaseBox {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
} }
// 父盒子高度 // 父盒子高度
.set-common-head-fixed-container{ .set-common-head-fixed-container{
height:90px;// 预留菜单总高度,后期可能修改 height:90px;// 预留菜单总高度,后期可能修改
} }
// 顶部菜单盒子 // 顶部菜单盒子
.common-head-fixed-container{ .common-head-fixed-container{
position: fixed; position: fixed;
top: 0px; top: 0px;
left: 0px; left: 0px;
width: 100%; width: 100%;
z-index: 9; z-index: 9;
} }
.show-mobile{ .show-mobile{
padding: 0 5px; padding: 0 5px;
background-color: #2c3e50; background-color: #2c3e50;
.same-cell{ .same-cell{
color: #fff; color: #fff;
} }
} }
// 头部菜单做媒体查询,适应所有屏幕大小,自定义宽度和样式变化 // 头部菜单做媒体查询,适应所有屏幕大小,自定义宽度和样式变化
// 1、超小屏幕下,小于768px 布局容器的宽度为100% // 1、超小屏幕下,小于768px 布局容器的宽度为100%
@media screen and (max-width:767px){ @media screen and (max-width:767px){
.show-pc{ .show-pc{
display: none; display: none;
} }
.show-mobile{ .show-mobile{
display: block; display: block;
@include appBaseBox(); @include appBaseBox();
// background-color: red; // background-color: red;
} }
} }
// 2、小屏幕下,大于等于768px 布局容器改为750px // 2、小屏幕下,大于等于768px 布局容器改为750px
@media screen and (min-width: 750px){ @media screen and (min-width: 750px){
.show-pc{ .show-pc{
display: none; display: none;
} }
.show-mobile{ .show-mobile{
display: block; display: block;
@include appBaseBox(); @include appBaseBox();
// background-color: red; // background-color: red;
} }
} }
// 3、中等屏幕下, 大于等于992px 布局容器改为970 // 3、中等屏幕下, 大于等于992px 布局容器改为970
@media screen and (min-width:992px){ @media screen and (min-width:992px){
.show-pc{ .show-pc{
display: block; display: block;
// background-color: orange; // background-color: orange;
} }
.show-mobile{ .show-mobile{
display: none; display: none;
} }
} }
// 4、大屏幕下,大于等于1200px, 布局容器改为1170px // 4、大屏幕下,大于等于1200px, 布局容器改为1170px
@media screen and (min-width: 1200px){ @media screen and (min-width: 1200px){
.show-pc{ .show-pc{
display: block; display: block;
// background-color: yellow; // background-color: yellow;
} }
.show-mobile{ .show-mobile{
display: none; display: none;
} }
} }
\ No newline at end of file
// Generated by 'unplugin-auto-import' // Generated by 'unplugin-auto-import'
// We suggest you to commit this file into source control // We suggest you to commit this file into source control
declare global { declare global {
const computed: typeof import('vue')['computed'] const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp'] const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef'] const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent'] const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope'] const effectScope: typeof import('vue')['effectScope']
const EffectScope: typeof import('vue')['EffectScope'] const EffectScope: typeof import('vue')['EffectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance'] const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope'] const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h'] const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject'] const inject: typeof import('vue')['inject']
const isReadonly: typeof import('vue')['isReadonly'] const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef'] const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw'] const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick'] const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated'] const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount'] const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated'] const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured'] const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted'] const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked'] const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered'] const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose'] const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch'] const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted'] const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated'] const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide'] const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive'] const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly'] const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref'] const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent'] const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive'] const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly'] const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef'] const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw'] const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef'] const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs'] const toRefs: typeof import('vue')['toRefs']
const triggerRef: typeof import('vue')['triggerRef'] const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref'] const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs'] const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule'] const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars'] const useCssVars: typeof import('vue')['useCssVars']
const useSlots: typeof import('vue')['useSlots'] const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch'] const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect'] const watchEffect: typeof import('vue')['watchEffect']
} }
export {} export {}
// generated by unplugin-vue-components // generated by unplugin-vue-components
// We suggest you to commit this file into source control // We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/vue-next/pull/3399 // Read more: https://github.com/vuejs/vue-next/pull/3399
import '@vue/runtime-core' import '@vue/runtime-core'
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
ElAside: typeof import('element-plus/es')['ElAside'] ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar'] ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard'] ElCard: typeof import('element-plus/es')['ElCard']
ElCol: typeof import('element-plus/es')['ElCol'] ElCol: typeof import('element-plus/es')['ElCol']
ElContainer: typeof import('element-plus/es')['ElContainer'] ElContainer: typeof import('element-plus/es')['ElContainer']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog'] ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider'] ElDivider: typeof import('element-plus/es')['ElDivider']
ElDrawer: typeof import('element-plus/es')['ElDrawer'] ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty'] ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm'] ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader'] ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon'] ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElMain: typeof import('element-plus/es')['ElMain'] ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption'] ElOption: typeof import('element-plus/es')['ElOption']
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm'] ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: typeof import('element-plus/es')['ElPagination']
ElRadio: typeof import('element-plus/es')['ElRadio'] ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow'] ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect'] ElSelect: typeof import('element-plus/es')['ElSelect']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElTable: typeof import('element-plus/es')['ElTable'] ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTree: typeof import('element-plus/es')['ElTree'] ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload'] ElUpload: typeof import('element-plus/es')['ElUpload']
Form: typeof import('./components/Form.vue')['default'] Form: typeof import('./components/Form.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
} }
} }
export {} export {}
<template> <template>
<svg aria-hidden="true" class="svg-icon"> <svg aria-hidden="true" class="svg-icon">
<use :xlink:href="symbolId" :fill="color" /> <use :xlink:href="symbolId" :fill="color" />
</svg> </svg>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'; import { computed } from 'vue';
const props = defineProps({ const props = defineProps({
prefix: { prefix: {
type: String, type: String,
default: 'icon', default: 'icon',
}, },
iconClass: { iconClass: {
type: String, type: String,
required: false required: false
}, },
color: { color: {
type: String, type: String,
default: '' default: ''
} }
}) })
const symbolId = computed(() => `#${props.prefix}-${props.iconClass}`); const symbolId = computed(() => `#${props.prefix}-${props.iconClass}`);
</script> </script>
<style scoped> <style scoped>
.svg-icon { .svg-icon {
width: 1em; width: 1em;
height: 1em; height: 1em;
vertical-align: -0.15em; vertical-align: -0.15em;
overflow: hidden; overflow: hidden;
fill: currentColor; fill: currentColor;
} }
</style> </style>
\ No newline at end of file
<!-- 此处注意,使用 v-model="visible"绑定的形式 <!-- 此处注意,使用 v-model="visible"绑定的形式
上线会报错 上线会报错
修改为如下方式 修改为如下方式
:model-value="visible" :model-value="visible"
--> -->
<template> <template>
<el-dialog <el-dialog
:title='title' :title='title'
:model-value="visible" :model-value="visible"
:before-close="onClose" :before-close="onClose"
append-to-body append-to-body
:width="width + 'px'" :width="width + 'px'"
> >
<div class="container" :style="{height:height + 'px'}"> <div class="container" :style="{height:height + 'px'}">
<slot name="content"></slot> <slot name="content"></slot>
</div> </div>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button type='danger' @click="onClose">取消</el-button> <el-button type='danger' @click="onClose">取消</el-button>
<el-button type="primary" @click="onConfirm">确定</el-button> <el-button type="primary" @click="onConfirm">确定</el-button>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
const props = defineProps({ const props = defineProps({
title: {//弹框标题 title: {//弹框标题
type: String, type: String,
default: '标题' default: '标题'
}, },
visible: { //控制弹框的展示和影藏 visible: { //控制弹框的展示和影藏
type: Boolean, type: Boolean,
default: false default: false
}, },
width: { width: {
type: Number, type: Number,
default: 600 default: 600
}, },
height: { height: {
type: Number, type: Number,
default: 250 default: 250
} }
}) })
const emit = defineEmits(['onClose','onConfirm']) const emit = defineEmits(['onClose','onConfirm'])
//定义弹框的关闭 //定义弹框的关闭
const onClose = () =>{ const onClose = () =>{
emit('onClose') emit('onClose')
} }
//定义弹框的确定 //定义弹框的确定
const onConfirm = () =>{ const onConfirm = () =>{
emit('onConfirm') emit('onConfirm')
} }
</script> </script>
<style lang="scss" scope> <style lang="scss" scope>
.container { .container {
overflow-x: initial; overflow-x: initial;
overflow-y: auto; overflow-y: auto;
} }
.el-dialog { .el-dialog {
border-top-left-radius: 7px !important; border-top-left-radius: 7px !important;
border-top-right-radius: 7px !important; border-top-right-radius: 7px !important;
.el-dialog__header { .el-dialog__header {
border-top-left-radius: 7px !important; border-top-left-radius: 7px !important;
border-top-right-radius: 7px !important; border-top-right-radius: 7px !important;
background-color: #1890ff !important; background-color: #1890ff !important;
.el-dialog__title { .el-dialog__title {
color: #fff; color: #fff;
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
} }
.el-dialog__close { .el-dialog__close {
color: #fff; color: #fff;
} }
} }
.el-dialog__body { .el-dialog__body {
padding: 10px; padding: 10px;
} }
.el-dialog__footer { .el-dialog__footer {
border-top: 1px solid #e8eaec !important; border-top: 1px solid #e8eaec !important;
padding: 10px; padding: 10px;
} }
} }
</style> </style>
\ No newline at end of file
<!-- 下拉选择筛选 --> <!-- 下拉选择筛选 -->
<template> <template>
<el-dropdown ref="dropdown" :hide-on-click="false" trigger="contextmenu"> <el-dropdown ref="dropdown" :hide-on-click="false" trigger="contextmenu">
<span class="el-dropdown-link" @click="dropData.show"> <span class="el-dropdown-link" @click="dropData.show">
{{title}}<el-icon class="el-icon--right"><arrow-down /></el-icon> {{title}}<el-icon class="el-icon--right"><arrow-down /></el-icon>
</span> </span>
<template #dropdown> <template #dropdown>
<div class="space-between" style="width: 120px; padding: 10px 20px"> <div class="space-between" style="width: 120px; padding: 10px 20px">
<el-checkbox <el-checkbox
v-model="dropData.checkAll" v-model="dropData.checkAll"
:indeterminate="dropData.isIndeterminate" :indeterminate="dropData.isIndeterminate"
@change="dropData.handleCheckAllChange" @change="dropData.handleCheckAllChange"
>全选</el-checkbox >全选</el-checkbox
> >
<el-button type="primary" size="small" @click="dropData.confirm">确定</el-button> <el-button type="primary" size="small" @click="dropData.confirm">确定</el-button>
</div> </div>
<div style="height: 400px;width: 160px; overflow: auto"> <div style="height: 400px;width: 160px; overflow: auto">
<el-checkbox-group <el-checkbox-group
v-model="dropData.checkedList" v-model="dropData.checkedList"
@change="dropData.handleCheckedChange" @change="dropData.handleCheckedChange"
> >
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item v-for="(item, index) in list" :key="index"> <el-dropdown-item v-for="(item, index) in list" :key="index">
<el-checkbox :label="item"> <el-checkbox :label="item">
<div class="over1"> <div class="over1">
{{item[prop]}} {{item[prop]}}
</div> </div>
</el-checkbox> </el-checkbox>
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</template> </template>
</el-dropdown> </el-dropdown>
</template> </template>
<script lang="ts"> <script lang="ts">
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
export default { export default {
name: 'DropDownCheck', name: 'DropDownCheck',
props: { props: {
modValue: { modValue: {
type: Array, type: Array,
default: null, default: null,
required: true required: true
}, },
title: { title: {
type: String, type: String,
default: '' default: ''
}, },
list: { list: {
type: Array, type: Array,
default: null default: null
}, },
prop: { prop: {
type: String, type: String,
default: '' default: ''
} }
}, },
setup(props, context) { setup(props, context) {
const dropdown = ref() const dropdown = ref()
const dropData = reactive({ const dropData = reactive({
checkAll: false, checkAll: false,
isIndeterminate: true, isIndeterminate: true,
checkedList: props.modValue, checkedList: props.modValue,
handleCheckAllChange: (val: boolean) => { handleCheckAllChange: (val: boolean) => {
dropData.checkedList = val ? props.list : [] dropData.checkedList = val ? props.list : []
dropData.isIndeterminate = false dropData.isIndeterminate = false
context.emit('update:modValue', dropData.checkedList) context.emit('update:modValue', dropData.checkedList)
}, },
handleCheckedChange: (value: string[]) => { handleCheckedChange: (value: string[]) => {
const checkedCount = value.length const checkedCount = value.length
dropData.checkAll = checkedCount === props.list.length dropData.checkAll = checkedCount === props.list.length
dropData.isIndeterminate = checkedCount > 0 && checkedCount < props.list.length dropData.isIndeterminate = checkedCount > 0 && checkedCount < props.list.length
context.emit('update:modValue', dropData.checkedList) context.emit('update:modValue', dropData.checkedList)
}, },
show: () => { show: () => {
dropdown.value.handleOpen() dropdown.value.handleOpen()
}, },
confirm: () => { confirm: () => {
dropdown.value.handleClose() dropdown.value.handleClose()
context.emit('onConfirm', props.title) context.emit('onConfirm', props.title)
} }
}) })
return { return {
dropData, dropData,
dropdown dropdown
} }
} }
} }
</script> </script>
<style> <style>
</style> </style>
<template> <template>
<div> <div>
<div ref="commonEchartRef" :style="{ height: height, width: width }"></div> <div ref="commonEchartRef" :style="{ height: height, width: width }"></div>
</div> </div>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
import { ref, onMounted, watchEffect } from 'vue' import { ref, onMounted, watchEffect } from 'vue'
import useEcharts from '@/hooks/useEcharts'; import useEcharts from '@/hooks/useEcharts';
//接收父组件传递的参数 //接收父组件传递的参数
//withDefaults:设置默认值 //withDefaults:设置默认值
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
width?: string, width?: string,
height: string, height: string,
optios: any optios: any
}>(), { }>(), {
width: '100%', width: '100%',
height: '360px' height: '360px'
}) })
//定义ref属性 //定义ref属性
const commonEchartRef = ref<HTMLElement>() const commonEchartRef = ref<HTMLElement>()
onMounted(() => { onMounted(() => {
//叹号:断定commonEchartRef.value存在 //叹号:断定commonEchartRef.value存在
const { setOptions, resize } = useEcharts(commonEchartRef.value!) const { setOptions, resize } = useEcharts(commonEchartRef.value!)
watchEffect(() => { watchEffect(() => {
setOptions(props.optios) setOptions(props.optios)
}) })
//自适应 //自适应
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
resize(); resize();
}) })
}) })
</script> </script>
<style scoped lang='scss'> <style scoped lang='scss'>
</style> </style>
\ No newline at end of file
<template> <template>
<el-form> <el-form>
<el-form-item></el-form-item> <el-form-item></el-form-item>
</el-form> </el-form>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
</script> </script>
<style scoped></style> <style scoped></style>
\ No newline at end of file
<template> <template>
<el-dialog v-model="htmlData.htmlVisible" :title="htmlData.title"> <el-dialog v-model="htmlData.htmlVisible" :title="htmlData.title">
<div v-html="htmlData.details" /> <div v-html="htmlData.details" />
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
let props = defineProps({ let props = defineProps({
htmlData: { htmlData: {
type: Object, type: Object,
default: { default: {
htmlVisible: { htmlVisible: {
type: Boolean, type: Boolean,
default: false default: false
}, },
title: { title: {
type: String, type: String,
default: '' default: ''
}, },
details: { details: {
type: String, type: String,
default: '<p></p>' default: '<p></p>'
} }
} }
} }
}) })
</script> </script>
\ No newline at end of file
<template> <template>
<el-table :data="tableData" style="width: 100%" height="400px"> <el-table :data="tableData" style="width: 100%" height="400px">
<el-table-column <el-table-column
v-for="(item, index) in tableTitle" v-for="(item, index) in tableTitle"
:key="index" :key="index"
:label="item.lable" :label="item.lable"
> >
<template #default="scope"> <template #default="scope">
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<el-input v-model="scope.row[item.prop]" placeholder="Please input" /> <el-input v-model="scope.row[item.prop]" placeholder="Please input" />
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="180px" align="center" fixed="right"> <el-table-column label="操作" width="180px" align="center" fixed="right">
<template #default="scope"> <template #default="scope">
<div style="display: flex; align-items: center; justify-content: center"> <div style="display: flex; align-items: center; justify-content: center">
<slot v-bind="scope"></slot> <slot v-bind="scope"></slot>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div class="flex-center-h" style="margin-top: 10px"> <div class="flex-center-h" style="margin-top: 10px">
<el-input v-model="addInput" placeholder="输入名称" style="width: 300px"> <el-input v-model="addInput" placeholder="输入名称" style="width: 300px">
<template #prepend> <template #prepend>
<el-icon><Plus /></el-icon> <el-icon><Plus /></el-icon>
</template> </template>
</el-input> </el-input>
<el-button type="primary" style="margin-left: 10px" @click="add">新增</el-button> <el-button type="primary" style="margin-left: 10px" @click="add">新增</el-button>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
export default { export default {
name: 'InputTable', name: 'InputTable',
props: { props: {
tableTitle: { tableTitle: {
type: Array, type: Array,
default: null default: null
}, },
tableData: { tableData: {
type: Array, type: Array,
default: null default: null
} }
}, },
emits: ['onAdd'], emits: ['onAdd'],
setup(props, context) { setup(props, context) {
const addInput = ref('') const addInput = ref('')
const add = ref( async () => { const add = ref( async () => {
await context.emit('onAdd', addInput.value) await context.emit('onAdd', addInput.value)
addInput.value = '' addInput.value = ''
}) })
return { return {
add, add,
addInput addInput
} }
} }
} }
</script> </script>
<template> <template>
<div style="margin-top: 20px;"> <div style="margin-top: 20px;">
<el-pagination v-model:currentPage="pageData.pageNo" v-model:page-size="pageData.pageSize" <el-pagination v-model:currentPage="pageData.pageNo" v-model:page-size="pageData.pageSize"
:page-sizes="[10, 15, 20]" :small="pageData.small" :disabled="pageData.disabled" :page-sizes="[10, 15, 20]" :small="pageData.small" :disabled="pageData.disabled"
:background="pageData.background" layout="->, total, sizes, prev, pager, next, jumper" :total="total" :background="pageData.background" layout="->, total, sizes, prev, pager, next, jumper" :total="total"
:hide-on-single-page="pageData.hide" @size-change="handleSizeChange" :hide-on-single-page="pageData.hide" @size-change="handleSizeChange"
@current-change="handleCurrentChange" /> @current-change="handleCurrentChange" />
</div> </div>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
let props = defineProps({ let props = defineProps({
pageData: { pageData: {
type: Object, type: Object,
default: { default: {
pageNo: { pageNo: {
type: Number, type: Number,
default: 1 default: 1
}, },
pageSize: { pageSize: {
type: Number, type: Number,
default: 10 default: 10
}, },
small: { small: {
type: Boolean, type: Boolean,
default: false default: false
}, },
disabled: { disabled: {
type: Boolean, type: Boolean,
default: false default: false
}, },
background: { background: {
type: String || Boolean, type: String || Boolean,
default: '' || false default: '' || false
}, },
hide: { hide: {
type: Boolean, type: Boolean,
default: false default: false
} }
} }
}, },
total: { total: {
type: Number, type: Number,
default: 0 default: 0
} }
}) })
let emits = defineEmits(['sizeChange', 'currentChange']) let emits = defineEmits(['sizeChange', 'currentChange'])
// 新条数 // 新条数
const handleSizeChange = (val: number) => { const handleSizeChange = (val: number) => {
emits('sizeChange', val) emits('sizeChange', val)
} }
// // 新页数 // // 新页数
const handleCurrentChange = (val: number) => { const handleCurrentChange = (val: number) => {
emits('currentChange', val) emits('currentChange', val)
} }
</script> </script>
<style lang = "scss" scoped> <style lang = "scss" scoped>
</style> </style>
\ No newline at end of file
<template> <template>
<div style="margin-top: 20px;"> <div style="margin-top: 20px;">
<el-pagination v-model:currentPage="pageData.page" v-model:page-size="pageData.limit" <el-pagination v-model:currentPage="pageData.page" v-model:page-size="pageData.limit"
:page-sizes="[10, 15, 20]" :small="pageData.small" :disabled="pageData.disabled" :page-sizes="[10, 15, 20]" :small="pageData.small" :disabled="pageData.disabled"
:background="pageData.background" layout="->, total, sizes, prev, pager, next, jumper" :total="total" :background="pageData.background" layout="->, total, sizes, prev, pager, next, jumper" :total="total"
:hide-on-single-page="pageData.hide" @size-change="handleSizeChange" :hide-on-single-page="pageData.hide" @size-change="handleSizeChange"
@current-change="handleCurrentChange" /> @current-change="handleCurrentChange" />
</div> </div>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
let props = defineProps({ let props = defineProps({
pageData: { pageData: {
type: Object, type: Object,
default: { default: {
page: { page: {
type: Number, type: Number,
default: 1 default: 1
}, },
limit: { limit: {
type: Number, type: Number,
default: 10 default: 10
}, },
small: { small: {
type: Boolean, type: Boolean,
default: false default: false
}, },
disabled: { disabled: {
type: Boolean, type: Boolean,
default: false default: false
}, },
background: { background: {
type: String || Boolean, type: String || Boolean,
default: '' || false default: '' || false
}, },
hide: { hide: {
type: Boolean, type: Boolean,
default: false default: false
} }
} }
}, },
total: { total: {
type: Number, type: Number,
default: 0 default: 0
} }
}) })
let emits = defineEmits(['sizeChange', 'currentChange']) let emits = defineEmits(['sizeChange', 'currentChange'])
// 新条数 // 新条数
const handleSizeChange = (val: number) => { const handleSizeChange = (val: number) => {
emits('sizeChange', val) emits('sizeChange', val)
} }
// // 新页数 // // 新页数
const handleCurrentChange = (val: number) => { const handleCurrentChange = (val: number) => {
emits('currentChange', val) emits('currentChange', val)
} }
</script> </script>
<style lang = "scss" scoped> <style lang = "scss" scoped>
</style> </style>
\ No newline at end of file
<template> <template>
<div style="border: 1px solid #ccc"> <div style="border: 1px solid #ccc">
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" /> <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
<Editor style="height: 400px; overflow-y: hidden;" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode" <Editor style="height: 400px; overflow-y: hidden;" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode"
@onCreated="handleCreated" @onChange="handleChange" /> @onCreated="handleCreated" @onChange="handleChange" />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import '@wangeditor/editor/dist/css/style.css' // 引入 css import '@wangeditor/editor/dist/css/style.css' // 引入 css
import { onBeforeUnmount, shallowRef, computed } from 'vue' import { onBeforeUnmount, shallowRef, computed } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue' import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { createStorage } from "@/services/api/storage"; import { createStorage } from "@/services/api/storage";
type InsertFnType = (url: string, alt?: string, href?: string) => void type InsertFnType = (url: string, alt?: string, href?: string) => void
type InsertFnTypeVideo = (url: string, poster?: string) => void type InsertFnTypeVideo = (url: string, poster?: string) => void
const props = defineProps({ const props = defineProps({
valueHtml: { valueHtml: {
type: String, type: String,
default: '' default: ''
} }
}) })
const valueHtml = computed({ const valueHtml = computed({
get: () => props.valueHtml, get: () => props.valueHtml,
set: (value) => emits("htmlChange", value), set: (value) => emits("htmlChange", value),
}) })
const mode = shallowRef('mode') const mode = shallowRef('mode')
const emits = defineEmits(['htmlChange']) const emits = defineEmits(['htmlChange'])
// 编辑器实例,必须用 shallowRef // 编辑器实例,必须用 shallowRef
const editorRef = shallowRef() const editorRef = shallowRef()
const toolbarConfig = {} const toolbarConfig = {}
const editorConfig: any = { placeholder: '请输入内容...', MENU_CONF: {} } const editorConfig: any = { placeholder: '请输入内容...', MENU_CONF: {} }
// 自定义上传图片 // 自定义上传图片
editorConfig.MENU_CONF['uploadImage'] = { editorConfig.MENU_CONF['uploadImage'] = {
customUpload(file: File, insertFn: InsertFnTypeVideo) { customUpload(file: File, insertFn: InsertFnTypeVideo) {
console.log(file); console.log(file);
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
createStorage(formData).then((res: any) => { createStorage(formData).then((res: any) => {
if (res.code === 200) { if (res.code === 200) {
insertFn(res.data.url) insertFn(res.data.url)
} }
}) })
}, },
} }
// // 插入图片 // // 插入图片
// editorConfig.MENU_CONF['insertImage'] = { // editorConfig.MENU_CONF['insertImage'] = {
// onInsertedImage(imageNode: ImageElement | null) { // TS 语法 // onInsertedImage(imageNode: ImageElement | null) { // TS 语法
// if (imageNode == null) return // if (imageNode == null) return
// const { src, alt, url, href } = imageNode // const { src, alt, url, href } = imageNode
// console.log('inserted image', src, alt, url, href) // console.log('inserted image', src, alt, url, href)
// }, // },
// checkImage: customCheckImageFn, // 也支持 async 函数 // checkImage: customCheckImageFn, // 也支持 async 函数
// parseImageSrc: customParseImageSrc, // 也支持 async 函数 // parseImageSrc: customParseImageSrc, // 也支持 async 函数
// } // }
// 自定义上传视频 // 自定义上传视频
editorConfig.MENU_CONF['uploadVideo'] = { editorConfig.MENU_CONF['uploadVideo'] = {
customUpload(file: File, insertFn: InsertFnType) { customUpload(file: File, insertFn: InsertFnType) {
console.log(file); console.log(file);
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
createStorage(formData).then((res: any) => { createStorage(formData).then((res: any) => {
if (res.code === 200) { if (res.code === 200) {
insertFn(res.data.url) insertFn(res.data.url)
} }
}) })
}, },
} }
// 组件销毁时,也及时销毁编辑器 // 组件销毁时,也及时销毁编辑器
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: any) => { const handleCreated = (editor: any) => {
editorRef.value = editor // 记录 editor 实例,重要! editorRef.value = editor // 记录 editor 实例,重要!
} }
const handleChange = (editor: any) => { const handleChange = (editor: any) => {
const html = editor.getHtml() const html = editor.getHtml()
emits('htmlChange', html) emits('htmlChange', html)
} }
</script> </script>
\ No newline at end of file
//自定义按钮权限指令 //自定义按钮权限指令
import { Directive } from 'vue' import { Directive } from 'vue'
import { store } from '@/store/index'; import { store } from '@/store/index';
export const permission: Directive = { export const permission: Directive = {
mounted(el, binding) { mounted(el, binding) {
//value按钮上的权限 //value按钮上的权限
const { value } = binding; const { value } = binding;
//获取用户所有的权限 //获取用户所有的权限
const permissions = store.getters['user/getPermissions']; const permissions = store.getters['user/getPermissions'];
console.log('所有的权限') console.log('所有的权限')
console.log(permissions) console.log(permissions)
//判断传递进来的按钮权限,是否存在 //判断传递进来的按钮权限,是否存在
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const permissionRoles = value; const permissionRoles = value;
//判断传递进来的按钮权限字段,是否存在当前用户的permissions //判断传递进来的按钮权限字段,是否存在当前用户的permissions
const hasPermission = permissions.some((role) => { const hasPermission = permissions.some((role) => {
return permissionRoles.includes(role) return permissionRoles.includes(role)
}) })
if (!hasPermission) { //没有权限时,影藏 if (!hasPermission) { //没有权限时,影藏
el.style.display = 'none' el.style.display = 'none'
} }
} else { } else {
throw new Error('当前没有权限!') throw new Error('当前没有权限!')
} }
} }
} }
\ No newline at end of file
/** /**
*请求结果定义 *请求结果定义
* *
* @enum {number} * @enum {number}
*/ */
enum ResultEnum { enum ResultEnum {
SUCCESS = 0, SUCCESS = 0,
ERROR = 1, ERROR = 1,
TIMEOUT = 401, TIMEOUT = 401,
TYPE = 'success', TYPE = 'success',
} }
/** /**
*请求类型 *请求类型
* *
* @enum {number} * @enum {number}
*/ */
enum RequestEnum { enum RequestEnum {
GET = 'GET', GET = 'GET',
POST = 'POST', POST = 'POST',
PUT = 'PUT', PUT = 'PUT',
DELETE = 'DELETE', DELETE = 'DELETE',
} }
/** /**
*请求类型 *请求类型
* *
* @enum {number} * @enum {number}
*/ */
enum ContentTypeEnum { enum ContentTypeEnum {
// json // json
JSON = 'application/json;charset=UTF-8', JSON = 'application/json;charset=UTF-8',
// form-data qs // form-data qs
FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8', FORM_URLENCODED = 'application/x-www-form-urlencoded;charset=UTF-8',
// form-data upload // form-data upload
FORM_DATA = 'multipart/form-data;charset=UTF-8', FORM_DATA = 'multipart/form-data;charset=UTF-8',
} }
/** /**
*请求配置 *请求配置
* *
* @enum {number} * @enum {number}
*/ */
enum ConfigEnum { enum ConfigEnum {
// TOKEN // TOKEN
TOKEN = 'X-Access-Token', TOKEN = 'X-Access-Token',
} }
export { RequestEnum, ResultEnum, ContentTypeEnum, ConfigEnum } export { RequestEnum, ResultEnum, ContentTypeEnum, ConfigEnum }
\ No newline at end of file
import * as httpEnum from '@/enums/httpEnum' import * as httpEnum from '@/enums/httpEnum'
import * as roleEnum from '@/enums/roleEnum' import * as roleEnum from '@/enums/roleEnum'
export {httpEnum,roleEnum} export {httpEnum,roleEnum}
\ No newline at end of file
export enum RoleEnum { export enum RoleEnum {
// super admin // super admin
SUPER = 'super', SUPER = 'super',
// tester // tester
TEST = 'test', TEST = 'test',
} }
\ No newline at end of file
/// <reference types="vite/client" /> /// <reference types="vite/client" />
declare module '*.vue' { declare module '*.vue' {
import { DefineComponent } from 'vue' import { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any> const component: DefineComponent<{}, {}, any>
export default component export default component
} }
// 环境变量智能提示配置 // 环境变量智能提示配置
interface ImportMetaEnv { interface ImportMetaEnv {
VITE_APP_TITLE: string, VITE_APP_TITLE: string,
VITE_APP_PORT: string, VITE_APP_PORT: string,
VITE_APP_BASE_URL: string VITE_APP_BASE_URL: string
} }
// 申明进度条依赖模块 // 申明进度条依赖模块
declare module 'nprogress'; declare module 'nprogress';
\ No newline at end of file
import CustomTable from '@/table/index.vue' import CustomTable from '@/table/index.vue'
import CustomFormItem from '@/table/components/edit.vue' import CustomFormItem from '@/table/components/edit.vue'
import CustomInputTable from '@/components/inputTable/index.vue' import CustomInputTable from '@/components/inputTable/index.vue'
import { App } from 'vue' import { App } from 'vue'
const components: any = { const components: any = {
CustomTable, CustomTable,
CustomFormItem, CustomFormItem,
CustomInputTable CustomInputTable
} }
const GlobalComponents = (app: App) => { const GlobalComponents = (app: App) => {
Object.keys(components).forEach((key) => { Object.keys(components).forEach((key) => {
app.component(`${key}`, components[key]) app.component(`${key}`, components[key])
}) })
} }
export default GlobalComponents export default GlobalComponents
import {reactive} from 'vue' import {reactive} from 'vue'
import { DialogModel } from "@/type/BastType"; import { DialogModel } from "@/type/BastType";
export default function useDialog(){ export default function useDialog(){
//定义弹框属性 //定义弹框属性
const dialog = reactive<DialogModel>({ const dialog = reactive<DialogModel>({
title:'', title:'',
visible:false, visible:false,
width:630, width:630,
height:280 height:280
}) })
//展示 //展示
const onShow = () =>{ const onShow = () =>{
dialog.visible = true; dialog.visible = true;
} }
//关闭 //关闭
const onClose = () =>{ const onClose = () =>{
dialog.visible =false; dialog.visible =false;
} }
//确定 //确定
const onConfirm = () =>{ const onConfirm = () =>{
dialog.visible = false; dialog.visible = false;
} }
return { return {
dialog, dialog,
onShow, onShow,
onClose, onClose,
onConfirm onConfirm
} }
} }
\ No newline at end of file
import * as echarts from 'echarts' import * as echarts from 'echarts'
export default function useEcharts(el:HTMLElement){ export default function useEcharts(el:HTMLElement){
//初始化echarts //初始化echarts
const echartsInstance = echarts.init(el); const echartsInstance = echarts.init(el);
//设置options //设置options
const setOptions = (options:any) =>{ const setOptions = (options:any) =>{
echartsInstance.setOption(options) echartsInstance.setOption(options)
} }
//自适应监听 //自适应监听
const resize = () =>{ const resize = () =>{
echartsInstance.resize() echartsInstance.resize()
} }
return{ return{
setOptions, setOptions,
resize resize
} }
} }
\ No newline at end of file
import { getCurrentInstance, ComponentInternalInstance } from "vue-demi"; import { getCurrentInstance, ComponentInternalInstance } from "vue-demi";
export default function useInstance() { export default function useInstance() {
// 获取当前组件实例,proxy生产和开发环境可以用,开发环境下可以使用ctx,生产环境不允许ctx,会引起获取不到实例 // 获取当前组件实例,proxy生产和开发环境可以用,开发环境下可以使用ctx,生产环境不允许ctx,会引起获取不到实例
const { appContext, proxy } = getCurrentInstance() as ComponentInternalInstance const { appContext, proxy } = getCurrentInstance() as ComponentInternalInstance
const global = appContext.config.globalProperties; const global = appContext.config.globalProperties;
return { return {
proxy, proxy,
global global
} }
} }
\ No newline at end of file
export default { export default {
// 路由国际化 // 路由国际化
route: { route: {
dashboard: 'Dashboard', dashboard: 'Dashboard',
}, },
// 登录页面国际化 // 登录页面国际化
login: { login: {
title: 'starbos-system', title: 'starbos-system',
username: 'Username', username: 'Username',
password: 'Password' password: 'Password'
}, },
} }
\ No newline at end of file
// 自定义国际化配置 // 自定义国际化配置
import { createI18n } from 'vue-i18n' import { createI18n } from 'vue-i18n'
import { cacheStorage } from '@/utils/cacheStorage' import { cacheStorage } from '@/utils/cacheStorage'
// 本地语言包 // 本地语言包
import enLocale from './en' import enLocale from './en'
import zhCnLocale from './zh-cn' import zhCnLocale from './zh-cn'
const messages = { const messages = {
'zh-cn': { 'zh-cn': {
...zhCnLocale ...zhCnLocale
}, },
en: { en: {
...enLocale ...enLocale
} }
} }
/** /**
* 获取当前系统使用语言字符串 * 获取当前系统使用语言字符串
* *
* @returns zh-cn|en ... * @returns zh-cn|en ...
*/ */
export const getLanguage = () => { export const getLanguage = () => {
// 本地缓存获取 // 本地缓存获取
let language = cacheStorage.getLocalStorage('language') let language = cacheStorage.getLocalStorage('language')
if (language) { if (language) {
return language return language
} }
// 浏览器使用语言 // 浏览器使用语言
language = navigator.language.toLowerCase() language = navigator.language.toLowerCase()
const locales = Object.keys(messages) const locales = Object.keys(messages)
for (const locale of locales) { for (const locale of locales) {
if (language.indexOf(locale) > -1) { if (language.indexOf(locale) > -1) {
return locale return locale
} }
} }
return 'zh-cn' return 'zh-cn'
} }
const i18n = createI18n({ const i18n = createI18n({
locale: getLanguage(), locale: getLanguage(),
messages: messages messages: messages
}) })
export default i18n export default i18n
\ No newline at end of file
export default { export default {
// 路由国际化 // 路由国际化
route: { route: {
dashboard: '首页', dashboard: '首页',
}, },
// 登录页面国际化 // 登录页面国际化
login: { login: {
title: '永信达商城系统', title: '永信达商城系统',
username: '账号', username: '账号',
password: '密码' password: '密码'
} }
} }
\ No newline at end of file
<template> <template>
<Menu></Menu> <Menu></Menu>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Menu from '@/components/Menu.vue' import Menu from '@/components/Menu.vue'
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>
\ No newline at end of file
<template> <template>
<div> <div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
export default { export default {
setup () { setup () {
return {} return {}
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>
\ No newline at end of file
<template> <template>
<el-breadcrumb separator="/"> <el-breadcrumb separator="/">
<el-breadcrumb-item v-for="item in tabs">{{ item.meta.title }}</el-breadcrumb-item> <el-breadcrumb-item v-for="item in tabs">{{ item.meta.title }}</el-breadcrumb-item>
</el-breadcrumb> </el-breadcrumb>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
import { ref, watch, Ref } from 'vue' import { ref, watch, Ref } from 'vue'
import { useRoute, RouteLocationMatched } from 'vue-router'; import { useRoute, RouteLocationMatched } from 'vue-router';
//定义面包屑导航数据 //定义面包屑导航数据
const tabs: Ref<RouteLocationMatched[]> = ref([]); const tabs: Ref<RouteLocationMatched[]> = ref([]);
const route = useRoute(); const route = useRoute();
const getBredcurm = () => { const getBredcurm = () => {
//获取所有有meta和title //获取所有有meta和title
let mached = route.matched.filter(item => item.meta && item.meta.title); let mached = route.matched.filter(item => item.meta && item.meta.title);
// 判断第一个是否是首页,如果不是,构造一个 // 判断第一个是否是首页,如果不是,构造一个
const first = mached[0]; const first = mached[0];
if(first && first.path !== '/dashboard'){ if(first && first.path !== '/dashboard'){
//构造一个 //构造一个
mached = [{path: '/dashboard',meta:{title:'首页'}} as any].concat(mached); mached = [{path: '/dashboard',meta:{title:'首页'}} as any].concat(mached);
} }
//设置面包屑导航数据 //设置面包屑导航数据
tabs.value = mached; tabs.value = mached;
} }
getBredcurm(); getBredcurm();
//路由发生变化,重新获取面包屑导航数据 //路由发生变化,重新获取面包屑导航数据
watch(() => route.path, () => getBredcurm()); watch(() => route.path, () => getBredcurm());
</script> </script>
<style scoped lang='scss'> <style scoped lang='scss'>
</style> </style>
\ No newline at end of file
<template> <template>
<el-icon @click="changeIcon" class="fa-icons"> <el-icon @click="changeIcon" class="fa-icons">
<component :is="status ? Expand : Fold" /> <component :is="status ? Expand : Fold" />
</el-icon> </el-icon>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
import {computed } from 'vue' import {computed } from 'vue'
import { Fold, Expand } from '@element-plus/icons-vue' import { Fold, Expand } from '@element-plus/icons-vue'
import { useStore } from '@/store/index' import { useStore } from '@/store/index'
const store = useStore() const store = useStore()
const status = computed(()=>{ const status = computed(()=>{
// return store.getters['getCollapse'] // return store.getters['getCollapse']
return store.getters['menu/getCollapse'] return store.getters['menu/getCollapse']
}) })
//图标切换 //图标切换
const changeIcon = ()=>{ const changeIcon = ()=>{
console.log(store) console.log(store)
// store.commit('setCollapse',!status.value) // store.commit('setCollapse',!status.value)
store.commit('menu/setCollapse',!status.value) store.commit('menu/setCollapse',!status.value)
} }
</script> </script>
<style scoped lang='scss'> <style scoped lang='scss'>
.fa-icons { .fa-icons {
display: flex; display: flex;
align-items: center; align-items: center;
font-size: 20px; font-size: 20px;
color: #303133; color: #303133;
cursor: pointer; cursor: pointer;
margin-right: 15px; margin-right: 15px;
} }
</style> </style>
\ No newline at end of file
<template> <template>
<div style='display: flex;align-items: center;'> <div style='display: flex;align-items: center;'>
<Collapse></Collapse> <Collapse></Collapse>
<BredCum></BredCum> <BredCum></BredCum>
</div> </div>
<UserInfo></UserInfo> <UserInfo></UserInfo>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import UserInfo from './UserInfo.vue'; import UserInfo from './UserInfo.vue';
import Collapse from './Collapse.vue'; import Collapse from './Collapse.vue';
import BredCum from './BredCum.vue'; import BredCum from './BredCum.vue';
</script> </script>
\ No newline at end of file
<template> <template>
<el-dropdown placement="bottom-start"> <el-dropdown placement="bottom-start">
<span class="el-dropdown-link"> <span class="el-dropdown-link">
<el-avatar :size="45" fit="contain" :src="avatar" /> <el-avatar :size="45" fit="contain" :src="avatar" />
</span> </span>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<!-- <el-dropdown-item @click="userInfo">个人信息</el-dropdown-item> --> <!-- <el-dropdown-item @click="userInfo">个人信息</el-dropdown-item> -->
<el-dropdown-item @click="loginOut">退出登录</el-dropdown-item> <el-dropdown-item @click="loginOut">退出登录</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
import useInstance from '@/hooks/useInstance'; import useInstance from '@/hooks/useInstance';
import { cleanSession, getToken } from '@/utils/auth'; import { cleanSession, getToken } from '@/utils/auth';
import { store } from '@/store/index' import { store } from '@/store/index'
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
import router from '@/router'; import router from '@/router';
const { global } = useInstance() const { global } = useInstance()
const avatar = store.state.user.userAvatar const avatar = store.state.user.userAvatar
//退出登录 //退出登录
const loginOut = async () => { const loginOut = async () => {
window.location.href = "/#/login"; window.location.href = "/#/login";
cleanSession(); cleanSession();
// let confirm = await global.$myconfirm('确定退出登录吗?') // let confirm = await global.$myconfirm('确定退出登录吗?')
// if (confirm) { // if (confirm) {
// let parm = { // let parm = {
// token: getToken() // token: getToken()
// } // }
// let res = await loginOutApi(parm) // let res = await loginOutApi(parm)
// if (res && res.code == 200) { // if (res && res.code == 200) {
// //跳到登录 // //跳到登录
// window.location.href = "/login"; // window.location.href = "/login";
// //清空session // //清空session
// cleanSession(); // cleanSession();
// } // }
// } // }
} }
//还原数据 //还原数据
// const restore = async () => { // const restore = async () => {
// let confirm = await global.$myconfirm('确定还原数据吗?') // let confirm = await global.$myconfirm('确定还原数据吗?')
// if (confirm) { // if (confirm) {
// let res = await restoreApi(); // let res = await restoreApi();
// if (res && res.code == 200) { // if (res && res.code == 200) {
// //信息提示 // //信息提示
// global.$message({ message: res.message, type: 'success' }) // global.$message({ message: res.message, type: 'success' })
// } // }
// } // }
// } // }
//跳转个人信息 //跳转个人信息
const userInfo = async () => { const userInfo = async () => {
router.push({ path: '/user' }) router.push({ path: '/user' })
} }
</script> </script>
<style scoped lang='scss'> <style scoped lang='scss'>
</style> </style>
\ No newline at end of file
<template> <template>
<el-container class="layout"> <el-container class="layout">
<el-aside width="auto" class="asside"> <el-aside width="auto" class="asside">
<MenuBar></MenuBar> <MenuBar></MenuBar>
</el-aside> </el-aside>
<el-container> <el-container>
<el-header class="header"> <el-header class="header">
<Header></Header> <Header></Header>
</el-header> </el-header>
<el-main class="main"> <el-main class="main">
<Tabs style="padding-top: 10px"></Tabs> <Tabs style="padding-top: 10px"></Tabs>
<keep-alive> <keep-alive>
<router-view></router-view> <router-view></router-view>
</keep-alive> </keep-alive>
</el-main> </el-main>
</el-container> </el-container>
</el-container> </el-container>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Header from '@/layout/header/Header.vue'; import Header from '@/layout/header/Header.vue';
import MenuBar from '@/layout/menu/MenuBar.vue'; import MenuBar from '@/layout/menu/MenuBar.vue';
import Tabs from './tabs/Tabs.vue'; import Tabs from './tabs/Tabs.vue';
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.layout { .layout {
height: 100%; height: 100%;
.asside { .asside {
background-color: #304156; background-color: #304156;
} }
.header { .header {
height: 50px; height: 50px;
border-bottom: 1px solid #e5e5e5; border-bottom: 1px solid #e5e5e5;
// background-color: blueviolet; // background-color: blueviolet;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.main { .main {
padding-top: 0px; padding-top: 0px;
padding-left: 0px !important; padding-left: 0px !important;
padding-right: 0px !important; padding-right: 0px !important;
} }
} }
</style> </style>
\ No newline at end of file
<template> <template>
<MenuLogo class="layout-logo" v-if="!isCollapse"></MenuLogo> <MenuLogo class="layout-logo" v-if="!isCollapse"></MenuLogo>
<el-menu :default-active="activeIdex" class="el-menu-vertical-startbos" :collapse="isCollapse" @open="handleOpen" <el-menu :default-active="activeIdex" class="el-menu-vertical-startbos" :collapse="isCollapse" @open="handleOpen"
@close="handleClose" background-color="#304156" router> @close="handleClose" background-color="#304156" router>
<MenuItem :menuList="menuList"> <MenuItem :menuList="menuList">
</MenuItem> </MenuItem>
</el-menu> </el-menu>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { reactive, computed } from 'vue' import { reactive, computed } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { useStore } from '@/store/index' import { useStore } from '@/store/index'
import MenuItem from './MenuItem.vue' import MenuItem from './MenuItem.vue'
import MenuLogo from '@/layout/menu/MenuLogo.vue' import MenuLogo from '@/layout/menu/MenuLogo.vue'
// setup语法糖中 定义的数据和方法,直接可以在模板中使用,无需要 return // setup语法糖中 定义的数据和方法,直接可以在模板中使用,无需要 return
const store = useStore() const store = useStore()
// store.commit('menu/setCollapse') // store.commit('menu/setCollapse')
// store.dispatch('menu/getMenuList') // store.dispatch('menu/getMenuList')
// store.getters['user/getPermissions'] // store.getters['user/getPermissions']
//当前路由 //当前路由
const route = useRoute(); const route = useRoute();
const activeIdex = computed(() => { const activeIdex = computed(() => {
const { path } = route; const { path } = route;
return path; return path;
}) })
//菜单数据 //菜单数据
const menuList = computed(() => { const menuList = computed(() => {
return store.getters['menu/getMenuList'] return store.getters['menu/getMenuList']
}) })
const isCollapse = computed(() => { const isCollapse = computed(() => {
return store.getters['menu/getCollapse'] return store.getters['menu/getCollapse']
}) })
const handleOpen = (key: string, keyPath: string[]) => { const handleOpen = (key: string, keyPath: string[]) => {
// console.log(key, keyPath) // console.log(key, keyPath)
} }
const handleClose = (key: string, keyPath: string[]) => { const handleClose = (key: string, keyPath: string[]) => {
// console.log(key, keyPath) // console.log(key, keyPath)
} }
</script> </script>
<style scoped> <style scoped>
@keyframes logoAnimation { @keyframes logoAnimation {
0% { 0% {
transform: scale(0); transform: scale(0);
} }
50% { 50% {
transform: scale(1); transform: scale(1);
} }
100% { 100% {
transform: scale(1); transform: scale(1);
} }
} }
.layout-logo { .layout-logo {
animation: logoAnimation 1s ease-out; animation: logoAnimation 1s ease-out;
} }
.el-menu-vertical-startbos:not(.el-menu--collapse) { .el-menu-vertical-startbos:not(.el-menu--collapse) {
width: 230px; width: 230px;
min-height: 400px; min-height: 400px;
} }
.el-menu { .el-menu {
border-right: none; border-right: none;
} }
:deep(.el-sub-menu .el-sub-menu__title) { :deep(.el-sub-menu .el-sub-menu__title) {
color: #f4f4f5 !important; color: #f4f4f5 !important;
} }
:deep(.el-menu .el-menu-item) { :deep(.el-menu .el-menu-item) {
color: #bfcbd9; color: #bfcbd9;
} }
/* 菜单点中文字的颜色 */ /* 菜单点中文字的颜色 */
:deep(.el-menu-item.is-active) { :deep(.el-menu-item.is-active) {
color: #409eff !important; color: #409eff !important;
} }
/* 当前打开菜单的所有子菜单颜色 */ /* 当前打开菜单的所有子菜单颜色 */
:deep(.is-opened .el-menu-item) { :deep(.is-opened .el-menu-item) {
background-color: #1f2d3d !important; background-color: #1f2d3d !important;
} }
/* 鼠标移动菜单的颜色 */ /* 鼠标移动菜单的颜色 */
:deep(.el-menu-item:hover) { :deep(.el-menu-item:hover) {
background-color: #001528 !important; background-color: #001528 !important;
} }
</style> </style>
\ No newline at end of file
<template> <template>
<template v-for="menu in menuList" :key="menu.path"> <template v-for="menu in menuList" :key="menu.path">
<el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.path"> <el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.path">
<template #title> <template #title>
<el-icon> <el-icon>
<component class="icons" :is="menu.meta.icon" /> <component class="icons" :is="menu.meta.icon" />
</el-icon> </el-icon>
<span>{{ menu.meta.title }}</span> <span>{{ menu.meta.title }}</span>
</template> </template>
<menu-item :menuList="menu.children"></menu-item> <menu-item :menuList="menu.children"></menu-item>
</el-sub-menu> </el-sub-menu>
<el-menu-item style="color: #f4f4f5" v-else :index="menu.path"> <el-menu-item style="color: #f4f4f5" v-else :index="menu.path">
<i v-if="menu.meta.icon && menu.meta.icon.includes('el-icon')" :class="menu.meta.icon"></i> <i v-if="menu.meta.icon && menu.meta.icon.includes('el-icon')" :class="menu.meta.icon"></i>
<el-icon v-if="menu.meta.icon"> <el-icon v-if="menu.meta.icon">
<component class="icons" :is="menu.meta.icon" /> <component class="icons" :is="menu.meta.icon" />
</el-icon> </el-icon>
<template #title>{{ menu.meta.title }}</template> <template #title>{{ menu.meta.title }}</template>
</el-menu-item> </el-menu-item>
</template> </template>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
defineProps(['menuList']) defineProps(['menuList'])
</script> </script>
<style scoped> <style scoped>
.icons { .icons {
width: 24px; width: 24px;
height: 18px; height: 18px;
margin-right: 5px; margin-right: 5px;
} }
</style> </style>
\ No newline at end of file
<template> <template>
<div class="logo"> <div class="logo">
<img src="@/assets/logo.png" alt="logo" /> <img src="@/assets/logo.png" alt="logo" />
<span class="title">永信达商城</span> <span class="title">永信达商城</span>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.logo { .logo {
background-color: #2b2f3a; background-color: #2b2f3a;
height: 50px; height: 50px;
border: none; border: none;
line-height: 50px; line-height: 50px;
display: flex; display: flex;
align-items: center; align-items: center;
padding-left: 15px; padding-left: 15px;
color: #fff; color: #fff;
img { img {
width: 64px; width: 64px;
height: 32px; height: 32px;
margin-right: 12px; margin-right: 12px;
} }
span { span {
font-weight: 600; font-weight: 600;
line-height: 50px; line-height: 50px;
font-size: 16px; font-size: 16px;
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
vertical-align: middle; vertical-align: middle;
} }
} }
</style> </style>
\ No newline at end of file
<template> <template>
<el-tabs v-model="activeTab" @tab-click="clickBtn" type="card" closable @tab-remove="removeTab"> <el-tabs v-model="activeTab" @tab-click="clickBtn" type="card" closable @tab-remove="removeTab">
<el-tab-pane v-for="item in tabsList" :key="item.path" :label="item.title" :name="item.path"></el-tab-pane> <el-tab-pane v-for="item in tabsList" :key="item.path" :label="item.title" :name="item.path"></el-tab-pane>
</el-tabs> </el-tabs>
</template> </template>
<script setup lang='ts'> <script setup lang='ts'>
import { ref, computed, watch, onMounted } from 'vue' import { ref, computed, watch, onMounted } from 'vue'
import { useStore } from '@/store'; import { useStore } from '@/store';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { ITabe } from '@/store/types'; import { ITabe } from '@/store/types';
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const store = useStore(); const store = useStore();
//获取tabs数据 //获取tabs数据
const tabsList = computed(() => { const tabsList = computed(() => {
// return store.getters['getTabs'] // return store.getters['getTabs']
return store.getters['tabs/getTabs'] return store.getters['tabs/getTabs']
}) })
//当前激活的选项卡,他跟当前激活的路由是一样的; //当前激活的选项卡,他跟当前激活的路由是一样的;
const activeTab = ref(''); const activeTab = ref('');
const setActiveTab = () => { const setActiveTab = () => {
activeTab.value = route.path; activeTab.value = route.path;
} }
//删除选项卡 //删除选项卡
const removeTab = (targetName: string) => { const removeTab = (targetName: string) => {
if (targetName === '/dashboard') return; if (targetName === '/dashboard') return;
//选项卡数据列表 //选项卡数据列表
const tabs = tabsList.value; const tabs = tabsList.value;
//当前激活的选项卡 //当前激活的选项卡
let activeName = activeTab.value; let activeName = activeTab.value;
if (activeName === targetName) { if (activeName === targetName) {
tabs.forEach((tab: ITabe, index: number) => { tabs.forEach((tab: ITabe, index: number) => {
if (tab.path === targetName) { if (tab.path === targetName) {
const nextTab = tabs[index + 1] || tabs[index - 1] const nextTab = tabs[index + 1] || tabs[index - 1]
if (nextTab) { if (nextTab) {
activeName = nextTab.path activeName = nextTab.path
} }
} }
}) })
} }
//重新设置当前激活的选项卡 //重新设置当前激活的选项卡
activeTab.value = activeName activeTab.value = activeName
//重新设置选项卡数据 //重新设置选项卡数据
store.state.tabs.tabsList = tabs.filter((tab: ITabe) => tab.path !== targetName) store.state.tabs.tabsList = tabs.filter((tab: ITabe) => tab.path !== targetName)
//跳转路由 //跳转路由
router.push({ path: activeName }) router.push({ path: activeName })
} }
//添加选项卡 //添加选项卡
const addTab = () => { const addTab = () => {
//从当前路由获取path和title //从当前路由获取path和title
const { path, meta } = route; const { path, meta } = route;
//通过vuex设置 //通过vuex设置
const tab: ITabe = { const tab: ITabe = {
path: path, path: path,
title: meta.title as string title: meta.title as string
} }
// store.commit('addTabe', tab); // store.commit('addTabe', tab);
store.commit('tabs/addTabe', tab) store.commit('tabs/addTabe', tab)
} }
//监听路由的变化 //监听路由的变化
watch(() => route.path, () => { watch(() => route.path, () => {
//设置激活的选项卡 //设置激活的选项卡
setActiveTab(); setActiveTab();
//把当前路由添加到选项卡数据 //把当前路由添加到选项卡数据
addTab(); addTab();
}) })
//解决刷新数据丢失的问题 //解决刷新数据丢失的问题
const beforeRefresh = () => { const beforeRefresh = () => {
if (route.path != '/login') { if (route.path != '/login') {
window.addEventListener('beforeunload', () => { window.addEventListener('beforeunload', () => {
sessionStorage.setItem('tabsView', JSON.stringify(tabsList.value)) sessionStorage.setItem('tabsView', JSON.stringify(tabsList.value))
}) })
let tabSesson = sessionStorage.getItem("tabsView"); let tabSesson = sessionStorage.getItem("tabsView");
if (tabSesson) { if (tabSesson) {
let oldTabs = JSON.parse(tabSesson); let oldTabs = JSON.parse(tabSesson);
if (oldTabs.length > 0) { if (oldTabs.length > 0) {
store.state.tabs.tabsList = oldTabs; store.state.tabs.tabsList = oldTabs;
} }
} }
} }
} }
onMounted(() => { onMounted(() => {
//解决刷新选项卡数据丢失的问题 //解决刷新选项卡数据丢失的问题
beforeRefresh(); beforeRefresh();
//设置激活的选项卡 //设置激活的选项卡
setActiveTab(); setActiveTab();
//把当前路由添加到选项卡数据 //把当前路由添加到选项卡数据
addTab(); addTab();
}) })
//选项卡点击事件 //选项卡点击事件
const clickBtn = (tab: any) => { const clickBtn = (tab: any) => {
const { props } = tab; const { props } = tab;
//跳转路由 //跳转路由
router.push({ path: props.name }) router.push({ path: props.name })
} }
</script> </script>
<style scoped lang='scss'> <style scoped lang='scss'>
:deep(.el-tabs__header) { :deep(.el-tabs__header) {
margin: 0px; margin: 0px;
} }
:deep(.el-tabs__item) { :deep(.el-tabs__item) {
height: 26px !important; height: 26px !important;
line-height: 26px !important; line-height: 26px !important;
text-align: center !important; text-align: center !important;
border: 1px solid #d8dce5 !important; border: 1px solid #d8dce5 !important;
margin: 0px 3px !important; margin: 0px 3px !important;
color: #495060; color: #495060;
font-size: 12px !important; font-size: 12px !important;
padding: 0px 10px !important; padding: 0px 10px !important;
} }
:deep(.el-tabs__nav) { :deep(.el-tabs__nav) {
border: none !important; border: none !important;
} }
:deep(.is-active) { :deep(.is-active) {
border-bottom: 1px solid transparent !important; border-bottom: 1px solid transparent !important;
border: 1px solid #42b983 !important; border: 1px solid #42b983 !important;
background-color: #42b983 !important; background-color: #42b983 !important;
color: #fff !important; color: #fff !important;
} }
:deep(.el-tabs__item:hover) { :deep(.el-tabs__item:hover) {
color: #495060 !important; color: #495060 !important;
} }
:deep(.is-active:hover) { :deep(.is-active:hover) {
color: #fff !important; color: #fff !important;
} }
</style> </style>
\ No newline at end of file
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
// 注入路由 // 注入路由
import router from './router'; import router from './router';
import { start, close } from '@/utils/nprogress' import { start, close } from '@/utils/nprogress'
import { getToken, cleanSession, getMenu } from '@/utils/auth' import { getToken, cleanSession, getMenu } from '@/utils/auth'
import { elNotificaton } from '@/utils/customemessage' import { elNotificaton } from '@/utils/customemessage'
//import '@/mock' //生产时请注释掉, //import '@/mock' //生产时请注释掉,
import { filterAsyncRoutes } from '@/store/modules/menu' import { filterAsyncRoutes } from '@/store/modules/menu'
import { store, key } from '@/store' import { store, key } from '@/store'
import * as ElIconModules from '@element-plus/icons-vue' import * as ElIconModules from '@element-plus/icons-vue'
//全局添加组件 //全局添加组件
// 全局注入ui组件库,按需引入迁移到vite.config.ts配置 // 全局注入ui组件库,按需引入迁移到vite.config.ts配置
import ElementPlus from 'element-plus' import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css' import 'element-plus/dist/index.css'
import { CopyData, resetForm } from './utils/common'; import { CopyData, resetForm } from './utils/common';
import LqConfirm from './utils/LqConfirm' import LqConfirm from './utils/LqConfirm'
//引入按钮权限 //引入按钮权限
import { permission } from './directives/permission' import { permission } from './directives/permission'
//引入socket //引入socket
import SocketService from '@/socket/main' import SocketService from '@/socket/main'
// SocketService.Instance.connect(); // SocketService.Instance.connect();
// 国际化 // 国际化
import i18n from "@/lang/index"; import i18n from "@/lang/index";
//注册svg图标脚本 //注册svg图标脚本
import 'virtual:svg-icons-register' import 'virtual:svg-icons-register'
import GlobalComponents from './global-components'; import GlobalComponents from './global-components';
const whiteList = ['/login']; //白名单 const whiteList = ['/login']; //白名单
// 设置路由导航守卫 // 设置路由导航守卫
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
//设置标题 //设置标题
if (to.meta.title) { if (to.meta.title) {
document.title = String(to.meta.title) document.title = String(to.meta.title)
} }
else { else {
document.title = import.meta.env.VITE_APP_TITLE; document.title = import.meta.env.VITE_APP_TITLE;
} }
//获取token //获取token
let token = getToken(); let token = getToken();
if (token) { if (token) {
if (to.path === '/login' || to.path === '/') { if (to.path === '/login' || to.path === '/') {
next({ path: '/' }) next({ path: '/' })
} else { } else {
if (store.state.menu.menuList.length == 1) { if (store.state.menu.menuList.length == 1) {
try { try {
await store.dispatch('user/getInfo') await store.dispatch('user/getInfo')
await store.dispatch('menu/getMenuList', router) await store.dispatch('menu/getMenuList', router)
next({ ...to, replace: true }) next({ ...to, replace: true })
} catch (error) { } catch (error) {
cleanSession(); cleanSession();
next({ path: '/login' }) next({ path: '/login' })
} }
} else { } else {
next() next()
} }
} }
} else { } else {
//判断是否在白名单中 //判断是否在白名单中
if (whiteList.indexOf(to.path) !== -1 || to.path === '/import/lic') { //存在白名单,放行 if (whiteList.indexOf(to.path) !== -1 || to.path === '/import/lic') { //存在白名单,放行
next(); next();
} else { //不存在,登录 } else { //不存在,登录
next({ path: '/login' }) next({ path: '/login' })
} }
} }
}) })
const app = createApp(App); const app = createApp(App);
Object.keys(ElIconModules).forEach((key) => { Object.keys(ElIconModules).forEach((key) => {
app.component(key, ElIconModules[key as keyof typeof ElIconModules]) app.component(key, ElIconModules[key as keyof typeof ElIconModules])
}); });
app.use(store, key) app.use(store, key)
app.use(router); app.use(router);
app.use(ElementPlus) app.use(ElementPlus)
app.use(i18n); app.use(i18n);
app.mount('#app'); app.mount('#app');
//注册 //注册
app.directive('permission', permission); app.directive('permission', permission);
GlobalComponents(app) GlobalComponents(app)
//清空表单 //清空表单
app.config.globalProperties.$resetForm = resetForm; app.config.globalProperties.$resetForm = resetForm;
//对象复制 //对象复制
app.config.globalProperties.$objCoppy = CopyData; app.config.globalProperties.$objCoppy = CopyData;
//确定弹框 //确定弹框
app.config.globalProperties.$lqconfirm = LqConfirm; app.config.globalProperties.$lqconfirm = LqConfirm;
// 路由加载结束后执行 // 路由加载结束后执行
router.afterEach(() => { router.afterEach(() => {
close() close()
}) })
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router"; import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
import Layout from "@/layout/index.vue"; import Layout from "@/layout/index.vue";
const routes: Array<RouteRecordRaw> = [ const routes: Array<RouteRecordRaw> = [
{ {
path: "/", path: "/",
component: Layout, component: Layout,
redirect: "/dashboard", redirect: "/dashboard",
children: [ children: [
{ {
path: "/dashboard", path: "/dashboard",
component: () => import("@/views/dashboard/index.vue"), component: () => import("@/views/dashboard/index.vue"),
name: "dashboard", name: "dashboard",
meta: { meta: {
title: "首页", title: "首页",
icon: "#icondashboard", icon: "#icondashboard",
}, },
}, },
], ],
}, },
{ {
path: "/commodity", path: "/commodity",
component: Layout, component: Layout,
children: [ children: [
{ {
path: "/commodity/edit", path: "/commodity/edit",
component: () => import("@/views/commodityManage/edit.vue"), component: () => import("@/views/commodityManage/edit.vue"),
name: "edit", name: "edit",
meta: { meta: {
title: "商品编辑", title: "商品编辑",
icon: "", icon: "",
}, },
}, },
], ],
}, },
{ {
path: "/login", path: "/login",
name: "login", name: "login",
component: () => import("@/views/login/login.vue"), component: () => import("@/views/login/login.vue"),
}, },
{ {
path: "/import/lic", path: "/import/lic",
name: "importLic", name: "importLic",
component: () => import("@/views/login/importLic.vue"), component: () => import("@/views/login/importLic.vue"),
}, },
{ {
path: "/404", path: "/404",
name: "404", name: "404",
component: () => import("@/views/exception/404.vue"), component: () => import("@/views/exception/404.vue"),
}, },
// { // {
// path: '/:catchAll(.*)', // path: '/:catchAll(.*)',
// redirect: '/404' // redirect: '/404'
// } // }
]; ];
export const asyncRoutes: Array<RouteRecordRaw> = []; export const asyncRoutes: Array<RouteRecordRaw> = [];
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
// routes = routes:routes // routes = routes:routes
routes, routes,
}); });
export function addRoutes(routes: any) { export function addRoutes(routes: any) {
router.addRoute(routes); router.addRoute(routes);
} }
export default router; export default router;
import { request } from '../config' import { request } from '../config'
export function listGoods(params: any) { export function listGoods(params: any) {
return request({ return request({
url: '/goods/list', url: '/goods/list',
method: 'get', method: 'get',
params params
}) })
} }
export function deleteGoods(data: any) { export function deleteGoods(data: any) {
return request({ return request({
url: '/goods/delete', url: '/goods/delete',
method: 'post', method: 'post',
data data
}) })
} }
export function publishGoods(data: any) { export function publishGoods(data: any) {
return request({ return request({
url: '/goods/create', url: '/goods/create',
method: 'post', method: 'post',
data data
}) })
} }
export function detailGoods(id: number) { export function detailGoods(id: number) {
return request({ return request({
url: '/goods/detail', url: '/goods/detail',
method: 'get', method: 'get',
params: { id } params: { id }
}) })
} }
export function editGoods(data: any) { export function editGoods(data: any) {
return request({ return request({
url: '/goods/update', url: '/goods/update',
method: 'post', method: 'post',
data data
}) })
} }
export function listCatAndBrand() { export function listCatAndBrand() {
return request({ return request({
url: '/goods/catAndBrand', url: '/goods/catAndBrand',
method: 'get' method: 'get'
}) })
} }
export function xlsxDownload(key: string) { export function xlsxDownload(key: string) {
return request({ return request({
url: '/storage/download/' + key, url: '/storage/download/' + key,
method: 'get', method: 'get',
responseType: 'blob' responseType: 'blob'
}) })
} }
import router from '@/router' import router from '@/router'
import axios, { AxiosInstance } from 'axios' import axios, { AxiosInstance } from 'axios'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
// api路径 // api路径
const API_URL: string = import.meta.env.VITE_APP_BASE_URL const API_URL: string = import.meta.env.VITE_APP_BASE_URL
const service: AxiosInstance = axios.create({ const service: AxiosInstance = axios.create({
timeout: 15000 timeout: 15000
}) })
// 请求拦截 // 请求拦截
service.interceptors.request.use( service.interceptors.request.use(
config => { config => {
const token = sessionStorage.getItem('token') const token = sessionStorage.getItem('token')
if (token) { if (token) {
config.headers = { 'Authorization': `${token}`, ...config.headers } config.headers = { 'Authorization': `${token}`, ...config.headers }
} }
return config return config
} }
) )
// 数据返回拦截 // 数据返回拦截
service.interceptors.response.use( service.interceptors.response.use(
res => { res => {
// 数据请求成功后 相应操作 // 数据请求成功后 相应操作
const responseData = res.data const responseData = res.data
if (responseData.code !== 200) { if (responseData.code !== 200) {
ElMessage.error(responseData.msg) ElMessage.error(responseData.msg)
} }
return responseData return responseData
}, },
error => { error => {
// 数据请求失败后的相应操作 // 数据请求失败后的相应操作
const response = error.response; const response = error.response;
// 根据返回的code值来做不同的处理(和后端约定) // 根据返回的code值来做不同的处理(和后端约定)
switch (response.status) { switch (response.status) {
case 401: case 401:
if (response.data.code === 911) { if (response.data.code === 911) {
window.location.href = "/#/login"; window.location.href = "/#/login";
sessionStorage.clear() sessionStorage.clear()
return ElMessage.error('请重新登录') return ElMessage.error('请重新登录')
} else if (response.data.code === 913) { } else if (response.data.code === 913) {
router.push({ path: '/import/lic' }) router.push({ path: '/import/lic' })
return ElMessage.error('请重新导入lic文件') return ElMessage.error('请重新导入lic文件')
} }
ElMessage.error('错误请求') ElMessage.error('错误请求')
break; break;
case 403: case 403:
// 没有权限 // 没有权限
ElMessage.error('没有权限') ElMessage.error('没有权限')
break; break;
case 500: case 500:
// 服务端错误 // 服务端错误
ElMessage.error('服务端错误(500)') ElMessage.error('服务端错误(500)')
break; break;
case 503: case 503:
// 服务端错误 // 服务端错误
ElMessage.error('服务端错误(503)') ElMessage.error('服务端错误(503)')
break; break;
default: default:
ElMessage.error(`服务端错误${response.status}`) ElMessage.error(`服务端错误${response.status}`)
break; break;
} }
return error return error
} }
) )
interface ParamData { interface ParamData {
url: string; url: string;
method?: 'post' | 'get' | 'delete' | 'put'; method?: 'post' | 'get' | 'delete' | 'put';
data?: any; data?: any;
params?: any; params?: any;
headers?: any; headers?: any;
responseType?: any; responseType?: any;
} }
export function request(params: ParamData) { export function request(params: ParamData) {
if (params.url.indexOf('http') === -1) { if (params.url.indexOf('http') === -1) {
params.url = API_URL + params.url params.url = API_URL + params.url
} }
return service(params) return service(params)
} }
import { request } from '../config' import { request } from '../config'
export function getBankList(params: any) { export function getBankList(params: any) {
return request({ return request({
url: '/bank_info', url: '/bank_info',
method: 'get', method: 'get',
params, params,
}) })
} }
export function addBank(data: any) { export function addBank(data: any) {
return request({ return request({
url: '/bank_info', url: '/bank_info',
method: 'post', method: 'post',
data, data,
}) })
} }
export function updateBank(data: any) { export function updateBank(data: any) {
return request({ return request({
url: '/bank_info', url: '/bank_info',
method: 'put', method: 'put',
data, data,
}) })
} }
export function deleteBank(id: any) { export function deleteBank(id: any) {
return request({ return request({
url: '/bank_info', url: '/bank_info',
method: 'delete', method: 'delete',
params: { id }, params: { id },
}) })
} }
import { request } from '../config' import { request } from '../config'
export function listMall() { export function listMall() {
return request({ return request({
url: '/config/mall', url: '/config/mall',
method: 'get' method: 'get'
}) })
} }
export function updateMall(data: any) { export function updateMall(data: any) {
return request({ return request({
url: '/config/mall', url: '/config/mall',
method: 'post', method: 'post',
data data
}) })
} }
export function listExpress() { export function listExpress() {
return request({ return request({
url: '/config/express', url: '/config/express',
method: 'get' method: 'get'
}) })
} }
export function updateExpress(data: any) { export function updateExpress(data: any) {
return request({ return request({
url: '/config/express', url: '/config/express',
method: 'post', method: 'post',
data data
}) })
} }
export function listOrder() { export function listOrder() {
return request({ return request({
url: '/config/order', url: '/config/order',
method: 'get' method: 'get'
}) })
} }
export function updateOrder(data: any) { export function updateOrder(data: any) {
return request({ return request({
url: '/config/order', url: '/config/order',
method: 'post', method: 'post',
data data
}) })
} }
export function listWx() { export function listWx() {
return request({ return request({
url: '/config/wx', url: '/config/wx',
method: 'get' method: 'get'
}) })
} }
export function updateWx(data: any) { export function updateWx(data: any) {
return request({ return request({
url: '/config/wx', url: '/config/wx',
method: 'post', method: 'post',
data data
}) })
} }
// 税率 // 税率
export function taxConfig() { export function taxConfig() {
return request({ return request({
url: '/config/tax', url: '/config/tax',
method: 'get' method: 'get'
}) })
} }
export function saveTaxConfig(data: any) { export function saveTaxConfig(data: any) {
return request({ return request({
url: '/config/tax', url: '/config/tax',
method: 'post', method: 'post',
data data
}) })
} }
import { request } from '../config' import { request } from '../config'
export function getPayList() { export function getPayList() {
return request({ return request({
url: '/pay/list', url: '/pay/list',
method: 'get' method: 'get'
}) })
} }
export function updatePay(data: any) { export function updatePay(data: any) {
return request({ return request({
url: '/pay/display', url: '/pay/display',
method: 'put', method: 'put',
data data
}) })
} }
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论