update:

1. 用户/角色 管理
This commit is contained in:
xuyucheng 2023-11-07 15:46:14 +08:00
parent 57c948572b
commit 4d06f33df2
14 changed files with 2927 additions and 141 deletions

209
package-lock.json generated
View File

@ -24,14 +24,16 @@
"mitt": "^3.0.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"openapi-fetch": "^0.8.1",
"path": "^0.12.7",
"pinia": "^2.1.4",
"pinyin-pro": "^3.15.2",
"pnpm": "^8.9.0",
"pnpm": "^8.10.0",
"qs": "^6.11.2",
"responsive-storage": "^2.2.0",
"sortablejs": "^1.15.0",
"vue": "^3.3.4",
"vue-demi": "^0.14.6",
"vue-echarts": "^6.6.1",
"vue-router": "^4.2.2",
"vue-types": "^5.1.0"
@ -55,7 +57,7 @@
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"autoprefixer": "^10.4.14",
"autoprefixer": "^10.4.16",
"cloc": "^2.11.0",
"cssnano": "^6.0.1",
"eslint": "^8.43.0",
@ -64,7 +66,7 @@
"husky": "^8.0.3",
"lint-staged": "^13.2.2",
"picocolors": "^1.0.0",
"postcss": "^8.4.24",
"postcss": "^8.4.31",
"postcss-html": "^1.5.0",
"postcss-import": "^15.1.0",
"postcss-scss": "^4.0.6",
@ -86,7 +88,7 @@
"stylelint-prettier": "^3.0.0",
"stylelint-scss": "^5.0.1",
"svgo": "^3.0.2",
"tailwindcss": "^3.3.2",
"tailwindcss": "^3.3.5",
"terser": "^5.18.1",
"typescript": "5.0.4",
"vite": "^4.4.11",
@ -2531,28 +2533,6 @@
"vue-demi": ">=0.14.6"
}
},
"node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.14.6",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.6.tgz",
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@vueuse/metadata": {
"version": "10.5.0",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-10.5.0.tgz",
@ -2585,28 +2565,6 @@
"vue-demi": ">=0.14.6"
}
},
"node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.14.6",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.6.tgz",
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.6",
"resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.6.tgz",
@ -3630,9 +3588,23 @@
},
"node_modules/autoprefixer": {
"version": "10.4.16",
"resolved": "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.16.tgz",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
"integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/autoprefixer"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"browserslist": "^4.21.10",
"caniuse-lite": "^1.0.30001538",
@ -4757,28 +4729,6 @@
"vue-demi": "*"
}
},
"node_modules/element-plus/node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.14.6",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.6.tgz",
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/element-plus/node_modules/@vueuse/metadata": {
"version": "9.13.0",
"resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz",
@ -4792,28 +4742,6 @@
"vue-demi": "*"
}
},
"node_modules/element-plus/node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.14.6",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.6.tgz",
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz",
@ -7299,6 +7227,19 @@
"node": ">=12"
}
},
"node_modules/openapi-fetch": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.8.1.tgz",
"integrity": "sha512-xmzMaBCydPTMd0TKy4P2DYx/JOe9yjXtPIky1n1GV7nJJdZ3IZgSHvAWVbe06WsPD8EreR7E97IAiskPr6sa2g==",
"dependencies": {
"openapi-typescript-helpers": "^0.0.4"
}
},
"node_modules/openapi-typescript-helpers": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.4.tgz",
"integrity": "sha512-Q0MTapapFAG993+dx8lNw33X6P/6EbFr31yNymJHq56fNc6dODyRm8tWyRnGxuC74lyl1iCRMV6nQCGQsfVNKg=="
},
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.3.tgz",
@ -7533,28 +7474,6 @@
}
}
},
"node_modules/pinia/node_modules/vue-demi": {
"version": "0.14.6",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.6.tgz",
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/pinyin-pro": {
"version": "3.17.0",
"resolved": "https://registry.npmmirror.com/pinyin-pro/-/pinyin-pro-3.17.0.tgz",
@ -7581,15 +7500,18 @@
}
},
"node_modules/pnpm": {
"version": "8.9.0",
"resolved": "https://registry.npmmirror.com/pnpm/-/pnpm-8.9.0.tgz",
"integrity": "sha512-74hZk44fBTe5/PAwkEQxE5Lzs4s0QXbmzU/e4hsiVSSwrCobCK4q4t3Vs/9LjKSW1neOlQ8+fJ9VW4EyWYJEHA==",
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/pnpm/-/pnpm-8.10.0.tgz",
"integrity": "sha512-nCy4Pyts9qJdjFgwC/mRl8fvO+hM8+dm8pBUtAuDtC+Kq6b8wxSp7PJ8APfOgKdXu0xgiADnrb4tKdxccFb1vg==",
"bin": {
"pnpm": "bin/pnpm.cjs",
"pnpx": "bin/pnpx.cjs"
},
"engines": {
"node": ">=16.14"
},
"funding": {
"url": "https://opencollective.com/pnpm"
}
},
"node_modules/popmotion": {
@ -7610,8 +7532,22 @@
},
"node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.31.tgz",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
@ -9898,9 +9834,9 @@
}
},
"node_modules/tailwindcss": {
"version": "3.3.3",
"resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.3.3.tgz",
"integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
"integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
"dev": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
@ -9908,10 +9844,10 @@
"chokidar": "^3.5.3",
"didyoumean": "^1.2.2",
"dlv": "^1.1.3",
"fast-glob": "^3.2.12",
"fast-glob": "^3.3.0",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
"jiti": "^1.18.2",
"jiti": "^1.19.1",
"lilconfig": "^2.1.0",
"micromatch": "^4.0.5",
"normalize-path": "^3.0.0",
@ -10705,6 +10641,31 @@
"@vue/shared": "3.3.4"
}
},
"node_modules/vue-demi": {
"version": "0.14.6",
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz",
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/vue-echarts": {
"version": "6.6.1",
"resolved": "https://registry.npmmirror.com/vue-echarts/-/vue-echarts-6.6.1.tgz",

View File

@ -43,14 +43,16 @@
"mitt": "^3.0.0",
"mockjs": "^1.1.0",
"nprogress": "^0.2.0",
"openapi-fetch": "^0.8.1",
"path": "^0.12.7",
"pinia": "^2.1.4",
"pinyin-pro": "^3.15.2",
"pnpm": "^8.9.0",
"pnpm": "^8.10.0",
"qs": "^6.11.2",
"responsive-storage": "^2.2.0",
"sortablejs": "^1.15.0",
"vue": "^3.3.4",
"vue-demi": "^0.14.6",
"vue-echarts": "^6.6.1",
"vue-router": "^4.2.2",
"vue-types": "^5.1.0"
@ -74,7 +76,7 @@
"@vitejs/plugin-vue-jsx": "^3.0.1",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"autoprefixer": "^10.4.14",
"autoprefixer": "^10.4.16",
"cloc": "^2.11.0",
"cssnano": "^6.0.1",
"eslint": "^8.43.0",
@ -83,7 +85,7 @@
"husky": "^8.0.3",
"lint-staged": "^13.2.2",
"picocolors": "^1.0.0",
"postcss": "^8.4.24",
"postcss": "^8.4.31",
"postcss-html": "^1.5.0",
"postcss-import": "^15.1.0",
"postcss-scss": "^4.0.6",
@ -105,7 +107,7 @@
"stylelint-prettier": "^3.0.0",
"stylelint-scss": "^5.0.1",
"svgo": "^3.0.2",
"tailwindcss": "^3.3.2",
"tailwindcss": "^3.3.5",
"terser": "^5.18.1",
"typescript": "5.0.4",
"vite": "^4.4.11",

View File

@ -57,8 +57,8 @@ dependencies:
specifier: ^3.15.2
version: 3.15.2
pnpm:
specifier: ^8.9.0
version: registry.npmmirror.com/pnpm@8.9.0
specifier: ^8.10.0
version: 8.10.0
qs:
specifier: ^6.11.2
version: 6.11.2
@ -4627,6 +4627,12 @@ packages:
dev: false
optional: true
/pnpm@8.10.0:
resolution: {integrity: sha512-nCy4Pyts9qJdjFgwC/mRl8fvO+hM8+dm8pBUtAuDtC+Kq6b8wxSp7PJ8APfOgKdXu0xgiADnrb4tKdxccFb1vg==}
engines: {node: '>=16.14'}
hasBin: true
dev: false
/popmotion@11.0.5:
resolution: {integrity: sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==}
dependencies:
@ -6969,14 +6975,6 @@ packages:
engines: {node: '>=8'}
dev: true
registry.npmmirror.com/pnpm@8.9.0:
resolution: {integrity: sha512-74hZk44fBTe5/PAwkEQxE5Lzs4s0QXbmzU/e4hsiVSSwrCobCK4q4t3Vs/9LjKSW1neOlQ8+fJ9VW4EyWYJEHA==, registry: https://registry.npmjs.org/, tarball: https://registry.npmmirror.com/pnpm/-/pnpm-8.9.0.tgz}
name: pnpm
version: 8.9.0
engines: {node: '>=16.14'}
hasBin: true
dev: false
registry.npmmirror.com/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, registry: https://registry.npmjs.org/, tarball: https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz}
name: string-width

72
src/api/wide/apis.ts Normal file
View File

@ -0,0 +1,72 @@
import createClient from "openapi-fetch";
import {paths} from "./schema";
import {formatToken, getToken} from "@/utils/auth";
import {useUserStoreHook} from "@/store/modules/user";
import {FilterKeys, PathsWithMethod} from "openapi-typescript-helpers";
import {FetchOptions} from "openapi-fetch/src";
let timeoutPromise = (timeout: number) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('服务器地址不可用');
}, timeout)
})
};
function createSmebizClient<Paths extends {}>(clientOptions: Parameters<typeof createClient>[0] = {}, timeout?: number) {
const baseClient = createClient<Paths>(clientOptions);
return {
...baseClient,
async post<P extends PathsWithMethod<Paths, "post">>(url: P, body?: FetchOptions<FilterKeys<Paths[P], "post">>['body'], init?: FetchOptions<FilterKeys<Paths[P], "post">>) {
if (!init) init = {} as FetchOptions<FilterKeys<Paths[P], "post">>
if (body) init.body = body
if (!init.headers) init.headers = {}
const userData = getToken();
if (userData) {
const now = new Date().getTime();
const expired = parseInt(userData.expires) - now <= 0;
if (expired) {
// useUserStoreHook().logOut();
} else {
init.headers["Authorization"] = formatToken(userData.accessToken);
}
}
if (timeout) {
let controller = new AbortController();
init.signal = controller.signal;
setTimeout(() => {
// 当时间到达之后运行 abort
controller.abort();
}, timeout);
}
return await baseClient.POST(url, init)
}
}
}
export const sapi = createSmebizClient<paths>({baseUrl: ""}, 10000)
//
// export const sApi = new Proxy(baseClient, {
// get(_, key: keyof typeof baseClient) {
// const headers = {}
// const data = getToken();
// if (data) {
// const now = new Date().getTime();
// const expired = parseInt(data.expires) - now <= 0;
// if (expired) {
// useUserStoreHook().logOut();
// } else {
// headers["Authorization"] = formatToken(data.accessToken);
// }
// }
// const newClient = createClient<paths>({
// headers: headers,
// baseUrl: "",
// });
// return newClient[key];
// },
// });
// sPost('/wd-smebiz/rate/rate_serve/get')

8
src/api/wide/index.ts Normal file
View File

@ -0,0 +1,8 @@
import {sapi} from "./apis"
import {components} from "./schema";
type st = components['schemas']
const spost = sapi.post
export {sapi, spost}
export type {st}

2255
src/api/wide/schema.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@ import { createApp, Directive } from "vue";
import { MotionPlugin } from "@vueuse/motion";
// import { useEcharts } from "@/plugins/echarts";
import { injectResponsiveStorage } from "@/utils/responsive";
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// import Table from "@pureadmin/table";
// import PureDescriptions from "@pureadmin/descriptions";
@ -17,6 +18,7 @@ import "./style/reset.scss";
import "./style/index.scss";
// 一定要在main.ts中导入tailwind.css防止vite每次hmr都会请求src/style/index.scss整体css文件导致热更新慢的问题
import "./style/tailwind.css";
import "tailwindcss/tailwind.css"
import "element-plus/dist/index.css";
// 导入字体图标
import "./assets/iconfont/iconfont.js";
@ -30,6 +32,10 @@ Object.keys(directives).forEach(key => {
app.directive(key, (directives as { [key: string]: Directive })[key]);
});
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
// 全局注册`@iconify/vue`图标库
import {
IconifyIconOffline,

View File

@ -23,6 +23,15 @@ export default {
title: "查询条件",
showParent: true
}
},
{
path: "/setting/user",
name: "user",
component: () => import("@/views/setting/user/index.vue"),
meta: {
title: "用户管理",
showParent: true
}
}
]
};

View File

@ -19,6 +19,7 @@ html {
line-height: 1.5;
tab-size: 4;
text-size-adjust: 100%;
font-size: 14px;
}
body {

View File

@ -0,0 +1,30 @@
<template>
<el-container>
<el-tabs v-model="active">
<el-tab-pane label="用户" name="user">
<user />
</el-tab-pane>
<el-tab-pane label="角色" name="role">
<role />
</el-tab-pane>
</el-tabs>
</el-container>
</template>
<script setup lang='ts'>
import { ref } from "vue"
import user from "./user.vue"
import role from "./role.vue"
const active = ref('user')
</script>
<style scoped>
.el-container {
background-color: #fff;
padding: 15px 20px;
}
.el-tabs {
width: 100%;
}
</style>

View File

@ -0,0 +1,248 @@
<template>
<el-row justify="space-between">
<el-input placeholder="搜索角色"></el-input>
<el-button type="primary" @click="setCreate">添加角色</el-button>
</el-row>
<el-table :data="tableData.items" class="mt-2">
<el-table-column label="角色" prop="name"></el-table-column>
<el-table-column label="人数" prop="count" align="center"></el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button type="primary" link @click="setEdit(scope.row)">编辑</el-button>
<el-button type="danger" link @click="deleteRole(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination v-model:current-page="page.page" v-model:page-size="page.page_size" :page-sizes="[10, 20, 50, 100]"
:page-count="1" layout="sizes, prev, pager, next" @size-change="handleSizeChange"
@current-change="handleCurrentChange" />
<el-dialog v-model="visible" title="编辑角色" width="400">
<el-form :model="form">
<el-form-item label="角色">
<el-input v-model="form.name"></el-input>
</el-form-item>
<div v-for="(item, index) in ruleData" :key="index">
<h2 class="mb-2 text-[#409EFF]">{{ item.label }}</h2>
<div v-for="(v, k) in item.children" :key="k">
<h4 class="mb-2">{{ v.label }}</h4>
<div class="mb-2">
<el-checkbox v-model="m.checked" v-for="(m, n) in v.children" :key="n"
@change="(val) => { checkboxChange(val, m.id) }">
{{ m.label }}
</el-checkbox>
</div>
</div>
</div>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="updateRole">
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang='ts'>
import { ref, onMounted } from "vue"
import { spost } from "@/api/wide/index"
import { ElMessage } from 'element-plus'
const visible = ref(false)
const editStatus = ref(false)
const form = ref({
name: "",
posts: [],
auth_data: [],
})
const page = ref({
page: 1,
page_size: 10,
})
const tableData = ref({
count: 0,
items: []
})
const ruleData = ref([
{
label: "首页",
children: [
{
label: "数据平台监控看板",
children: [
{ label: "查看", id: 1, checked: false },
{ label: "编辑", id: 2, checked: false },
{ label: "删除", id: 3, checked: false },
]
},
]
},
{
label: "数据查询",
children: [
{
label: "企业数据查询",
children: [
{ label: "查看", id: 4, checked: false },
{ label: "编辑", id: 5, checked: false },
{ label: "删除", id: 6, checked: false },
]
},
{
label: "数据调用记录",
children: [
{ label: "查看", id: 7, checked: false },
{ label: "编辑", id: 8, checked: false },
{ label: "删除", id: 9, checked: false },
]
},
]
},
{
label: "数据采集",
children: [
{
label: "采集任务",
children: [
{ label: "查看", id: 10, checked: false },
{ label: "编辑", id: 11, checked: false },
{ label: "删除", id: 12, checked: false },
{ label: "新建", id: 13, checked: false },
]
},
]
},
{
label: "数据清洗",
children: [
{
label: "清洗任务",
children: [
{ label: "查看", id: 14, checked: false },
{ label: "编辑", id: 15, checked: false },
{ label: "删除", id: 16, checked: false },
{ label: "新建", id: 17, checked: false },
]
},
]
},
{
label: "设置",
children: [
{
label: "用户设置",
children: [
{ label: "查看", id: 18, checked: false },
{ label: "编辑", id: 19, checked: false },
{ label: "删除", id: 20, checked: false },
]
},
{
label: "数据存储设置",
children: [
{ label: "查看", id: 21, checked: false },
{ label: "编辑", id: 22, checked: false },
{ label: "删除", id: 23, checked: false },
]
},
]
},
])
onMounted(() => {
init()
})
const init = async () => {
const { error, data } = await spost("/wide_data/user/department/query", page.value)
tableData.value = data
}
const handleSizeChange = () => {
}
const handleCurrentChange = () => {
}
const setCreate = () => {
visible.value = true
editStatus.value = false
form.value = {
name: '',
posts: [],
auth_data: []
}
ruleData.value.forEach(item => {
item.children.forEach(v => {
v.children.forEach(m => {
m.checked = false
})
})
})
}
const setEdit = (row) => {
visible.value = true
editStatus.value = true
Object.assign(form.value, row)
form.value.auth_data = row.auth_data.map(item => { return item.id })
ruleData.value.forEach(item => {
item.children.forEach(v => {
v.children.forEach(m => {
m.checked = form.value.auth_data.includes(m.id)
})
})
})
}
const checkboxChange = (val, id) => {
if (val) {
if (!form.value.auth_data.includes(id)) {
form.value.auth_data.push(id)
}
} else {
if (form.value.auth_data.includes(id)) {
const index = form.value.auth_data.findIndex(item => { return item === id })
form.value.auth_data.splice(index, 1)
}
}
}
const updateRole = async () => {
const { error, data } = await spost(editStatus.value ? "/wide_data/user/department/update" : "/wide_data/user/department/add", form.value)
ElMessage({
message: error ? error.toString() : '操作成功',
type: error ? 'warning' : 'success'
})
visible.value = false
init()
}
const deleteRole = async (row) => {
const { error, data } = await spost("/wide_data/user/department/delete", { id: row.id })
ElMessage({
message: '删除成功',
type: 'success',
})
init()
}
</script>
<style scope>
.el-row>.el-input {
width: 200px;
}
.el-pagination {
float: right;
margin-top: 20px;
}
</style>

View File

@ -0,0 +1,180 @@
<template>
<el-container>
<el-aside width="200">
<el-input placeholder="请输入角色" />
<el-row class="mt-3 mb-3" align="middle">
<el-icon class="mr-2 text-[#409EFF]" :style="{ 'visibility': !page.query.departments ? 'visible' : 'hidden' }">
<Check />
</el-icon>
<el-text :type="!page.query.departments ? 'primary' : ''" @click=" page.query.departments = undefined, init()">全部</el-text>
</el-row>
<el-row v-for="item in roleList" :key="item.id" class="mt-3 mb-3" align="middle">
<el-icon class="mr-2 text-[#409EFF]"
:style="{ 'visibility': page.query.departments === item.id ? 'visible' : 'hidden' }">
<Check />
</el-icon>
<el-text :type="page.query.departments === item.id ? 'primary' : ''" @click="page.query.departments = item.id, init()">
{{ item.name }}
</el-text>
</el-row>
</el-aside>
<el-main>
<el-row justify="space-between">
<el-text type="primary">总人数{{ tableData.count }}</el-text>
<el-button type="primary" @click="visible = true, editStatus = false, form = {
name: '',
email: '',
phone: '',
departments: null,
}">添加用户</el-button>
</el-row>
<el-table :data="tableData.items" class="mt-2">
<el-table-column label="姓名" prop="name"></el-table-column>
<el-table-column label="状态" prop="status" align="center">
<template #default="scope">
<el-button :type="scope.row.status ? 'success' : 'info'" link>{{ scope.row.status ? '正常' : '停用' }}</el-button>
</template>
</el-table-column>
<el-table-column label="邮箱" prop="email" align="center"></el-table-column>
<el-table-column label="手机" prop="phone" align="center"></el-table-column>
<el-table-column label="角色" prop="departments" align="center">
<template #default="scope">
<span>{{ scope.row.departments.length ? scope.row.departments[0].name : '-' }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button type="primary" link
@click="visible = true, editStatus = true, Object.assign(form, scope.row), form.departments = scope.row.departments.length ? scope.row.departments[0].id : 0">编辑</el-button>
<el-button type="danger" link @click="deleteUser(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination v-model:current-page="page.page" v-model:page-size="page.page_size" :page-sizes="[10, 20, 50, 100]"
:page-count="1" layout="sizes, prev, pager, next" @size-change="handleSizeChange"
@current-change="handleCurrentChange" />
</el-main>
</el-container>
<el-dialog v-model="visible" title="编辑用户" width="400">
<el-form :model="form">
<el-form-item label="姓名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="手机">
<el-input v-model="form.phone"></el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email"></el-input>
</el-form-item>
<el-form-item label="角色">
<el-select v-model="form.departments">
<el-option v-for="item in roleList" :key="item.id" :label="item.name" :value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="状态">
<el-switch></el-switch>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false"> </el-button>
<el-button type="primary" @click="updateUser">
</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang='ts'>
import { ref, onMounted } from "vue"
import { spost } from "@/api/wide/index"
import { ElMessage } from 'element-plus'
const visible = ref(false)
const editStatus = ref(false)
const page = ref({
query: { departments: undefined },
page: 1,
page_size: 10,
})
const form = ref({
name: "",
email: "",
phone: "",
departments: 0,
})
const roleList = ref([])
const tableData = ref({
count: 0,
items: []
})
onMounted(() => {
init()
roleInit()
})
const init = async () => {
const { error, data } = await spost("/wide_data/user/user/query", page.value)
tableData.value = data
}
const roleInit = async () => {
const { error, data } = await spost("/wide_data/user/department/all", {})
roleList.value = data.items
}
const handleSizeChange = () => {
}
const handleCurrentChange = () => {
}
const updateUser = async () => {
const { error, data } = await spost(editStatus.value ? "/wide_data/user/user/update" : "/wide_data/user/user/add", { ...form.value, ...{ departments: [form.value.departments] } })
ElMessage({
message: error ? error.toString() : '操作成功',
type: error ? 'warning' : 'success'
})
visible.value = false
init()
}
const deleteUser = async (row) => {
await spost("/wide_data/user/user/delete", { id: row.id })
ElMessage({
message: '删除成功',
type: 'success',
})
init()
}
</script>
<style scoped>
.el-aside {
border-right: 1px solid #e4e7ed;
padding-right: 20px;
}
.el-main {
padding: 0 20px;
}
.el-pagination {
float: right;
margin-top: 20px;
}
.el-text {
cursor: pointer;
}
</style>

View File

@ -1,12 +1,16 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: "class",
important: true,
corePlugins: {
preflight: false
},
content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
theme: {
extend: {
width: {
'150': '150px'
},
colors: {
bg_color: "var(--el-bg-color)",
primary: "var(--el-color-primary)",
@ -14,5 +18,10 @@ module.exports = {
text_color_regular: "var(--el-text-color-regular)"
}
}
},
css: {
postcss: {
plugins: [require("tailwindcss"), require("autoprefixer")]
}
}
};

View File

@ -45,17 +45,24 @@ export default ({ command, mode }: ConfigEnv): UserConfigExport => {
// 本地跨域代理 https://cn.vitejs.dev/config/server-options.html#server-proxy
proxy: {
"/wide_data/": {
target: "http://0.0.0.0:8012",
target: "http://116.63.135.125",
changeOrigin: true
}
}
},
plugins: getPluginsList(command, VITE_CDN, VITE_COMPRESSION),
plugins: getPluginsList(command, VITE_CDN, VITE_COMPRESSION),css: {
postcss: {
plugins: [
require("tailwindcss"),
require("autoprefixer"),
]
}
},
// https://cn.vitejs.dev/config/dep-optimization-options.html#dep-optimization-options
optimizeDeps: {
include,
exclude
exclude: ['vue-demi']
},
build: {
outDir:"wd-data-web",