保存进度!
3
企业级管理系统/前端/项目源码/.browserslistrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
> 1%
|
||||||
|
last 2 versions
|
||||||
|
not dead
|
3
企业级管理系统/前端/项目源码/.env.development
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
VUE_APP_API = '/devApi'
|
||||||
|
VUE_APP_DEV_TARGET = 'http://v3.web-jshtml.cn/api'
|
||||||
|
# VUE_API_DEV_TARGET = 'http://v3.com/api'
|
1
企业级管理系统/前端/项目源码/.env.production
Normal file
@ -0,0 +1 @@
|
|||||||
|
VUE_APP_API = 'http://v3.web-jshtml.cn/api'
|
1
企业级管理系统/前端/项目源码/.env.test
Normal file
@ -0,0 +1 @@
|
|||||||
|
VUE_APP_API = 'http://v3.web-jshtml.cn/api'
|
14
企业级管理系统/前端/项目源码/.eslintrc.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
|
||||||
|
parserOptions: {
|
||||||
|
parser: "babel-eslint",
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||||
|
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||||
|
},
|
||||||
|
};
|
22
企业级管理系统/前端/项目源码/.gitignore
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
24
企业级管理系统/前端/项目源码/README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# vue3-element-plus-admin
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lints and fixes files
|
||||||
|
```
|
||||||
|
npm run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize configuration
|
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
3
企业级管理系统/前端/项目源码/babel.config.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: ["@vue/cli-plugin-babel/preset"],
|
||||||
|
};
|
30307
企业级管理系统/前端/项目源码/package-lock.json
generated
Normal file
44
企业级管理系统/前端/项目源码/package.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "vue3-element-plus-admin",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"dev": "vue-cli-service serve --mode test",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint",
|
||||||
|
"build:test": "vue-cli-service build --mode test"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.21.0",
|
||||||
|
"core-js": "^3.6.5",
|
||||||
|
"element-plus": "^2.2.26",
|
||||||
|
"js-cookie": "^2.2.1",
|
||||||
|
"js-sha1": "^0.6.0",
|
||||||
|
"vue": "^3.2.27",
|
||||||
|
"vue-router": "^4.1.6",
|
||||||
|
"vuex": "^4.0.2",
|
||||||
|
"wangeditor": "^4.7.12"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-router": "~4.5.0",
|
||||||
|
"@vue/cli-plugin-vuex": "~4.5.0",
|
||||||
|
"@vue/cli-service": "~4.5.0",
|
||||||
|
"@vue/compiler-sfc": "^3.0.0",
|
||||||
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"babel-plugin-component": "^1.1.1",
|
||||||
|
"eslint": "^6.7.2",
|
||||||
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
|
"eslint-plugin-vue": "^7.0.0",
|
||||||
|
"prettier": "^2.2.1",
|
||||||
|
"sass": "^1.26.5",
|
||||||
|
"sass-loader": "^8.0.2",
|
||||||
|
"svg-sprite-loader": "^5.2.1",
|
||||||
|
"unplugin-auto-import": "^0.5.11",
|
||||||
|
"unplugin-element-plus": "^0.2.0",
|
||||||
|
"unplugin-vue-components": "^0.17.17"
|
||||||
|
}
|
||||||
|
}
|
BIN
企业级管理系统/前端/项目源码/public/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
25
企业级管理系统/前端/项目源码/public/index.html
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<!-- vue3最新版本 -->
|
||||||
|
<script src="https://unpkg.com/vue@next"></script>
|
||||||
|
<!-- 引入Element Plus UI 组件库 -->
|
||||||
|
<link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css" />
|
||||||
|
<script src="//unpkg.com/element-plus"></script>
|
||||||
|
<!-- 语言包 -->
|
||||||
|
<script src="https://unpkg.com/browse/element-plus@1.2.0-beta.4/es/locale/lang/zh-cn.mjs"></script>
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
21
企业级管理系统/前端/项目源码/src/App.vue
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<el-config-provider :locale="locale">
|
||||||
|
<router-view />
|
||||||
|
</el-config-provider>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import zhCn from 'element-plus/lib/locale/lang/zh-cn'
|
||||||
|
export default {
|
||||||
|
name: "App",
|
||||||
|
setup() {
|
||||||
|
// 切换为中文
|
||||||
|
let locale = zhCn
|
||||||
|
return {
|
||||||
|
locale
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
#app{}
|
||||||
|
</style>
|
37
企业级管理系统/前端/项目源码/src/api/account.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import instance from "@/utils/request"; // 引入拦截器
|
||||||
|
/** 注册 */
|
||||||
|
export function Register(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/register/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 登录 */
|
||||||
|
export function Login(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/login/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 登出 */
|
||||||
|
export function Logout(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/logout/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 路由权限 */
|
||||||
|
export function GetPermission(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/permission",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
72
企业级管理系统/前端/项目源码/src/api/common.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import instance from "@/utils/request"; // 引入拦截器
|
||||||
|
/** 获取验证码 */
|
||||||
|
export function GetCode(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/getCode/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** http 状态码异常演示接口 */
|
||||||
|
export function ErrorHttp(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/error/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BasisTable组件公共接口
|
||||||
|
* @param { String } method 请求类型
|
||||||
|
* @param { String } url 请求地址
|
||||||
|
* @param { Object } data 请求参数
|
||||||
|
*/
|
||||||
|
export function TableData(params = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: params.method,
|
||||||
|
url: params.url,
|
||||||
|
data: params.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param { method } String 请求类型
|
||||||
|
* @param { url } String 请求地址
|
||||||
|
* @param { data } Object 请求参数
|
||||||
|
* @description BasisTable组件公共接口
|
||||||
|
*/
|
||||||
|
export function SwitchStatus(params = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: params.method,
|
||||||
|
url: params.url,
|
||||||
|
data: params.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param { method } String 请求类型
|
||||||
|
* @param { url } String 请求地址
|
||||||
|
* @param { data } Object 请求参数
|
||||||
|
* @description BasisTable组件公共接口
|
||||||
|
*/
|
||||||
|
export function CommonApi(params = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: params.method,
|
||||||
|
url: params.url,
|
||||||
|
data: params.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 文件上传 */
|
||||||
|
export function UploadFile(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/upload",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
102
企业级管理系统/前端/项目源码/src/api/info.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import instance from "@/utils/request"; // 引入拦截器
|
||||||
|
/** 一级分类添加 */
|
||||||
|
export function firstCategoryAdd(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/addFirstCategory/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取分类 */
|
||||||
|
export function GetCategory(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/getCategoryAll/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 子级分类添加 */
|
||||||
|
export function ChildCategoryAdd(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/addChildrenCategory/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分类编辑 */
|
||||||
|
export function CategoryEdit(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/editCategory/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 分类删除 */
|
||||||
|
export function CategoryDel(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/deleteCategory/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 添加信息 */
|
||||||
|
export function InfoCreate(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/add/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取列表 */
|
||||||
|
export function GetTableList(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/getList/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 发布状态 */
|
||||||
|
export function Status(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/status/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除 */
|
||||||
|
export function Delete(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/delete/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取详情 */
|
||||||
|
export function GetDetailed(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "get",
|
||||||
|
url: "/news/detailed/",
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 信息修改 */
|
||||||
|
export function InfoEdit(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/news/editInfo/",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
46
企业级管理系统/前端/项目源码/src/api/menu.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import instance from "@/utils/request"; // 引入拦截器
|
||||||
|
/** 创建菜单 */
|
||||||
|
export function MenuCreate(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/menu/create",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取菜单详情 */
|
||||||
|
export function MenuDetailed(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/menu/detailed",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 菜单编辑 */
|
||||||
|
export function MenuUpdate(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/menu/update",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 菜单列表 */
|
||||||
|
export function MenuList(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/menu/listsTree",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 菜单列表树状数据 */
|
||||||
|
export function MenuListTree(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/menu/listsTree",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
75
企业级管理系统/前端/项目源码/src/api/requestUrl.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
const apiUrl = {
|
||||||
|
// 信息模块
|
||||||
|
info: { // 模块键名
|
||||||
|
list: { // 列表数据接口
|
||||||
|
url: "/news/getList/",
|
||||||
|
method: "post"
|
||||||
|
},
|
||||||
|
info_status: {
|
||||||
|
url: "/news/status/",
|
||||||
|
method: "post"
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
method: "post",
|
||||||
|
url: "/news/delete/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 级联选择器模块
|
||||||
|
cascader: {
|
||||||
|
category: {
|
||||||
|
url: "/news/getCategoryAll/",
|
||||||
|
method: "post"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 菜单模块
|
||||||
|
menu: {
|
||||||
|
list: {
|
||||||
|
url: "/menu/lists",
|
||||||
|
method: "post"
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
method: "post",
|
||||||
|
url: "/menu/remove"
|
||||||
|
},
|
||||||
|
hidden_status: {
|
||||||
|
url: "/menu/statusHidden",
|
||||||
|
method: "post"
|
||||||
|
},
|
||||||
|
disabled_status: {
|
||||||
|
url: "/menu/statusDisabled",
|
||||||
|
method: "post"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 角色模块
|
||||||
|
role: {
|
||||||
|
status: {
|
||||||
|
url: "/role/status",
|
||||||
|
method: "post"
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
url: "/role/delete",
|
||||||
|
method: "post"
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
url: "/role/lists",
|
||||||
|
method: "post"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 用户模块
|
||||||
|
user: {
|
||||||
|
status: {
|
||||||
|
url: "/user/status",
|
||||||
|
method: "post"
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
method: "post",
|
||||||
|
url: "/user/remove"
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
url: "/user/lists",
|
||||||
|
method: "post"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export default apiUrl;
|
38
企业级管理系统/前端/项目源码/src/api/role.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import instance from "@/utils/request"; // 引入拦截器
|
||||||
|
/** 创建角色 */
|
||||||
|
export function RoleCreate(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/role/create",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 角色详情 */
|
||||||
|
export function RoleDetailed(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/role/detailed",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 角色修改 */
|
||||||
|
export function RoleUpdate(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/role/update",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 角色列表 */
|
||||||
|
export function RoleListAll(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/role/all",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
36
企业级管理系统/前端/项目源码/src/api/user.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import instance from "@/utils/request"; // 引入拦截器
|
||||||
|
/** 创建用户 */
|
||||||
|
export function UserCreate(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/user/create",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 用户详情 */
|
||||||
|
export function UserDetailed(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/user/detailed",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 用户修改 */
|
||||||
|
export function UserUpdate(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/user/update",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 修改密码 */
|
||||||
|
export function UpdatePass(data = {}){
|
||||||
|
return instance.request({
|
||||||
|
method: "post",
|
||||||
|
url: "/user/password",
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
BIN
企业级管理系统/前端/项目源码/src/assets/images/logo-min.png
Normal file
After Width: | Height: | Size: 490 B |
BIN
企业级管理系统/前端/项目源码/src/assets/images/logo.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
125
企业级管理系统/前端/项目源码/src/assets/zhCn.js
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
var zhCn = {
|
||||||
|
name: "zh-cn",
|
||||||
|
el: {
|
||||||
|
colorpicker: {
|
||||||
|
confirm: "\u786E\u5B9A",
|
||||||
|
clear: "\u6E05\u7A7A"
|
||||||
|
},
|
||||||
|
datepicker: {
|
||||||
|
now: "\u6B64\u523B",
|
||||||
|
today: "\u4ECA\u5929",
|
||||||
|
cancel: "\u53D6\u6D88",
|
||||||
|
clear: "\u6E05\u7A7A",
|
||||||
|
confirm: "\u786E\u5B9A",
|
||||||
|
selectDate: "\u9009\u62E9\u65E5\u671F",
|
||||||
|
selectTime: "\u9009\u62E9\u65F6\u95F4",
|
||||||
|
startDate: "\u5F00\u59CB\u65E5\u671F",
|
||||||
|
startTime: "\u5F00\u59CB\u65F6\u95F4",
|
||||||
|
endDate: "\u7ED3\u675F\u65E5\u671F",
|
||||||
|
endTime: "\u7ED3\u675F\u65F6\u95F4",
|
||||||
|
prevYear: "\u524D\u4E00\u5E74",
|
||||||
|
nextYear: "\u540E\u4E00\u5E74",
|
||||||
|
prevMonth: "\u4E0A\u4E2A\u6708",
|
||||||
|
nextMonth: "\u4E0B\u4E2A\u6708",
|
||||||
|
year: "\u5E74",
|
||||||
|
month1: "1 \u6708",
|
||||||
|
month2: "2 \u6708",
|
||||||
|
month3: "3 \u6708",
|
||||||
|
month4: "4 \u6708",
|
||||||
|
month5: "5 \u6708",
|
||||||
|
month6: "6 \u6708",
|
||||||
|
month7: "7 \u6708",
|
||||||
|
month8: "8 \u6708",
|
||||||
|
month9: "9 \u6708",
|
||||||
|
month10: "10 \u6708",
|
||||||
|
month11: "11 \u6708",
|
||||||
|
month12: "12 \u6708",
|
||||||
|
weeks: {
|
||||||
|
sun: "\u65E5",
|
||||||
|
mon: "\u4E00",
|
||||||
|
tue: "\u4E8C",
|
||||||
|
wed: "\u4E09",
|
||||||
|
thu: "\u56DB",
|
||||||
|
fri: "\u4E94",
|
||||||
|
sat: "\u516D"
|
||||||
|
},
|
||||||
|
months: {
|
||||||
|
jan: "\u4E00\u6708",
|
||||||
|
feb: "\u4E8C\u6708",
|
||||||
|
mar: "\u4E09\u6708",
|
||||||
|
apr: "\u56DB\u6708",
|
||||||
|
may: "\u4E94\u6708",
|
||||||
|
jun: "\u516D\u6708",
|
||||||
|
jul: "\u4E03\u6708",
|
||||||
|
aug: "\u516B\u6708",
|
||||||
|
sep: "\u4E5D\u6708",
|
||||||
|
oct: "\u5341\u6708",
|
||||||
|
nov: "\u5341\u4E00\u6708",
|
||||||
|
dec: "\u5341\u4E8C\u6708"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
loading: "\u52A0\u8F7D\u4E2D",
|
||||||
|
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
|
||||||
|
noData: "\u65E0\u6570\u636E",
|
||||||
|
placeholder: "\u8BF7\u9009\u62E9"
|
||||||
|
},
|
||||||
|
cascader: {
|
||||||
|
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
|
||||||
|
loading: "\u52A0\u8F7D\u4E2D",
|
||||||
|
placeholder: "\u8BF7\u9009\u62E9",
|
||||||
|
noData: "\u6682\u65E0\u6570\u636E"
|
||||||
|
},
|
||||||
|
pagination: {
|
||||||
|
goto: "\u524D\u5F80",
|
||||||
|
pagesize: "\u6761/\u9875",
|
||||||
|
total: "\u5171 {total} \u6761",
|
||||||
|
pageClassifier: "\u9875",
|
||||||
|
deprecationWarning: "\u4F60\u4F7F\u7528\u4E86\u4E00\u4E9B\u5DF2\u88AB\u5E9F\u5F03\u7684\u7528\u6CD5\uFF0C\u8BF7\u53C2\u8003 el-pagination \u7684\u5B98\u65B9\u6587\u6863"
|
||||||
|
},
|
||||||
|
messagebox: {
|
||||||
|
title: "\u63D0\u793A",
|
||||||
|
confirm: "\u786E\u5B9A",
|
||||||
|
cancel: "\u53D6\u6D88",
|
||||||
|
error: "\u8F93\u5165\u7684\u6570\u636E\u4E0D\u5408\u6CD5!"
|
||||||
|
},
|
||||||
|
upload: {
|
||||||
|
deleteTip: "\u6309 delete \u952E\u53EF\u5220\u9664",
|
||||||
|
delete: "\u5220\u9664",
|
||||||
|
preview: "\u67E5\u770B\u56FE\u7247",
|
||||||
|
continue: "\u7EE7\u7EED\u4E0A\u4F20"
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
emptyText: "\u6682\u65E0\u6570\u636E",
|
||||||
|
confirmFilter: "\u7B5B\u9009",
|
||||||
|
resetFilter: "\u91CD\u7F6E",
|
||||||
|
clearFilter: "\u5168\u90E8",
|
||||||
|
sumText: "\u5408\u8BA1"
|
||||||
|
},
|
||||||
|
tree: {
|
||||||
|
emptyText: "\u6682\u65E0\u6570\u636E"
|
||||||
|
},
|
||||||
|
transfer: {
|
||||||
|
noMatch: "\u65E0\u5339\u914D\u6570\u636E",
|
||||||
|
noData: "\u65E0\u6570\u636E",
|
||||||
|
titles: ["\u5217\u8868 1", "\u5217\u8868 2"],
|
||||||
|
filterPlaceholder: "\u8BF7\u8F93\u5165\u641C\u7D22\u5185\u5BB9",
|
||||||
|
noCheckedFormat: "\u5171 {total} \u9879",
|
||||||
|
hasCheckedFormat: "\u5DF2\u9009 {checked}/{total} \u9879"
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
error: "\u52A0\u8F7D\u5931\u8D25"
|
||||||
|
},
|
||||||
|
pageHeader: {
|
||||||
|
title: "\u8FD4\u56DE"
|
||||||
|
},
|
||||||
|
popconfirm: {
|
||||||
|
confirmButtonText: "\u786E\u5B9A",
|
||||||
|
cancelButtonText: "\u53D6\u6D88"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { zhCn as default };
|
||||||
|
//# sourceMappingURL=zh-cn.mjs.map
|
||||||
|
|
21
企业级管理系统/前端/项目源码/src/components/HelloWorld.vue
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div class="home">
|
||||||
|
<h1>这里是测试文字</h1>
|
||||||
|
<ul>
|
||||||
|
<li>无序列表LI</li>
|
||||||
|
<li>无序列表LI</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "HelloWorld",
|
||||||
|
props: {
|
||||||
|
msg: String,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
<style scoped lang="scss"></style>
|
12
企业级管理系统/前端/项目源码/src/components/cd-form/Input.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
import { h } from 'vue';
|
||||||
|
const Input = (props, context) => {
|
||||||
|
return () => {
|
||||||
|
return (
|
||||||
|
<div>sdfdsf</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Input.props = ['level'];
|
||||||
|
export default Input;
|
34
企业级管理系统/前端/项目源码/src/components/cd-form/hook/relationHook.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
export function relationHook(){
|
||||||
|
/**
|
||||||
|
* @param { String } value 控制方的选项 value
|
||||||
|
* @param { Array } data 关联关系的数据配置 relation_hidden
|
||||||
|
* @param { Object } props 显示/隐藏对象集保
|
||||||
|
*/
|
||||||
|
const HiddenItem = (value, data, props) => {
|
||||||
|
if(data && Array.isArray(data) && data.length > 0) {
|
||||||
|
data.forEach(item => {
|
||||||
|
const field = item[0];
|
||||||
|
const objValue = item[1];
|
||||||
|
props[field] = objValue[value]
|
||||||
|
// 选项为 1 时
|
||||||
|
// props["title"] = objValue["1"] => true
|
||||||
|
// props["iamge_url"] = objValue["1"] => true
|
||||||
|
// 选项为 0 时
|
||||||
|
// props["title"] = objValue["0"] => true
|
||||||
|
// props["iamge_url"] = objValue["0"] => undefined
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const DisabledItem = (value, data, props) => {
|
||||||
|
if(data && Array.isArray(data) && data.length > 0) {
|
||||||
|
data.forEach(item => {
|
||||||
|
const field = item[0];
|
||||||
|
const objValue = item[1];
|
||||||
|
props[field] = objValue[value]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { HiddenItem, DisabledItem };
|
||||||
|
}
|
75
企业级管理系统/前端/项目源码/src/components/cd-form/hook/rulesHook.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { moneyNValid } from "@/utils/amountFormat";
|
||||||
|
/**
|
||||||
|
* @returns BasisForm组件创建校验规则
|
||||||
|
*/
|
||||||
|
export function rulesHook() {
|
||||||
|
/**
|
||||||
|
* @param {*} data 配置额外组件
|
||||||
|
*/
|
||||||
|
const InitRules = (data = []) => {
|
||||||
|
if (data.length === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 判断是否有required属性
|
||||||
|
data.forEach((item) => {
|
||||||
|
// 初始化规则数组
|
||||||
|
let rulesArr = [];
|
||||||
|
if (item.required) {
|
||||||
|
const json = {
|
||||||
|
required: true,
|
||||||
|
message: item.required_msg || messageType(item).msg,
|
||||||
|
trigger: "blur",
|
||||||
|
};
|
||||||
|
rulesArr.push(json);
|
||||||
|
}
|
||||||
|
// 生成placeholder
|
||||||
|
item.placeholder = item.placeholder || messageType(item).placeholder;
|
||||||
|
// 是否有其他的校验规则
|
||||||
|
const rule = item.rule;
|
||||||
|
if (rule && Array.isArray(rule) && rule.length > 0) {
|
||||||
|
rulesArr = rulesArr.concat(rule);
|
||||||
|
}
|
||||||
|
// price
|
||||||
|
if (item.type === "price" && !item.rule) {
|
||||||
|
const json = { validator: moneyNValid, trigger: "blur" };
|
||||||
|
rulesArr.push(json);
|
||||||
|
}
|
||||||
|
// 定义rules属性赋值
|
||||||
|
item.rules = rulesArr;
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @description 提示文本
|
||||||
|
*/
|
||||||
|
const messageType = (data) => {
|
||||||
|
let msg = "";
|
||||||
|
switch (data.type) {
|
||||||
|
case "input":
|
||||||
|
case "wangeditor":
|
||||||
|
case "price":
|
||||||
|
case "range":
|
||||||
|
case "textarea":
|
||||||
|
msg = "请输入";
|
||||||
|
break;
|
||||||
|
case "upload":
|
||||||
|
msg = "请上传";
|
||||||
|
break;
|
||||||
|
case "radio":
|
||||||
|
case "checkbox":
|
||||||
|
case "select":
|
||||||
|
case "date":
|
||||||
|
case "cascader":
|
||||||
|
msg = "请选择";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msg = "未定义";
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
msg: `${msg}${data.label}`,
|
||||||
|
placeholder: `${msg}${data.label}`,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return { InitRules };
|
||||||
|
}
|
180
企业级管理系统/前端/项目源码/src/components/cd-form/index.vue
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<template>
|
||||||
|
<el-form ref="formDom" :model="field" :class="[{'label-gray': labelGray}]" :label-position="labelPosition" element-loading-text="加载中,请稍候" :label-width="label_width" >
|
||||||
|
<el-row :gutter="gutter">
|
||||||
|
<template v-for="item in form_item" :key="item.prop">
|
||||||
|
<el-col v-if="!form_hidden[item.prop]" :span="item.col || 24">
|
||||||
|
<component :is="'htmlComponent'" v-if="item.type === 'html'" :prop="item" />
|
||||||
|
<el-form-item v-else :label="item.label" :prop="item.prop" :rules="item.rules">
|
||||||
|
<!--自定义label-->
|
||||||
|
<template v-if="item.label_html" #label>
|
||||||
|
<span class="custom-label">
|
||||||
|
<div>
|
||||||
|
<span style="position: relative;">
|
||||||
|
<label class="form-center" v-html="item.label_html.label || ''" />
|
||||||
|
<em v-if="item.label_html.spot" class="spot"></em>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span :class="item.label_html.suffix_class" @click="item.label_html.suffix_callback && item.label_html.suffix_callback(item)" v-html="item.label_html.suffix_text || ''" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<!--动态组件-->
|
||||||
|
<div v-show="control" style="width:100%">
|
||||||
|
<component :is="item.type + 'Component'" v-if="item.type !== 'slot'" v-model:value="field[item.prop]" v-model:second-value="field[item.secondprop]" v-model:select-value="field[item.selProp]" :data="item" :header="item" :disabled="disabled[item.prop]" @callback="componentCallback" />
|
||||||
|
<!--插槽-->
|
||||||
|
<template v-else>
|
||||||
|
<slot :name="item.slot_name" />
|
||||||
|
<span v-if="item.tip" class="tip">{{ item.tip }}</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<div v-show="!control">
|
||||||
|
<slot v-if="item.slot_text" :name="item.slot_text" />
|
||||||
|
<span v-else>{{ fieldText[item.prop] || '--' }}</span>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
</el-row>
|
||||||
|
<!-- button -->
|
||||||
|
<div :class="['form-button', {'dialog-footer': dialog}]">
|
||||||
|
<template v-if="form_button && form_button.length > 0">
|
||||||
|
<template v-for="button in form_button" :key="button.key">
|
||||||
|
<template v-if="!button.hidden">
|
||||||
|
<CdButton v-if="button.key === 'submit'" :loading="load || loading" margin="0 0 0 16px" :type="button.type" @click="button.callback ? button.callback() : handlerFormValidate()">
|
||||||
|
{{ button.label }}
|
||||||
|
</CdButton>
|
||||||
|
<CdButton v-else-if="button.key === 'cancel'" margin="0 0 0 16px" border @click="button.callback ? button.callback() : handlerFormCancel()">
|
||||||
|
{{ button.label }}
|
||||||
|
</CdButton>
|
||||||
|
<CdButton v-else :type="button.type" margin="0 0 0 16px" @click="button.callback && button.callback()">{{ button.label }}</CdButton>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineAsyncComponent, onBeforeUnmount, reactive, ref, watch } from "vue";
|
||||||
|
import { checkDataType } from "../common";
|
||||||
|
// hook
|
||||||
|
import { rulesHook } from "./hook/rulesHook";
|
||||||
|
import { relationHook } from "./hook/relationHook";
|
||||||
|
// props
|
||||||
|
import { props } from "./props";
|
||||||
|
// require import components
|
||||||
|
const files = require.context("@/cd-components/cd-control", true, /\index.vue$/);
|
||||||
|
const modules = {};
|
||||||
|
files.keys().forEach((key) => {
|
||||||
|
const name = key.split("/");
|
||||||
|
modules[name[1] + "Component"] = files(key).default || files(key);
|
||||||
|
});
|
||||||
|
export default {
|
||||||
|
name: "BasisForm",
|
||||||
|
components: {
|
||||||
|
...modules,
|
||||||
|
CdButton: defineAsyncComponent(() => import("../cd-button")),
|
||||||
|
},
|
||||||
|
props,
|
||||||
|
emits: ["callback", "cancel"],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const { InitRules } = rulesHook();
|
||||||
|
const { HiddenItem, DisabledItem } = relationHook();
|
||||||
|
// 校验规则处理
|
||||||
|
const form_item = reactive(InitRules(props.item));
|
||||||
|
const label_width = ref(props.labelWidth);
|
||||||
|
const form_button = reactive(props.button);
|
||||||
|
const form_disabled = reactive(props.disabled);
|
||||||
|
const load = ref(false)
|
||||||
|
let form_hidden = ref({});
|
||||||
|
watch(() => props.hidden, (value) => {
|
||||||
|
form_hidden.value = value
|
||||||
|
})
|
||||||
|
// 表单提交验证
|
||||||
|
const formDom = ref(null);
|
||||||
|
const handlerFormValidate = () => {
|
||||||
|
formDom.value.validate((valid) => {
|
||||||
|
if(valid) {
|
||||||
|
if (checkDataType().isFunction(props.beforeChange)) {
|
||||||
|
load.value = true
|
||||||
|
props.beforeChange().then(() => {
|
||||||
|
load.value = false
|
||||||
|
}).catch(() => {
|
||||||
|
load.value = false
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
emit("callback")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
const handlerFormCancel = () => {
|
||||||
|
handlerFormReset()
|
||||||
|
emit("cancel");
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 重置表单
|
||||||
|
*/
|
||||||
|
const handlerFormReset = () => {
|
||||||
|
formDom.value.resetFields();
|
||||||
|
};
|
||||||
|
// change 事件
|
||||||
|
const componentCallback = (params) => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生命周期
|
||||||
|
*/
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
form_hidden.value = {}
|
||||||
|
handlerFormReset()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
form_item,
|
||||||
|
label_width,
|
||||||
|
form_button,
|
||||||
|
form_hidden,
|
||||||
|
form_disabled,
|
||||||
|
formDom,
|
||||||
|
load,
|
||||||
|
handlerFormValidate,
|
||||||
|
handlerFormCancel,
|
||||||
|
handlerFormReset,
|
||||||
|
componentCallback,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.form-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.form-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.form-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.form-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.custom-label {
|
||||||
|
position: relative;
|
||||||
|
> span {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::v-deep .color-lable-danger {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
background: #ff6060;
|
||||||
|
border-radius: 50%;
|
||||||
|
position: absolute;
|
||||||
|
right: -7px;
|
||||||
|
top: 7px;
|
||||||
|
}
|
||||||
|
:deep(.el-input__wrapper) {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
</style>
|
57
企业级管理系统/前端/项目源码/src/components/cd-form/props.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
export const props = {
|
||||||
|
item: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
labelWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: "100px",
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
fieldText: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
hidden: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
type: String,
|
||||||
|
default: "left",
|
||||||
|
},
|
||||||
|
labelPosition: {
|
||||||
|
type: String,
|
||||||
|
default: "right",
|
||||||
|
},
|
||||||
|
gutter: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
beforeChange: Function,
|
||||||
|
dialog: Boolean,
|
||||||
|
labelGray: Boolean,
|
||||||
|
control: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
fieldData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
};
|
86
企业级管理系统/前端/项目源码/src/components/control/cascader/index.vue
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<el-cascader :style="{width}" :disabled="disabled" v-model="data.value" :options="data.options" :props="data.props" @change="handlerChange"></el-cascader>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, onBeforeMount, watch } from 'vue';
|
||||||
|
// API
|
||||||
|
import { CommonApi } from "@/api/common";
|
||||||
|
// requestUrl
|
||||||
|
import ApiUrl from "@/api/requestUrl";
|
||||||
|
export default {
|
||||||
|
name: 'BasisCascader',
|
||||||
|
components: {},
|
||||||
|
props: {
|
||||||
|
cascaderProps: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
method: {
|
||||||
|
type: String,
|
||||||
|
default: "post"
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: "100%"
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ["update:value", 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const data = reactive({
|
||||||
|
props: props.data.props,
|
||||||
|
options: [],
|
||||||
|
value: 0
|
||||||
|
})
|
||||||
|
const handlerChange = (value) => {
|
||||||
|
// 获取最后一项
|
||||||
|
const val = value[value.length - 1];
|
||||||
|
// 返回
|
||||||
|
emit("update:value", val);
|
||||||
|
}
|
||||||
|
/** 获取列表 */
|
||||||
|
const getData = () => {
|
||||||
|
const url = ApiUrl?.cascader?.[props.url || props?.data?.url]?.url;
|
||||||
|
const method = ApiUrl?.cascader?.[props.url]?.method || "post";
|
||||||
|
if(!url) {
|
||||||
|
throw new Error("url地址不存在");
|
||||||
|
}
|
||||||
|
// 参数
|
||||||
|
const request_data = {
|
||||||
|
url,
|
||||||
|
method,
|
||||||
|
data: props.data,
|
||||||
|
}
|
||||||
|
CommonApi(request_data).then(response => {
|
||||||
|
data.options = response.data;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/** 生命周期挂载之前 */
|
||||||
|
onBeforeMount(() => {
|
||||||
|
getData();
|
||||||
|
})
|
||||||
|
/** 监听 */
|
||||||
|
watch(() => props.value, (newValue) => {
|
||||||
|
data.value = newValue
|
||||||
|
} )
|
||||||
|
|
||||||
|
return { data, handlerChange }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
43
企业级管理系统/前端/项目源码/src/components/control/checkbox/index.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<el-checkbox-group v-model="value" :disabled="form_disabled[data.prop]" @change="handlerChange">
|
||||||
|
<el-checkbox v-for="checkbox in data.options" :label="checkbox.value" :key="checkbox.value">{{ checkbox.label }}</el-checkbox>
|
||||||
|
</el-checkbox-group>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, toRefs } from 'vue';
|
||||||
|
export default {
|
||||||
|
name: "CheckboxComponent",
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:value', 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const data = reactive({
|
||||||
|
value: '',
|
||||||
|
data: props.data
|
||||||
|
})
|
||||||
|
|
||||||
|
const handlerChange = (val) => {
|
||||||
|
emit("update:value", val)
|
||||||
|
emit("callback", {
|
||||||
|
type: 'checkbox',
|
||||||
|
value: val,
|
||||||
|
data: props.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
handlerChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
52
企业级管理系统/前端/项目源码/src/components/control/date/index.vue
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<el-date-picker :style="`width: ${data.width}`"
|
||||||
|
v-model="value"
|
||||||
|
:disabled="disabled"
|
||||||
|
:type="data.date_type || 'datetime'"
|
||||||
|
:format="data.date_format || 'YYYY-MM-DD HH:mm:ss'"
|
||||||
|
:placeholder="data.placeholder || '选择日期时间'"
|
||||||
|
:start-placeholder="data.start_placeholder || '请选择开始日期'"
|
||||||
|
:end-placeholder="data.end_placeholder || '请选择结束日期'"
|
||||||
|
:range-separator="data.range_placeholder || '-'"
|
||||||
|
@change="handlerChange"
|
||||||
|
>
|
||||||
|
</el-date-picker>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, toRefs } from 'vue';
|
||||||
|
export default {
|
||||||
|
name: "DateComponent",
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [Array, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: Boolean
|
||||||
|
},
|
||||||
|
emits: ['update:value', 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const data = reactive({
|
||||||
|
value: '',
|
||||||
|
data: props.data
|
||||||
|
})
|
||||||
|
|
||||||
|
const handlerChange = (val) => {
|
||||||
|
emit("update:value", val)
|
||||||
|
emit("callback", {
|
||||||
|
type: 'date',
|
||||||
|
value: val,
|
||||||
|
data: props.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
handlerChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
49
企业级管理系统/前端/项目源码/src/components/control/input/index.vue
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<template>
|
||||||
|
<el-input
|
||||||
|
v-model="value"
|
||||||
|
:type="data.value_type || 'text'"
|
||||||
|
v-on:input="handlerEnter"
|
||||||
|
debounce
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:maxlength="prop.maxlength"
|
||||||
|
:minlength="prop.minlength || 0"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, toRefs, watchEffect } from 'vue';
|
||||||
|
export default {
|
||||||
|
name: "InputComponent",
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:value', 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const data = reactive({
|
||||||
|
value: '',
|
||||||
|
prop: props.data,
|
||||||
|
placeholder: props.data.placeholder
|
||||||
|
})
|
||||||
|
|
||||||
|
const handlerEnter = (val) => {
|
||||||
|
emit("update:value", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
handlerEnter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
41
企业级管理系统/前端/项目源码/src/components/control/inputNumber/index.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<el-input-number v-model="value" :min="data.min || 0" :max="data.max || 99999999" @change="handleChange" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, toRefs, watchEffect } from 'vue';
|
||||||
|
export default {
|
||||||
|
name: "InputComponent",
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:value', 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const data = reactive({
|
||||||
|
value: '',
|
||||||
|
data: props.data
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleChange = (val) => {
|
||||||
|
console.log(val)
|
||||||
|
emit("update:value", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
handleChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
74
企业级管理系统/前端/项目源码/src/components/control/keyword/index.vue
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<el-select v-model="key" placeholder="请选择" class="key-word-select" @change="handlerChange">
|
||||||
|
<el-option v-for="item in options" :key="item.value" :value="item.value" :label="item.label"></el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-input v-model="value" class="width-200" :placeholder="placeholder" v-on:input="callback"></el-input>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, toRefs, watch } from "vue";
|
||||||
|
export default {
|
||||||
|
name: "KeyWord",
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ["callback"],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const data = reactive({
|
||||||
|
key: "",
|
||||||
|
value: "",
|
||||||
|
placeholder: "请输入搜索的关键字",
|
||||||
|
options: props.data.options
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 下拉事件 */
|
||||||
|
const handlerChange = (value) => {
|
||||||
|
// 清除input输入框文本
|
||||||
|
data.value = "";
|
||||||
|
// 更新input输入框占位文本
|
||||||
|
updatePlaceholder();
|
||||||
|
// 回调
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 事件回调 */
|
||||||
|
const callback = () => {
|
||||||
|
emit("callback", {
|
||||||
|
type: 'keyword',
|
||||||
|
value: { key: data.key, value: data.value },
|
||||||
|
formItem: props.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** update Placeholder */
|
||||||
|
const updatePlaceholder =() => {
|
||||||
|
const item = data.options.filter(item => item.value === data.key)[0];
|
||||||
|
data.placeholder = `请输入${item.label}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 清除 */
|
||||||
|
const handlerClear = () => {
|
||||||
|
data.key = "";
|
||||||
|
data.value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
handlerChange,
|
||||||
|
handlerClear,
|
||||||
|
callback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.key-word-select {
|
||||||
|
width: 100px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.width-200 { width: 200px; }
|
||||||
|
</style>
|
57
企业级管理系统/前端/项目源码/src/components/control/radio/index.vue
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<template v-if="!data.options && data.callback && data.callback(data)"></template>
|
||||||
|
<el-radio-group v-else v-model="value" :disabled="disabled" @change="handlerChange">
|
||||||
|
<el-radio
|
||||||
|
v-for="radio in data.options"
|
||||||
|
:key="radio[data.key_value] || radio.value"
|
||||||
|
:label="radio[data.key_value] || radio.value">
|
||||||
|
{{ radio[data.key_label] || radio.label }}
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, toRefs, watch } from 'vue';
|
||||||
|
// API
|
||||||
|
import { RoleListAll } from "@/api/role";
|
||||||
|
export default {
|
||||||
|
name: "DateComponent",
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
disabled: Boolean
|
||||||
|
},
|
||||||
|
emits: ['update:value', 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const dataa = reactive({
|
||||||
|
value: '',
|
||||||
|
data: props.data
|
||||||
|
})
|
||||||
|
watch(() => props.data, () => {
|
||||||
|
RoleListAll().then(response => {
|
||||||
|
console.log(111)
|
||||||
|
}, {
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const handlerChange = (val) => {
|
||||||
|
emit("update:value", val)
|
||||||
|
emit("callback", {
|
||||||
|
type: 'radio',
|
||||||
|
value: val,
|
||||||
|
formItem: props.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
handlerChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
41
企业级管理系统/前端/项目源码/src/components/control/select/index.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<el-select v-model="value" :disabled="disabled" :style="`width: ${data.width || '100%'}`" @change="handlerChange">
|
||||||
|
<el-option v-for="select in data.options" :key="select.value" :label="select.label" :value="select.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, toRefs } from 'vue';
|
||||||
|
export default {
|
||||||
|
name: "SelectComponent",
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:value', 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const data = reactive({
|
||||||
|
value: '',
|
||||||
|
data: props.data
|
||||||
|
})
|
||||||
|
|
||||||
|
const handlerChange = (val) => {
|
||||||
|
emit("update:value", val)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
handlerChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
80
企业级管理系统/前端/项目源码/src/components/control/switch/index.vue
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<template>
|
||||||
|
<el-switch
|
||||||
|
v-model="init_data.value"
|
||||||
|
:loading="init_data.loading"
|
||||||
|
:before-change="handlerSwitch"
|
||||||
|
>
|
||||||
|
</el-switch>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, getCurrentInstance, watch } from 'vue';
|
||||||
|
// requestUrl
|
||||||
|
import ApiUrl from "@/api/requestUrl";
|
||||||
|
//API
|
||||||
|
import { SwitchStatus } from "@/api/common";
|
||||||
|
export default {
|
||||||
|
name: 'SwitchComponent',
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:value', 'callback'],
|
||||||
|
setup(props){
|
||||||
|
// 配置信息
|
||||||
|
const config = reactive(props.config);
|
||||||
|
// 数据
|
||||||
|
const data = reactive(props.data);
|
||||||
|
// 初始值
|
||||||
|
const init_data = reactive({
|
||||||
|
value: data[config.prop],
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
// 监听数据
|
||||||
|
watch(() => props.data, (newValue, oldValue) => {
|
||||||
|
init_data.value = newValue[config.prop]
|
||||||
|
})
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
// 事件
|
||||||
|
const handlerSwitch = (value) => {
|
||||||
|
init_data.loading = true;
|
||||||
|
// 请求参数
|
||||||
|
const url = config.api_url || ApiUrl?.[config.api_module]?.[config.api_key]?.url;
|
||||||
|
const method = config.method || ApiUrl?.[config.api_module]?.[config.api_key]?.method || "post";
|
||||||
|
if(!url) {
|
||||||
|
console.log("请求接口不存在");
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 请求参数
|
||||||
|
const key_id = config.key_id || 'id'
|
||||||
|
const request_data = {
|
||||||
|
url,
|
||||||
|
method,
|
||||||
|
data: {
|
||||||
|
[key_id]: data[key_id], // 等价于["id"]: data["id"]
|
||||||
|
[config.prop]: !init_data.value // 等价于["status"]: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
SwitchStatus(request_data).then(response => {
|
||||||
|
proxy.$message.success(response.message);
|
||||||
|
data.status = value;
|
||||||
|
init_data.loading = false;
|
||||||
|
resolve(true)
|
||||||
|
}).catch(error => {
|
||||||
|
init_data.loading = false;
|
||||||
|
reject(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return { config, init_data, handlerSwitch }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
44
企业级管理系统/前端/项目源码/src/components/control/textarea/index.vue
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<el-input
|
||||||
|
v-model="value"
|
||||||
|
type="textarea"
|
||||||
|
debounce
|
||||||
|
:rows="data.rows || 5"
|
||||||
|
:disabled="form_disabled[data.prop]"
|
||||||
|
:style="`width: ${data.width || '100%'}`"
|
||||||
|
:placeholder="data.placeholder"
|
||||||
|
@change="handlerChange"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, toRefs } from 'vue';
|
||||||
|
export default {
|
||||||
|
name: "TextareaComponent",
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:value', 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const data = reactive({
|
||||||
|
value: '',
|
||||||
|
data: props.data
|
||||||
|
})
|
||||||
|
|
||||||
|
const handlerChange = (val) => {
|
||||||
|
emit("update:value", val)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
handlerChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
86
企业级管理系统/前端/项目源码/src/components/control/upload/index.vue
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
<template>
|
||||||
|
<el-upload
|
||||||
|
class="avatar-uploader"
|
||||||
|
action="#"
|
||||||
|
:http-request="handlerUpload"
|
||||||
|
:before-upload="handlerBeforeOnUpload"
|
||||||
|
:on-error="handlerOnError"
|
||||||
|
:show-file-list="false"
|
||||||
|
:disabled="disabled"
|
||||||
|
>
|
||||||
|
<img v-if="data.image_url" :src="data.image_url" class="avatar" />
|
||||||
|
<span v-else>+</span>
|
||||||
|
</el-upload>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, getCurrentInstance, watch } from 'vue';
|
||||||
|
import { UploadFile } from "@/api/common";
|
||||||
|
export default {
|
||||||
|
name: "BasisUpload",
|
||||||
|
components: {},
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ["update:value", 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const data = reactive({
|
||||||
|
image_url: ""
|
||||||
|
})
|
||||||
|
const handlerOnError = (res, file) => {}
|
||||||
|
const handlerBeforeOnUpload = async (file) => {
|
||||||
|
const isLt2M = file.size / 1024 / 1024 < 2; // 限制文件大小不能大于 2M
|
||||||
|
if (!isLt2M) {
|
||||||
|
proxy.$message.error("上传图片大小不能超过 2MB!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isJPG && isLt2M;
|
||||||
|
}
|
||||||
|
const handlerUpload = async (params) => {
|
||||||
|
const file = params.file;
|
||||||
|
// 实例化表单对象
|
||||||
|
const form = new FormData();
|
||||||
|
// 表单添加 files 字段
|
||||||
|
form.append("files", file);
|
||||||
|
// 上传接口
|
||||||
|
try{
|
||||||
|
const url = await startUpload(form)
|
||||||
|
data.image_url = url;
|
||||||
|
emit("update:imageUrl", url)
|
||||||
|
}catch{
|
||||||
|
console.log("上传失败")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 开始文件上传
|
||||||
|
*/
|
||||||
|
const startUpload = (form) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
UploadFile(form).then(response => {
|
||||||
|
resolve(response.data.files_path);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
watch(() => props.value, (newValue, oldValue) => {
|
||||||
|
data.image_url = newValue
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
handlerUpload,
|
||||||
|
handlerOnError,
|
||||||
|
handlerBeforeOnUpload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
</style>
|
69
企业级管理系统/前端/项目源码/src/components/control/wangeditor/index.vue
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="editor"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, onMounted, watch, nextTick } from 'vue';
|
||||||
|
import WangEditor from 'wangeditor';
|
||||||
|
// cookies
|
||||||
|
import { getToken } from "@/utils/cookies"; // 这是封装好的方法
|
||||||
|
export default {
|
||||||
|
name: 'Wangeditor',
|
||||||
|
components: {},
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ["update:value", 'callback'],
|
||||||
|
setup(props, { emit }){
|
||||||
|
let html = ref(null)
|
||||||
|
// 内容
|
||||||
|
let content = ref('');
|
||||||
|
// 富文本DOM元素
|
||||||
|
const editor = ref(null);
|
||||||
|
// 富文本对象
|
||||||
|
let editor_instance = null;
|
||||||
|
// 生命周期
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
// 创建富文本对象
|
||||||
|
editor_instance = new WangEditor(editor.value);
|
||||||
|
// 图片上传配置
|
||||||
|
editor_instance.config.uploadImgServer = process.env.VUE_APP_DEV_TARGET + '/upload' // 上传图片的接口地址
|
||||||
|
editor_instance.config.uploadFileName = 'files' // formdata中的name属性
|
||||||
|
editor_instance.config.uploadImgHeaders = {
|
||||||
|
Token: getToken() // 设置请求头
|
||||||
|
}
|
||||||
|
editor_instance.config.uploadImgHooks = {
|
||||||
|
// 图片上传并返回结果,但图片插入错误时触发
|
||||||
|
fail: function (xhr, editor, result) {
|
||||||
|
console.log(result)
|
||||||
|
},
|
||||||
|
// 例如服务器端返回的不是 { errno: 0, data: [...] } 这种格式,可使用 customInsert
|
||||||
|
customInsert: function(insertImgFn, result) {
|
||||||
|
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
|
||||||
|
insertImgFn(result.data.files_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 配置change事件
|
||||||
|
Object.assign(editor_instance.config, {
|
||||||
|
onchange(value) {
|
||||||
|
content.value = value;
|
||||||
|
emit("update:value", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// 创建
|
||||||
|
editor_instance.create();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
watch(() => props.value, (newContent, oldContent) => {
|
||||||
|
editor_instance.txt.html(newContent);
|
||||||
|
})
|
||||||
|
return { editor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
</style>
|
34
企业级管理系统/前端/项目源码/src/components/form/hook/relationHook.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
export function relationHook(){
|
||||||
|
/**
|
||||||
|
* @param { String } value 控制方的选项 value
|
||||||
|
* @param { Array } data 关联关系的数据配置 relation_hidden
|
||||||
|
* @param { Object } props 显示/隐藏对象集保
|
||||||
|
*/
|
||||||
|
const HiddenItem = (value, data, props) => {
|
||||||
|
if(data && Array.isArray(data) && data.length > 0) {
|
||||||
|
data.forEach(item => {
|
||||||
|
const field = item[0];
|
||||||
|
const objValue = item[1];
|
||||||
|
props[field] = objValue[value]
|
||||||
|
// 选项为 1 时
|
||||||
|
// props["title"] = objValue["1"] => true
|
||||||
|
// props["iamge_url"] = objValue["1"] => true
|
||||||
|
// 选项为 0 时
|
||||||
|
// props["title"] = objValue["0"] => true
|
||||||
|
// props["iamge_url"] = objValue["0"] => undefined
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const DisabledItem = (value, data, props) => {
|
||||||
|
if(data && Array.isArray(data) && data.length > 0) {
|
||||||
|
data.forEach(item => {
|
||||||
|
const field = item[0];
|
||||||
|
const objValue = item[1];
|
||||||
|
props[field] = objValue[value]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { HiddenItem, DisabledItem };
|
||||||
|
}
|
88
企业级管理系统/前端/项目源码/src/components/form/hook/rulesHook.js
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { reactive } from "vue";
|
||||||
|
// 验证
|
||||||
|
import { validate_email, validate_password } from "@/utils/validate";
|
||||||
|
/**
|
||||||
|
* @returns BasisForm组件创建校验规则
|
||||||
|
*/
|
||||||
|
export function rulesHook(){
|
||||||
|
/**
|
||||||
|
* @param {*} data 配置额外组件
|
||||||
|
*/
|
||||||
|
const InitRules = (data = []) => {
|
||||||
|
if(data.length === 0) { return false; }
|
||||||
|
// 判断是否有required属性
|
||||||
|
data.forEach(item => {
|
||||||
|
//初始化规则数组
|
||||||
|
let rulesArr = [];
|
||||||
|
if(item.required) {
|
||||||
|
let json = { required: true, message: item.message || messageType(item), trigger: 'change' }
|
||||||
|
rulesArr.push(json)
|
||||||
|
}
|
||||||
|
// 是否有其他的校验规则
|
||||||
|
const rule = item.rule;
|
||||||
|
if(rule && Array.isArray(rule) && rule.length > 0) {
|
||||||
|
rulesArr = rulesArr.concat(rule);
|
||||||
|
}
|
||||||
|
// 用户名
|
||||||
|
if(item.value_type === 'username') {
|
||||||
|
const rule = {
|
||||||
|
validator(rule, value, callback, source, options) {
|
||||||
|
if(!value || value === ""){
|
||||||
|
callback(new Error("请输入用户名"));
|
||||||
|
}else if(!validate_email(value)) {
|
||||||
|
callback(new Error("邮箱格式不正确"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rulesArr = rulesArr.concat(rule);
|
||||||
|
}
|
||||||
|
// 密码
|
||||||
|
if(item.value_type === 'password') {
|
||||||
|
const rule = {
|
||||||
|
validator(rule, value, callback, source, options) {
|
||||||
|
if(!value || value === ""){
|
||||||
|
callback(new Error("请输入用密码"));
|
||||||
|
}else if(!validate_password(value)) {
|
||||||
|
callback(new Error("请输入>=6并且<=20位的密码,包含数字、字母"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rulesArr = rulesArr.concat(rule);
|
||||||
|
}
|
||||||
|
// 定义rules属性赋值
|
||||||
|
item.rules = rulesArr;
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @description 提示文本
|
||||||
|
*/
|
||||||
|
const messageType = (data) => {
|
||||||
|
let msg = "";
|
||||||
|
switch(data.type){
|
||||||
|
case "input":
|
||||||
|
case "wangeditor":
|
||||||
|
msg = "请输入";
|
||||||
|
break;
|
||||||
|
case "upload":
|
||||||
|
msg = "请上传";
|
||||||
|
break;
|
||||||
|
case "radio":
|
||||||
|
case "checkbox":
|
||||||
|
case "select":
|
||||||
|
case "date":
|
||||||
|
case "cascader":
|
||||||
|
msg = "请选择";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
msg = "未定义";
|
||||||
|
}
|
||||||
|
return `${msg}${data.label}`;
|
||||||
|
}
|
||||||
|
return { InitRules };
|
||||||
|
}
|
128
企业级管理系统/前端/项目源码/src/components/form/index.vue
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<template>
|
||||||
|
<el-form ref="formDom" v-loading="loading" element-loading-text="加载中,请稍候" :label-width="label_width" :model="field">
|
||||||
|
<el-row>
|
||||||
|
<template v-for="item in form_item" :key="item.prop">
|
||||||
|
<el-col v-if="!form_hidden[item.prop]" :span="item.col || 24">
|
||||||
|
<el-form-item v-if="item.type !== 'slot'" :label="item.label" :prop="item.prop" :rules="item.rules">
|
||||||
|
<component
|
||||||
|
v-model:value="field[item.prop]"
|
||||||
|
:is="item.type + 'Component'"
|
||||||
|
:data="item"
|
||||||
|
:disabled="disabled[item.prop]"
|
||||||
|
@callback="componentCallback"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-else :label="item.label" :prop="item.prop" :rules="item.rules">
|
||||||
|
<slot :name="item.slot_name"></slot>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
</el-row>
|
||||||
|
<!-- button -->
|
||||||
|
<el-form-item v-if="form_button && form_button.length > 0">
|
||||||
|
<el-button
|
||||||
|
v-for="item in form_button"
|
||||||
|
:key="item.key"
|
||||||
|
:type="item.type"
|
||||||
|
@click="item.callback ? item.callback() : handlerFormActive(item)"
|
||||||
|
>
|
||||||
|
{{ item.label }}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
// hook
|
||||||
|
import { rulesHook } from "./hook/rulesHook";
|
||||||
|
import { relationHook } from "./hook/relationHook";
|
||||||
|
// require import components
|
||||||
|
const files = require.context('@c/control', true, /\index.vue$/);
|
||||||
|
const modules = {}
|
||||||
|
files.keys().forEach(key => {
|
||||||
|
const name = key.split("/")
|
||||||
|
modules[name[1]+'Component'] = files(key).default || files(key)
|
||||||
|
})
|
||||||
|
export default {
|
||||||
|
name: 'BasisForm',
|
||||||
|
components: modules,
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
labelWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: "100px"
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
hidden: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
hidden: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ["callback"],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const { InitRules } = rulesHook();
|
||||||
|
const { HiddenItem, DisabledItem } = relationHook();
|
||||||
|
// 校验规则处理
|
||||||
|
const form_item = reactive(InitRules(props.item));
|
||||||
|
const label_width = ref(props.labelWidth);
|
||||||
|
const form_button = reactive(props.button);
|
||||||
|
const form_hidden = reactive(props.hidden);
|
||||||
|
const form_disabled = reactive(props.disabled);
|
||||||
|
// 表单提交验证
|
||||||
|
const formDom = ref(null);
|
||||||
|
// form表单动作
|
||||||
|
const handlerFormActive = (data) => {
|
||||||
|
// 提交表单事件
|
||||||
|
if(data.key === 'submit') {
|
||||||
|
formDom.value.validate((valid) => valid && emit("callback"));
|
||||||
|
}
|
||||||
|
// 重置表单事件
|
||||||
|
if(data.key === 'reset') { handlerFormReset(); }
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 重置表单
|
||||||
|
*/
|
||||||
|
const handlerFormReset = () => {
|
||||||
|
formDom.value.resetFields();
|
||||||
|
}
|
||||||
|
// change 事件
|
||||||
|
const componentCallback = (params) => {
|
||||||
|
if(params.formItem.relation_hidden) {
|
||||||
|
HiddenItem(params.value, params.formItem.relation_hidden, form_hidden)
|
||||||
|
}
|
||||||
|
if(params.formItem.relation_disabled) {
|
||||||
|
DisabledItem(params.value, params.formItem.relation_hidden, form_disabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { formDom, form_item, label_width, form_button, form_hidden, form_disabled, formDom, handlerFormActive, componentCallback, handlerFormReset }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
69
企业级管理系统/前端/项目源码/src/components/pagination/index.vue
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<el-pagination
|
||||||
|
class="pull-right"
|
||||||
|
sizs="small"
|
||||||
|
background
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
v-model:current-page="current_page"
|
||||||
|
:page-size="10"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="total">
|
||||||
|
</el-pagination>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, watchEffect, watch } from 'vue';
|
||||||
|
export default {
|
||||||
|
name: 'Pagination',
|
||||||
|
props: {
|
||||||
|
total: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
current: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
flag: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ["sizeChange", "currentChange", "update:flag"],
|
||||||
|
setup(props, { emit }){
|
||||||
|
// 当前页码
|
||||||
|
const current_page = ref(1);
|
||||||
|
// 总条数统计
|
||||||
|
const total = ref(props.total);
|
||||||
|
const page_status = ref(false);
|
||||||
|
// 监听props.total发生变化时更新total
|
||||||
|
watchEffect(() => {
|
||||||
|
total.value = props.total;
|
||||||
|
current_page.value = props.current;
|
||||||
|
})
|
||||||
|
watch(() => props.flag, (newValue) => {
|
||||||
|
page_status.value = newValue
|
||||||
|
})
|
||||||
|
// 页码事件
|
||||||
|
const handleSizeChange = (val) => {
|
||||||
|
page_status.value = true
|
||||||
|
emit("update:flag", true)
|
||||||
|
const params = {
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: val
|
||||||
|
}
|
||||||
|
emit("sizeChange", params, 'page')
|
||||||
|
}
|
||||||
|
const handleCurrentChange = (val) => {
|
||||||
|
if(page_status.value) { return false }
|
||||||
|
const params = {
|
||||||
|
pageNumber: val
|
||||||
|
}
|
||||||
|
emit("currentChange", params, 'page')
|
||||||
|
}
|
||||||
|
return { total, current_page, handleSizeChange, handleCurrentChange }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
130
企业级管理系统/前端/项目源码/src/components/search/index.vue
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="button_group.length > 0" class="form-search-button-group">
|
||||||
|
<el-button v-for="item in button_group" :key="item.id" :type="item.type" @click="item.callback && item.callback()">{{ item.label }}</el-button>
|
||||||
|
</div>
|
||||||
|
<el-form ref="searchForm" inline :label-width="label_width" :model="field">
|
||||||
|
<template v-if="form_item && form_item.length > 0">
|
||||||
|
<el-form-item v-for="item in form_item" :key="item.prop" :label="item.label" :prop="item.prop" :label-width="item.label_width || label_width">
|
||||||
|
<component :ref="componentDom" :key="item.type" v-model:value="field[item.prop]" :is="item.type + 'Component'" :data="item" @callback="componentCallback" />
|
||||||
|
</el-form-item>
|
||||||
|
<!-- button -->
|
||||||
|
<el-form-item>
|
||||||
|
<div class="pull-right">
|
||||||
|
<el-button type="danger" @click="handlerSearch">搜索</el-button>
|
||||||
|
<el-button v-if="button.reset_button" @click="handlerReset">重置</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, ref, inject, toRefs, nextTick } from 'vue';
|
||||||
|
// require import components
|
||||||
|
const files = require.context('@c/control', true, /\index.vue$/);
|
||||||
|
const modules = {}
|
||||||
|
files.keys().forEach(key => {
|
||||||
|
const name = key.split("/")
|
||||||
|
modules[name[1]+'Component'] = files(key).default || files(key)
|
||||||
|
})
|
||||||
|
export default {
|
||||||
|
name: 'BasisForm',
|
||||||
|
components: modules,
|
||||||
|
props: {
|
||||||
|
item: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
labelWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: "100px"
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
button_group: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
button_col: {
|
||||||
|
type: Number,
|
||||||
|
default: 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ["callbackSearch"],
|
||||||
|
setup(props, { emit }){
|
||||||
|
const data = reactive({ key: "", value: "" });
|
||||||
|
// 获取父组件provide数据
|
||||||
|
const search_config = inject("search_config");
|
||||||
|
// label占位宽度
|
||||||
|
const label_width = ref(search_config?.label_width || props.labelWidth);
|
||||||
|
// 组件元素配置
|
||||||
|
const form_item = reactive(search_config?.form_item || props.item);
|
||||||
|
// 字段配置
|
||||||
|
const field = reactive(search_config?.form_data || props.field);
|
||||||
|
// 按钮配置
|
||||||
|
const button = reactive(search_config?.form_button || props.button);
|
||||||
|
// 按钮组配置
|
||||||
|
const button_group = reactive(search_config?.form_button_group || props.button_group);
|
||||||
|
// 按钮占位 col
|
||||||
|
const button_col = reactive(search_config?.button_col || props.button_col);
|
||||||
|
/**
|
||||||
|
* 获取动态组件的dom
|
||||||
|
*/
|
||||||
|
const keyword = ref(null)
|
||||||
|
const componentDom = el => {
|
||||||
|
console.log(el)
|
||||||
|
if(el && el.data.type === 'keyword') {
|
||||||
|
keyword.value = el
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 搜索
|
||||||
|
const handlerSearch = () => {
|
||||||
|
const data = formatRequest();
|
||||||
|
// 回调父组件方法
|
||||||
|
emit("callbackSearch", data, "search");
|
||||||
|
}
|
||||||
|
// 重置
|
||||||
|
const searchForm = ref(null);
|
||||||
|
const handlerReset = () => {
|
||||||
|
searchForm.value.resetFields();
|
||||||
|
// 调用关键字组件的clear方法
|
||||||
|
keyword.value && keyword.value.handlerClear()
|
||||||
|
emit("callbackSearch", {}, "search");
|
||||||
|
}
|
||||||
|
/** 参数格式化 */
|
||||||
|
const formatRequest = () => {
|
||||||
|
// 声明空的JSON对象临时存储数据
|
||||||
|
const request_data = {};
|
||||||
|
// 过滤在值存在的数据
|
||||||
|
for(let key in field) {
|
||||||
|
if(field[key] !== "") { request_data[key] = field[key]; }
|
||||||
|
}
|
||||||
|
// 判断关键字下拉选择是否有值存在
|
||||||
|
if(data.key && data.value) { request_data[data.key] = data.value; }
|
||||||
|
// 返回参数
|
||||||
|
return request_data;
|
||||||
|
}
|
||||||
|
// 回调
|
||||||
|
const componentCallback = (params) => {
|
||||||
|
if(params.type === 'keyword') {
|
||||||
|
data.key = params.value.key
|
||||||
|
data.value = params.value.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
form_item, field, label_width, button, componentCallback, handlerSearch, handlerReset, componentDom, searchForm, button_group, button_col
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.form-search-button-group { margin-bottom: 20px; }
|
||||||
|
</style>
|
38
企业级管理系统/前端/项目源码/src/components/svgIcon/Index.vue
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<template>
|
||||||
|
<svg class="svg-class" :class="svgClassName">
|
||||||
|
<use :href="svgIcon"></use>
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { ref, computed } from "vue";
|
||||||
|
export default {
|
||||||
|
name: "SvgIcon",
|
||||||
|
props: {
|
||||||
|
iconName: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props){
|
||||||
|
// className
|
||||||
|
const svgClassName = ref(props.className);
|
||||||
|
// svg 图标
|
||||||
|
const svgIcon = computed(() => `#icon-${props.iconName}`);
|
||||||
|
return {
|
||||||
|
svgClassName,
|
||||||
|
svgIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.svg-class {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
</style>
|
1
企业级管理系统/前端/项目源码/src/components/svgIcon/icon/home.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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="1608734152787" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1160" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M959.390493 527.761985c0 23.127743-18.419512 41.87369-41.138956 41.87369-12.335956 0-23.276123-5.640464-30.817889-14.393825L541.089525 202.729238c-16.065907-16.353456-42.113143-16.353456-58.179051 0L237.802034 452.204126c2.877537 5.636371 4.653997 11.926634 4.653997 18.690688l0 165.475775c0 0.328481-0.089028 0.635473-0.097214 0.961908l0.297782 0 0 163.003468c0 23.125697 18.506493 41.871643 41.337477 41.871643l82.568531 0L366.562607 677.738765c0-22.850427 18.520819-41.3692 41.3692-41.3692L614.775758 636.369565c22.848381 0 41.3692 18.518772 41.3692 41.3692 0 22.846334-18.520819 41.3692-41.3692 41.3692L449.299983 719.107965l0 165.473729c0 22.427802-17.875113 40.583301-40.142256 41.246403l0 0.121773L263.148305 925.94987c-57.115835 0-103.418394-46.864354-103.418394-104.678084L159.729911 637.331473l0.084934 0c-0.00614-0.326435-0.097214-0.633427-0.097214-0.961908L159.717631 531.680225l-23.162536 23.575952c-7.541767 8.745175-18.475793 14.379499-30.807656 14.379499-22.719444 0-41.138956-18.745946-41.138956-41.87369 0-11.862165 4.895497-22.520923 12.687974-30.141484l-0.237407-0.2415 362.215602-368.668571c40.164768-40.881083 105.285928-40.881083 145.450696 0l361.569896 368.010585-0.299829 0.305969C954.175725 504.680291 959.390493 515.563152 959.390493 527.761985zM614.733802 842.206584c0.443092 0 0.854461 0.119727 1.294482 0.132006l0-0.132006 122.683157 0c22.828938 0 41.337477-18.745946 41.337477-41.871643L780.048919 637.331473l0.534166 0c-0.016373-0.496304-0.145309-0.961908-0.145309-1.464351 0-23.125697 18.417465-41.87369 41.138956-41.87369 22.719444 0 41.136909 18.747993 41.136909 41.87369 0 0.502443-0.125867 0.968048-0.145309 1.464351l0.405229 0 0 183.940312c0 57.812707-46.299489 104.678084-103.418394 104.678084l-143.528927 0 0-0.132006c-0.441045 0.014326-0.852414 0.132006-1.294482 0.132006-22.719444 0-41.138956-18.7439-41.138956-41.869596C573.594847 860.9556 592.014358 842.206584 614.733802 842.206584z" p-id="1161"></path></svg>
|
After Width: | Height: | Size: 2.3 KiB |
@ -0,0 +1 @@
|
|||||||
|
<?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="1608736466130" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="791" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M782.27531852 936.77037037H241.72468148c-60.19602963 0-109.22666667-49.03063703-109.22666666-109.22666667V196.4562963c0-60.19602963 49.03063703-109.22666667 109.22666666-109.22666667h540.55063704c60.19602963 0 109.22666667 49.03063703 109.22666666 109.22666667v631.0874074c0 60.19602963-49.03063703 109.22666667-109.22666666 109.22666667zM241.72468148 160.04740741c-20.02488889 0-36.40888889 16.384-36.40888889 36.40888889v631.0874074c0 20.02488889 16.384 36.40888889 36.40888889 36.40888889h540.55063704c20.02488889 0 36.40888889-16.384 36.40888889-36.40888889V196.4562963c0-20.02488889-16.384-36.40888889-36.40888889-36.40888889H241.72468148z" p-id="792"></path><path d="M747.44414815 343.30548148H271.70133333c-20.14625185 0-36.40888889-16.26263703-36.40888888-36.40888889s16.26263703-36.40888889 36.40888888-36.40888889h475.74281482c20.14625185 0 36.40888889 16.26263703 36.40888888 36.40888889s-16.26263703 36.40888889-36.40888888 36.40888889zM747.44414815 497.43644445H271.70133333c-20.14625185 0-36.40888889-16.26263703-36.40888888-36.4088889s16.26263703-36.40888889 36.40888888-36.40888888h475.74281482c20.14625185 0 36.40888889 16.26263703 36.40888888 36.40888888s-16.26263703 36.40888889-36.40888888 36.4088889zM554.47703703 653.99466667H271.70133333c-20.14625185 0-36.40888889-16.26263703-36.40888888-36.40888889s16.26263703-36.40888889 36.40888888-36.40888889h282.7757037c20.14625185 0 36.40888889 16.26263703 36.40888889 36.40888889s-16.26263703 36.40888889-36.40888889 36.40888889z" p-id="793"></path></svg>
|
After Width: | Height: | Size: 1.9 KiB |
1
企业级管理系统/前端/项目源码/src/components/svgIcon/icon/logout.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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="1621589152962" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2857" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M706.432 195.136c-14.656-9.536-34.56-5.44-44.224 9.408-9.536 14.848-5.376 34.688 9.472 44.288C772.032 314.048 832 424.448 832 544.192c0 193.92-157.504 351.68-351.04 351.68s-351.04-157.76-351.04-351.68c0-119.68 60.032-230.144 160.448-295.296 14.848-9.6 19.072-29.504 9.472-44.352C290.112 189.632 270.336 185.408 255.552 195.072 136.768 272.192 65.856 402.688 65.856 544.192 65.856 773.504 252.032 960 480.96 960S896 773.504 896 544.192C896 402.624 825.152 272.128 706.432 195.136zM480.96 572.16c17.664 0 32-14.656 32-32.832l0-380.8c0-18.112-14.336-32.768-32-32.768s-32 14.656-32 32.768l0 380.8C448.96 557.504 463.232 572.16 480.96 572.16z" p-id="2858"></path></svg>
|
After Width: | Height: | Size: 1.0 KiB |
1
企业级管理系统/前端/项目源码/src/components/svgIcon/icon/menuBtn.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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="1621586114074" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2473" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><defs><style type="text/css"></style></defs><path d="M980.8 468.8H43.2C17.6 468.8 0 486.4 0 512s17.6 43.2 43.2 43.2h939.2c25.6 0 43.2-17.6 43.2-43.2-1.6-25.6-19.2-43.2-44.8-43.2zM980.8 768H43.2C17.6 768 0 785.6 0 811.2s17.6 43.2 43.2 43.2h939.2c25.6 0 43.2-17.6 43.2-43.2-1.6-25.6-19.2-43.2-44.8-43.2zM43.2 256h939.2c25.6 0 43.2-17.6 43.2-43.2s-17.6-43.2-43.2-43.2H43.2c-25.6 0-43.2 17.6-43.2 43.2S17.6 256 43.2 256z" p-id="2474"></path></svg>
|
After Width: | Height: | Size: 775 B |
2
企业级管理系统/前端/项目源码/src/components/svgIcon/icon/system.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?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="1627108347577" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4935" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.eot?#iefix") format("embedded-opentype"), url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.woff2") format("woff2"), url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.woff") format("woff"), url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.ttf") format("truetype"), url("//at.alicdn.com/t/font_1031158_1uhr8ri0pk5.svg#iconfont") format("svg"); }
|
||||||
|
</style></defs><path d="M660.750044 997.266537c-14.811783 0-29.804198-5.418945-40.461457-15.173046-15.714941-14.45052-69.181866-55.995766-107.114482-55.995767-38.293879 0-91.580173 41.545246-107.114482 55.995767-16.256835 15.173046-42.809667 19.688834-63.221027 10.657259l-3.070736-1.445052-153.898042-89.231964c-17.701887-13.1861-27.094726-38.47451-22.217675-59.969659 4.696419-20.772623 13.908626-87.786911-5.057682-120.661845-18.966308-32.874934-81.64544-58.343976-102.0568-64.846711-20.41136-6.322103-37.932616-26.191568-41.545246-47.325454-0.361263-2.167578-9.212207-54.370083-9.212207-92.663962 0-38.293879 8.850944-90.315752 9.212207-92.663962 3.61263-21.133886 21.133886-41.003352 41.545246-47.325454s83.090492-31.791145 102.0568-64.84671c19.146939-33.055565 9.934733-99.889222 5.057682-120.661845-4.877051-21.675781 4.335156-46.78356 22.217675-59.96966l2.890104-1.986946 153.898042-88.8707c20.41136-9.031575 46.964191-4.515788 63.221027 10.657258 15.714941 14.45052 69.181866 55.995766 107.114482 55.995767 38.293879 0 91.580173-41.545246 107.114483-55.995767 16.256835-15.173046 42.809667-19.688834 63.221026-10.657258l3.070736 1.445052 153.898042 89.231963c17.701887 13.1861 27.094726 38.47451 22.217675 59.969659-4.696419 20.772623-13.908626 87.786911 5.057682 120.661846 18.966308 32.874934 81.64544 58.343976 102.0568 64.84671 20.41136 6.322103 37.932616 26.191568 41.545246 47.325454 0.361263 2.167578 9.212207 54.370083 9.212207 92.663962 0 38.293879-8.850944 90.315752-9.212207 92.663962-3.61263 21.133886-21.133886 41.003352-41.545246 47.325454s-83.090492 31.791145-102.0568 64.84671c-19.146939 33.055565-9.934733 99.889222-5.057682 120.661845 4.877051 21.495149-4.335156 46.78356-22.217675 59.96966l-2.890104 1.986946-153.898042 88.870701c-7.22526 2.890104-14.992415 4.515788-22.75957 4.515787zM225.247486 852.580702l140.531311 81.284177c15.353678-13.727994 82.548598-70.626918 147.214676-70.626918s131.860998 56.718292 147.214677 70.626918l140.53131-81.284177c-4.154525-19.869466-19.869466-106.572588 12.644206-162.748986 33.416828-57.982713 120.661845-87.786911 136.376786-92.844593 1.445052-8.489681 8.128418-50.938084 8.128417-80.561651 0-29.623567-6.683366-72.07197-8.128417-80.561651-15.714941-5.057682-102.959958-34.86188-136.376786-92.844594-32.333039-56.176398-16.79873-142.87952-12.644206-162.748985l-140.53131-81.284177c-15.353678 13.727994-82.548598 70.626918-147.214677 70.626918-64.84671 0-131.860998-56.718292-147.214676-70.626918l-140.531311 81.284177c4.154525 19.869466 19.869466 106.572588-12.644205 162.748985-33.416828 57.982713-120.661845 87.786911-136.376786 92.844594-1.445052 8.489681-8.128418 50.938084-8.128418 80.561651 0 29.623567 6.683366 72.07197 8.128418 80.561651 15.714941 5.057682 102.959958 34.86188 136.376786 92.844593 32.333039 56.176398 16.79873 142.87952 12.644205 162.748986z" p-id="4936"></path><path d="M512.993473 729.751279c-117.59111 0-213.145176-95.734697-213.145175-213.325807s95.734697-213.325807 213.325807-213.325807 213.145176 95.734697 213.145175 213.325807S630.584583 729.751279 512.993473 729.751279z m0-363.972482c-83.090492 0-150.646675 67.556183-150.646675 150.646675s67.556183 150.646675 150.646675 150.646675c83.090492 0 150.646675-67.556183 150.646675-150.646675S596.083965 365.778797 512.993473 365.778797z" p-id="4937"></path></svg>
|
After Width: | Height: | Size: 4.0 KiB |
1
企业级管理系统/前端/项目源码/src/components/svgIcon/icon/user.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?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="1608814595533" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="809" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512 962C263.4875 962 62 760.5125 62 512S263.4875 62 512 62s450 201.4875 450 450-201.4875 450-450 450z m0-825.00000029C304.8875 136.99999971 136.99999971 304.8875 136.99999971 512s167.88750029 375.00000029 375.00000029 375.00000029 375.00000029-167.88750029 375.00000029-375.00000029S719.1125 136.99999971 512 136.99999971z m0 675a299.40000029 299.40000029 0 0 1-234-112.5A299.40000029 299.40000029 0 0 1 512 586.99999971a299.25 299.25 0 0 1 233.96249971 112.5A299.25 299.25 0 0 1 512 811.99999971z m0-262.49999942a150.00000029 150.00000029 0 1 1 0-300.00000058 150.00000029 150.00000029 0 0 1 0 300.00000058z" p-id="810"></path></svg>
|
After Width: | Height: | Size: 1011 B |
7
企业级管理系统/前端/项目源码/src/components/svgIcon/svg.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// 获取当前svg目录所有为.svg结尾的文件
|
||||||
|
const context = require.context('./icon', false, /\.svg$/);
|
||||||
|
// 解析获取的.svg文件的文件名称,并返回
|
||||||
|
const requireAll = (requireContext) => {
|
||||||
|
return requireContext.keys().map(requireContext);
|
||||||
|
};
|
||||||
|
requireAll(context);
|
67
企业级管理系统/前端/项目源码/src/components/switch/index.vue
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<el-switch
|
||||||
|
v-model="init_data.value"
|
||||||
|
:loading="init_data.loading"
|
||||||
|
@change="handlerSwitch($event)"
|
||||||
|
>
|
||||||
|
</el-switch>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, getCurrentInstance } from 'vue';
|
||||||
|
// requestUrl
|
||||||
|
import ApiUrl from "@/api/requestUrl";
|
||||||
|
//API
|
||||||
|
import { SwitchStatus } from "@/api/common";
|
||||||
|
export default {
|
||||||
|
name: 'SwitchComponent',
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props){
|
||||||
|
// 配置信息
|
||||||
|
const config = reactive(props.config);
|
||||||
|
// 数据
|
||||||
|
const data = reactive(props.data);
|
||||||
|
// 初始值
|
||||||
|
const init_data = reactive({
|
||||||
|
value: data[config.prop],
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
// 事件
|
||||||
|
const handlerSwitch = (value) => {
|
||||||
|
// 请求参数
|
||||||
|
const key_id = config.key_id;
|
||||||
|
if(!key_id) { return false; }
|
||||||
|
init_data.loading = true;
|
||||||
|
// 参数
|
||||||
|
const request_data = {
|
||||||
|
url: config.api_url || ApiUrl[config.api_module][config.api_module_key],
|
||||||
|
method: config.method || "post",
|
||||||
|
data: {
|
||||||
|
[key_id]: data[key_id], // 等价于["id"]: data["id"]
|
||||||
|
[config.prop]: value // 等价于["status"]: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 接口请求
|
||||||
|
SwitchStatus(request_data).then(response => {
|
||||||
|
proxy.$message.success(response.message);
|
||||||
|
init_data.value = value;
|
||||||
|
init_data.loading = false;
|
||||||
|
}).catch(error => {
|
||||||
|
init_data.loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return { config, init_data, handlerSwitch }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
39
企业级管理系统/前端/项目源码/src/components/table/configHook.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { reactive } from "vue";
|
||||||
|
/**
|
||||||
|
* BasisTable组件默认配置
|
||||||
|
* @param { Boolean } selection 多选项配置
|
||||||
|
* @param { Boolean } batch_delete 指量删除按钮
|
||||||
|
* @param { Boolean } pagination 分页
|
||||||
|
*/
|
||||||
|
export function configHook(){
|
||||||
|
const config = reactive({
|
||||||
|
selection: true,
|
||||||
|
batch_delete: true,
|
||||||
|
pagination: true,
|
||||||
|
request: true,
|
||||||
|
search: true,
|
||||||
|
action_request: false,
|
||||||
|
row_key: "id",
|
||||||
|
expand_all: true,
|
||||||
|
has_button_delete: "",
|
||||||
|
has_button_batch_delete: ""
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} data 配置额外组件,true显示,false不显示
|
||||||
|
*/
|
||||||
|
const configInit = (data = {}) => {
|
||||||
|
// 无数据时不执行
|
||||||
|
if(JSON.stringify(data) === "{}") { return false; }
|
||||||
|
// 获取默认配置项的所有key
|
||||||
|
const keys = Object.keys(config);
|
||||||
|
// 循环传入的配置项
|
||||||
|
for(let key in data) {
|
||||||
|
// 过滤原型链的对象
|
||||||
|
if (!data.hasOwnProperty(key)) { continue; }
|
||||||
|
// ES6语法判断传入的key和默认配置的key相同时,则直接更新默认配置项的值
|
||||||
|
if(keys.includes(key)) { config[key] = data[key]; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { config, configInit };
|
||||||
|
}
|
121
企业级管理系统/前端/项目源码/src/components/table/index.vue
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<template>
|
||||||
|
<SearchForm v-if="config.search" @callbackSearch="getList" />
|
||||||
|
<el-table :row-key="config.row_key" :default-expand-all="config.expand_all" :data="table_data.data" v-loading="table_data.loading" element-loading-text="加载中,请稍候" border style="width: 100%" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column v-if="config.selection" type="selection" width="40"></el-table-column>
|
||||||
|
<template v-for="header in data.render_header" :key="header.prop">
|
||||||
|
<!-- switch -->
|
||||||
|
<el-table-column v-if="header.type === 'switch'" :label="header.label" :width="header.width">
|
||||||
|
<template #default="scope">
|
||||||
|
<Switch :data="scope.row" :config="header" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- function -->
|
||||||
|
<el-table-column v-else-if="header.type === 'function'" :label="header.label" :width="header.width">
|
||||||
|
<template #default="scope">
|
||||||
|
<div v-html="header.callback && header.callback(scope.row)"></div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- slot -->
|
||||||
|
<el-table-column v-else-if="header.type === 'slot'" :label="header.label" :width="header.width">
|
||||||
|
<template #default="scope">
|
||||||
|
<slot :name="header.slot_name" :data="scope.row"></slot>
|
||||||
|
<el-button v-if="header.delete_elem" @click="handlerDelete('delete', scope.row)" v-has-button="config.has_button_delete">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<!-- text -->
|
||||||
|
<el-table-column v-else :prop="header.prop" :label="header.label" :width="header.width"></el-table-column>
|
||||||
|
</template>
|
||||||
|
</el-table>
|
||||||
|
<el-row class="margin-top-20">
|
||||||
|
<el-col :span="6">
|
||||||
|
<el-button v-if="config.batch_delete" :disabled="!table_data.data_id" @click="handlerDelete('batch')" v-has-button="config.has_button_batch_delete">批量删除</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="18">
|
||||||
|
<Pagination
|
||||||
|
v-if="config.pagination"
|
||||||
|
@sizeChange="getList"
|
||||||
|
@currentChange="getList"
|
||||||
|
:total="table_data.total"
|
||||||
|
:current="table_data.current_page" />
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, getCurrentInstance, onBeforeMount, watch } from 'vue';
|
||||||
|
// store
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
// components
|
||||||
|
import SearchForm from "@c/search";
|
||||||
|
import Pagination from "@c/pagination";
|
||||||
|
import Switch from "@c/control/switch";
|
||||||
|
// hook
|
||||||
|
import { configHook } from "./configHook";
|
||||||
|
import { requestHook } from "./requestHook";
|
||||||
|
export default {
|
||||||
|
name: 'TableComponents',
|
||||||
|
components: { Pagination, Switch, SearchForm },
|
||||||
|
props: {
|
||||||
|
columns: {
|
||||||
|
type: Array,
|
||||||
|
default: () => ([])
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
search: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ["onload"],
|
||||||
|
setup(props, { emit }){
|
||||||
|
// store
|
||||||
|
const store = useStore();
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const { config, configInit } = configHook();
|
||||||
|
const { requestData, table_data, handlerDeleteComfirm, saveDataId } = requestHook();
|
||||||
|
const data = reactive({
|
||||||
|
table_data: [],
|
||||||
|
render_header: props.columns,
|
||||||
|
row_data_id: [],
|
||||||
|
currentPage: 0,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
onBeforeMount(() => {
|
||||||
|
// 默认配置项处理
|
||||||
|
configInit(props.config);
|
||||||
|
// 请求数据
|
||||||
|
getList(props.request)
|
||||||
|
})
|
||||||
|
|
||||||
|
const getList = (params, type) => {
|
||||||
|
requestData(params, type).then(response => {
|
||||||
|
emit("onload", table_data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 删除动作 */
|
||||||
|
const handlerDelete = (type, val) => {
|
||||||
|
if(type === "delete") { saveDataId(val); }
|
||||||
|
handlerDeleteComfirm();
|
||||||
|
}
|
||||||
|
/** 复选框事件 */
|
||||||
|
const handleSelectionChange = (val) => {
|
||||||
|
saveDataId(val);
|
||||||
|
}
|
||||||
|
watch(() => store.state.app.table_action_request, () => {
|
||||||
|
config.action_request && getList();
|
||||||
|
})
|
||||||
|
return { data, config, table_data, requestData, getList, handlerDelete, handleSelectionChange }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
.margin-top-20 { margin-top: 20px; }
|
||||||
|
</style>
|
154
企业级管理系统/前端/项目源码/src/components/table/requestHook.js
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import { reactive, getCurrentInstance } from "vue";
|
||||||
|
// requestUrl
|
||||||
|
import ApiUrl from "@/api/requestUrl";
|
||||||
|
// API
|
||||||
|
import { TableData, CommonApi } from "@/api/common";
|
||||||
|
import { configHook } from "./configHook";
|
||||||
|
import { ElMessage } from "element-plus"
|
||||||
|
export function requestHook(){
|
||||||
|
const { config, configInit } = configHook();
|
||||||
|
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
let request_config = {
|
||||||
|
has: true, // 是否请求
|
||||||
|
url: "", // 请求模块
|
||||||
|
method: "post", // 请求类型
|
||||||
|
data: {}, // 请求参数
|
||||||
|
delete_key: '', // 删除接口的KEY
|
||||||
|
search_params: {}
|
||||||
|
}
|
||||||
|
const table_data = reactive({
|
||||||
|
data: [],
|
||||||
|
data_id: "",
|
||||||
|
current_page: 0,
|
||||||
|
total: 0,
|
||||||
|
loading: false
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* @returns 列表数据请求
|
||||||
|
*/
|
||||||
|
const loadData = () => {
|
||||||
|
// 判断条件是否请求接口
|
||||||
|
if(!request_config.has) { return false; }
|
||||||
|
if(!request_config.url) { return false; }
|
||||||
|
// 参数
|
||||||
|
const url = ApiUrl[request_config.url]?.list?.url;
|
||||||
|
const method = ApiUrl[request_config.url]?.list?.method || 'post';
|
||||||
|
const data = { ...request_config.data, ...request_config.search_params };
|
||||||
|
if(!url) {
|
||||||
|
console.log("请求地址不存在");
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
const request_data = {
|
||||||
|
url,
|
||||||
|
method,
|
||||||
|
data
|
||||||
|
}
|
||||||
|
// 加载状态
|
||||||
|
table_data.loading = true;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
TableData(request_data).then(response => {
|
||||||
|
|
||||||
|
let response_data = response.data.data;
|
||||||
|
// 是否格式化数据
|
||||||
|
if(request_config.format_data && Object.prototype.toString.call(request_config.format_data) === "[object Function]") {
|
||||||
|
response_data = request_config.format_data(response.data.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(response_data)
|
||||||
|
|
||||||
|
table_data.data = response_data;
|
||||||
|
table_data.total = response.data.total;
|
||||||
|
table_data.current_page = response.data.current_page;
|
||||||
|
// 取消加载状态
|
||||||
|
table_data.loading = false;
|
||||||
|
resolve(response.data);
|
||||||
|
}).catch(error => {
|
||||||
|
reject()
|
||||||
|
// 取消加载状态
|
||||||
|
table_data.loading = false;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const requestData = (data = {}, type = 'init') => {
|
||||||
|
// 初始化逻辑
|
||||||
|
if(type === "init") {
|
||||||
|
request_config = {...request_config, ...data};
|
||||||
|
}
|
||||||
|
// 分页逻辑
|
||||||
|
if(type === 'page') {
|
||||||
|
request_config.data = {...request_config.data, ...data};
|
||||||
|
}
|
||||||
|
// 搜索
|
||||||
|
if(type === "search"){
|
||||||
|
request_config.data.pageNumber = 1;
|
||||||
|
request_config.data.pageSize = 10;
|
||||||
|
request_config.search_params = data;
|
||||||
|
}
|
||||||
|
// 请求数据
|
||||||
|
return loadData();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Object} data
|
||||||
|
* @description 手动请求
|
||||||
|
*/
|
||||||
|
const handlerRequestData = (data = {}) => {
|
||||||
|
table_data.params_data = data;
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param { String、Array } value
|
||||||
|
* @description 存储数据ID,作用于删除接口使用
|
||||||
|
* 删除接口
|
||||||
|
*/
|
||||||
|
const saveDataId = (value) => {
|
||||||
|
const isArray = Array.isArray(value);
|
||||||
|
if(!isArray) {
|
||||||
|
table_data.data_id = value[request_config.delete_key];
|
||||||
|
}else{
|
||||||
|
table_data.data_id = value.length > 0 ? value.map(item => item[request_config.delete_key]).join() : "";
|
||||||
|
}
|
||||||
|
console.log(table_data.data_id)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @description 删除动作的确认弹窗
|
||||||
|
*/
|
||||||
|
const handlerDeleteComfirm = () => {
|
||||||
|
proxy.deleteConfirm({
|
||||||
|
title: "删除",
|
||||||
|
message: "确认删除当前数据吗?",
|
||||||
|
thenFun: () => { handlerDelete(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const handlerDelete = () => {
|
||||||
|
const url = ApiUrl?.[request_config.url]?.delete?.url
|
||||||
|
const method = ApiUrl?.[request_config.url]?.delete?.method || "post"
|
||||||
|
if(!url) {
|
||||||
|
console.log("未配置删除接口参数");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 参数
|
||||||
|
const request_data = {
|
||||||
|
url,
|
||||||
|
method: method,
|
||||||
|
data: { [request_config.delete_key]: table_data.data_id },
|
||||||
|
}
|
||||||
|
CommonApi(request_data).then(response => {
|
||||||
|
// 成功提示
|
||||||
|
proxy.$message({
|
||||||
|
message: response.message,
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
loadData();
|
||||||
|
table_data.data_id = "";
|
||||||
|
proxy.deleteConfirmClose();
|
||||||
|
}).catch(error => {
|
||||||
|
proxy.confirmButtonLoading(false);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return { table_data, requestData, handlerDelete, saveDataId, handlerDeleteComfirm };
|
||||||
|
}
|
67
企业级管理系统/前端/项目源码/src/components/wangeditor/index.vue
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="editor"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, onMounted, watch } from 'vue';
|
||||||
|
import WangEditor from 'wangeditor';
|
||||||
|
// cookies
|
||||||
|
import { getToken } from "@/utils/cookies"; // 这是封装好的方法
|
||||||
|
export default {
|
||||||
|
name: 'Wangeditor',
|
||||||
|
components: {},
|
||||||
|
props: {
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ["update:content"],
|
||||||
|
setup(props, { emit }){
|
||||||
|
let html = ref(null)
|
||||||
|
// 内容
|
||||||
|
let content = ref();
|
||||||
|
// 富文本DOM元素
|
||||||
|
const editor = ref();
|
||||||
|
// 富文本对象
|
||||||
|
let editor_instance = null;
|
||||||
|
// 生命周期
|
||||||
|
onMounted(() => {
|
||||||
|
// 创建富文本对象
|
||||||
|
editor_instance = new WangEditor(editor.value);
|
||||||
|
// 图片上传配置
|
||||||
|
editor_instance.config.uploadImgServer = process.env.VUE_APP_DEV_TARGET + '/upload' // 上传图片的接口地址
|
||||||
|
editor_instance.config.uploadFileName = 'files' // formdata中的name属性
|
||||||
|
editor_instance.config.uploadImgHeaders = {
|
||||||
|
Token: getToken() // 设置请求头
|
||||||
|
}
|
||||||
|
editor_instance.config.uploadImgHooks = {
|
||||||
|
// 图片上传并返回结果,但图片插入错误时触发
|
||||||
|
fail: function (xhr, editor, result) {
|
||||||
|
console.log(result)
|
||||||
|
},
|
||||||
|
// 例如服务器端返回的不是 { errno: 0, data: [...] } 这种格式,可使用 customInsert
|
||||||
|
customInsert: function(insertImgFn, result) {
|
||||||
|
// insertImgFn 可把图片插入到编辑器,传入图片 src ,执行函数即可
|
||||||
|
insertImgFn(result.data.files_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 配置change事件
|
||||||
|
Object.assign(editor_instance.config, {
|
||||||
|
onchange(value) {
|
||||||
|
content.value = value;
|
||||||
|
emit("update:content", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// 创建
|
||||||
|
editor_instance.create();
|
||||||
|
})
|
||||||
|
watch(() => props.content, (newContent, oldContent) => {
|
||||||
|
editor_instance.txt.html(newContent);
|
||||||
|
})
|
||||||
|
return { editor }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
</style>
|
27
企业级管理系统/前端/项目源码/src/hook/dialogHook.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/** props */
|
||||||
|
export const propsType = {
|
||||||
|
flag: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: "30%"
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: "消息"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** 自定义hook */
|
||||||
|
export function dialogHook(emit){
|
||||||
|
/** dialog关闭 */
|
||||||
|
const close = (form) => {
|
||||||
|
emit("update:flag", false)
|
||||||
|
// 重置表单
|
||||||
|
form && form.value.handlerFormReset();
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
close
|
||||||
|
};
|
||||||
|
}
|
19
企业级管理系统/前端/项目源码/src/hook/infoHook.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { reactive } from "vue";
|
||||||
|
import { GetCategory } from "@/api/info";
|
||||||
|
/** 自定义hook */
|
||||||
|
export function categoryHook(){
|
||||||
|
const infoData = reactive({
|
||||||
|
category_options: []
|
||||||
|
})
|
||||||
|
/** 获取分类 */
|
||||||
|
const handlerGetCategory = () => {
|
||||||
|
return GetCategory().then(response => {
|
||||||
|
// return response.data;
|
||||||
|
infoData.category_options = response.data;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
infoData,
|
||||||
|
handlerGetCategory
|
||||||
|
};
|
||||||
|
}
|
17
企业级管理系统/前端/项目源码/src/hook/permissionHook.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// api
|
||||||
|
import { GetPermission } from "@a/account";
|
||||||
|
// store
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
/** 自定义hook */
|
||||||
|
export function permissionHook(){
|
||||||
|
|
||||||
|
console.log(store)
|
||||||
|
/** 获取分类 */
|
||||||
|
const getPermission = () => {
|
||||||
|
|
||||||
|
GetPermission().then(response => {
|
||||||
|
store.dispatch("permission/getPermissionAction")
|
||||||
|
})
|
||||||
|
};
|
||||||
|
return { getPermission }
|
||||||
|
}
|
7
企业级管理系统/前端/项目源码/src/js/data.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
const globalData = {
|
||||||
|
whether: [
|
||||||
|
{ value: "1", label: "是" },
|
||||||
|
{ value: "0", label: "否" },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
export default globalData;
|
15
企业级管理系统/前端/项目源码/src/js/elemCode.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
const elemCode = {
|
||||||
|
// 信息模块
|
||||||
|
"init:add": 'M001F001E001', // 信息 - 添加按钮
|
||||||
|
"init:edit": 'M001F001E002', // 信息 -编辑按钮
|
||||||
|
"init:del": 'M001F001E003', // 信息 -删除按钮
|
||||||
|
// 菜单模块
|
||||||
|
"menu:add": 'M002F001E001', // 菜单 - 添加按钮
|
||||||
|
"menu:edit": 'M002F001E002', // 菜单 -编辑按钮
|
||||||
|
"menu:del": 'M002F001E003', // 菜单 -删除按钮
|
||||||
|
// 角色模块
|
||||||
|
"role:add": 'M003F001E001', // 角色 - 添加按钮
|
||||||
|
"role:edit": 'M003F001E002', // 角色 -编辑按钮
|
||||||
|
"role:del": 'M003F001E003', // 角色 -删除按钮
|
||||||
|
}
|
||||||
|
export default elemCode;
|
43
企业级管理系统/前端/项目源码/src/layout/Index.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<el-container id="layout-container">
|
||||||
|
<el-aside id="layout-aside" :width="collapse === true ? '60px' : '250px'"><layout-aside /></el-aside>
|
||||||
|
<el-container>
|
||||||
|
<el-header id="layout-header" height="75px"><layout-header /></el-header>
|
||||||
|
<el-main id="layout-main"><layout-main /></el-main>
|
||||||
|
</el-container>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import LayoutAside from "./components/Aside";
|
||||||
|
import LayoutHeader from "./components/Header";
|
||||||
|
import LayoutMain from "./components/Main";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import { computed } from "vue";
|
||||||
|
export default {
|
||||||
|
name: "Layout",
|
||||||
|
components: { LayoutAside, LayoutHeader, LayoutMain },
|
||||||
|
props: {},
|
||||||
|
setup(props){
|
||||||
|
const store = useStore();
|
||||||
|
const collapse = computed(() => store.state.app.collapse);
|
||||||
|
return {
|
||||||
|
collapse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scpoed>
|
||||||
|
#layout-container { height: 100vh; }
|
||||||
|
#layout-aside {
|
||||||
|
background-color: #344a5f;
|
||||||
|
@include webkit(transition, all .3s ease 0s);
|
||||||
|
}
|
||||||
|
#layout-header {
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
background-color: $color_main;
|
||||||
|
@include webkit(box-shadow, 0 0 10px 0 rgba(0, 0, 0, .1));
|
||||||
|
}
|
||||||
|
#layout-main { background-color: #f7f7f7; }
|
||||||
|
</style>
|
97
企业级管理系统/前端/项目源码/src/layout/components/Aside.vue
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<template>
|
||||||
|
<h1 class="logo"><img :src="logo" alt=""></h1>
|
||||||
|
<el-menu :collapse="collapse" :default-active="currentPath" background-color="#344a5f" text-color="#fff" active-text-color="#ffffff" router>
|
||||||
|
<template v-for="item in routers" :key="item.path">
|
||||||
|
<template v-if="!item.hidden">
|
||||||
|
<!-- 一级菜单 -->
|
||||||
|
<template v-if="hasOnlyChild(item.children)">
|
||||||
|
<el-menu-item :index="item.children[0].path">
|
||||||
|
<img class="menu-icon" :src="item.meta.icon" alt="">
|
||||||
|
<template #title>{{ item.children[0].meta && item.children[0].meta.title }}</template>
|
||||||
|
</el-menu-item>
|
||||||
|
</template>
|
||||||
|
<!-- 子级菜单 -->
|
||||||
|
<template v-else>
|
||||||
|
<el-sub-menu v-if="item.children && item.children.length > 0" :index="item.path" >
|
||||||
|
<template #title>
|
||||||
|
<img class="menu-icon" :src="item.meta && item.meta.icon" alt="">
|
||||||
|
<span>{{ item.meta && item.meta.title }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-for="child in item.children" :key="child.path">
|
||||||
|
<el-menu-item v-if="!child.hidden" :index="child.path">{{ child.meta && child.meta.title }}</el-menu-item>
|
||||||
|
</template>
|
||||||
|
</el-sub-menu>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</el-menu>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useRouter, useRoute } from "vue-router";
|
||||||
|
import { reactive, computed, toRefs } from "vue";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
export default {
|
||||||
|
name: "Aside",
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
setup(){
|
||||||
|
const { options } = useRouter();
|
||||||
|
const { path } = useRoute();
|
||||||
|
const store = useStore();
|
||||||
|
const routers = options.routes;
|
||||||
|
/**
|
||||||
|
* 数据
|
||||||
|
*/
|
||||||
|
const data = reactive({
|
||||||
|
logo: computed(() => {
|
||||||
|
return store.state.app.collapse ? require("@/assets/images/logo-min.png") : require("@/assets/images/logo.png")
|
||||||
|
}),
|
||||||
|
collapse: computed(() => store.state.app.collapse)
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否只有一个子级菜单
|
||||||
|
*/
|
||||||
|
const hasOnlyChild = (children) => {
|
||||||
|
|
||||||
|
if(!children) { return false; }
|
||||||
|
// 存储路由
|
||||||
|
if(!children) { return false; }
|
||||||
|
const childRouter = children.filter(item => {
|
||||||
|
return item.hidden ? false : true;
|
||||||
|
})
|
||||||
|
|
||||||
|
// 只有一个子级路由
|
||||||
|
if(childRouter.length === 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 否则
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取当前路由路径
|
||||||
|
*/
|
||||||
|
const currentPath = computed(() => path);
|
||||||
|
return {
|
||||||
|
...toRefs(data),
|
||||||
|
routers,
|
||||||
|
hasOnlyChild,
|
||||||
|
currentPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.logo {
|
||||||
|
padding: 20px 0;
|
||||||
|
border-bottom: 1px solid #2d4153;
|
||||||
|
img { margin: auto; }
|
||||||
|
}
|
||||||
|
.menu-icon {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
display: inline-block;
|
||||||
|
margin:0 5px 0 0;
|
||||||
|
}
|
||||||
|
</style>
|
102
企业级管理系统/前端/项目源码/src/layout/components/Header.vue
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<div class="header-wrap">
|
||||||
|
<div class="wrap">
|
||||||
|
<span class="menu-btn" @click="switchAside">
|
||||||
|
<svg-icon iconName="menuBtn" className="icon-menu-svg"></svg-icon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="wrap">
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="face-info">
|
||||||
|
<img src="../../assets/images/logo-min.png" alt="409019683@qq.com">
|
||||||
|
<span class="name">{{ username }}</span>
|
||||||
|
</div>
|
||||||
|
<span class="logout" @click="handlerLogout">
|
||||||
|
<svg-icon iconName="logout" className="icon-logout"></svg-icon>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, getCurrentInstance } from "vue";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
export default {
|
||||||
|
name: "Header",
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
setup(){
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
// Vuex
|
||||||
|
const store = useStore();
|
||||||
|
// 引入router
|
||||||
|
const { replace } = useRouter();
|
||||||
|
// 菜单按钮
|
||||||
|
const switchAside = (() => { store.commit('app/SET_COLLAPSE'); })
|
||||||
|
// 用户名
|
||||||
|
const username = ref(store.state.app.username);
|
||||||
|
// 登出
|
||||||
|
const handlerLogout = (() => {
|
||||||
|
proxy.$confirm('确认退出管理后台', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
store.dispatch('app/logoutAction').then(response => {
|
||||||
|
proxy.$message({
|
||||||
|
message: response.message,
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
// 刷新页面清除数据
|
||||||
|
location.reload();
|
||||||
|
replace({
|
||||||
|
name: "Login"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).catch(error => {});
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
switchAside,
|
||||||
|
handlerLogout,
|
||||||
|
username
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.header-wrap {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.user-info {
|
||||||
|
float: right;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.face-info {
|
||||||
|
span, img {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
span { margin-left: 15px;}
|
||||||
|
}
|
||||||
|
.logout {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 75px;
|
||||||
|
height: 75px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.menu-btn { cursor: pointer; } // 手势
|
||||||
|
.icon-menu-svg { font-size: 24px; }
|
||||||
|
.icon-logout { font-size: 24px; }
|
||||||
|
</style>
|
25
企业级管理系统/前端/项目源码/src/layout/components/Main.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div id="main-content">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "Main",
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
setup(){
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
#main-content {
|
||||||
|
background-color: #fff; // 背景色
|
||||||
|
padding: 20px; // 内边距(4个边都为20px)
|
||||||
|
min-height: 100%; // 高度
|
||||||
|
@include webkit(box-sizing, border-box); // css3阴影
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
25
企业级管理系统/前端/项目源码/src/main.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { createApp } from "vue";
|
||||||
|
import App from "./App.vue";
|
||||||
|
import router from "./router";
|
||||||
|
import store from "./store";
|
||||||
|
// 守卫路由
|
||||||
|
import "./router/permit";
|
||||||
|
// elementui
|
||||||
|
import ElementUI from "./plugins/elementui";
|
||||||
|
// 批量导入svg文件
|
||||||
|
import "@/components/svgIcon/svg";
|
||||||
|
// svgicon
|
||||||
|
import SvgIcon from "@/components/svgIcon/Index.vue";
|
||||||
|
// 全局方法
|
||||||
|
import Global from "@/utils/global";
|
||||||
|
// 自定义指令
|
||||||
|
import directive from "./plugins/directive";
|
||||||
|
const app = createApp(App);
|
||||||
|
app
|
||||||
|
.use(store)
|
||||||
|
.use(router)
|
||||||
|
.use(ElementUI)
|
||||||
|
.use(directive)
|
||||||
|
.use(Global)
|
||||||
|
.component("svg-icon", SvgIcon)
|
||||||
|
.mount("#app");
|
33
企业级管理系统/前端/项目源码/src/plugins/directive.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import store from "../store";
|
||||||
|
// 元素编码
|
||||||
|
import elemCode from "../js/elemCode";
|
||||||
|
// 导出
|
||||||
|
export default (app) => {
|
||||||
|
app.directive('has-button', {
|
||||||
|
// 创建完成:在绑定元素的 attribute 或事件监听器被应用之前调用
|
||||||
|
created() {},
|
||||||
|
// 挂载之前:在绑定元素的父组件挂载之前调用
|
||||||
|
beforeMount(el, binding, vnode, prevVnode) {},
|
||||||
|
// 挂载完成:绑定元素的父组件被挂载时调用
|
||||||
|
mounted(el, binding, vnode, prevVnode) {
|
||||||
|
// 获取元素权限
|
||||||
|
const elem_data = store.getters["permission/elem"];
|
||||||
|
const user_type = store.getters["permission/user_type"];
|
||||||
|
// 否则是非超管
|
||||||
|
if(!elem_data) { return false }
|
||||||
|
const elems = elem_data.split(",")
|
||||||
|
const code = elemCode[binding.value] // 等价于elemCode['init:edit']
|
||||||
|
if(!user_type && !elems.includes(code)) {
|
||||||
|
el.parentNode.removeChild(el);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 更新之前:在包含组件的 VNode 更新之前调用
|
||||||
|
beforeUpdate() {},
|
||||||
|
// 更新完成:在包含组件的 VNode 及其子组件的 VNode 更新之后调用
|
||||||
|
updated() {},
|
||||||
|
// 销毁之前:在绑定元素的父组件卸载之前调用
|
||||||
|
beforeUnmount() {},
|
||||||
|
// 销毁完成:卸载绑定元素的父组件时调用
|
||||||
|
unmounted() {}
|
||||||
|
})
|
||||||
|
}
|
35
企业级管理系统/前端/项目源码/src/plugins/elementui.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { ElConfigProvider, ElSlider, ElButton, ElSwitch, ElTree, ElForm, ElFormItem, ElInput, ElSelect, ElCol , ElRow, ElMessage, ElMessageBox, ElContainer, ElAside, ElHeader,ElMain, ElMenu, ElMenuItem, ElSubMenu, ElTable, ElPagination, ElUpload, ElDatePicker, ElCascader, ElRadio, ElLoading, ElTimePicker, ElCheckbox, ElDialog, ElInputNumber } from 'element-plus';
|
||||||
|
// 导出
|
||||||
|
export default (app) => {
|
||||||
|
app.use(ElConfigProvider);
|
||||||
|
app.use(ElButton);
|
||||||
|
app.use(ElSwitch);
|
||||||
|
app.use(ElForm);
|
||||||
|
app.use(ElFormItem);
|
||||||
|
app.use(ElInput);
|
||||||
|
app.use(ElCol);
|
||||||
|
app.use(ElRow);
|
||||||
|
app.use(ElMessage);
|
||||||
|
app.use(ElMessageBox);
|
||||||
|
app.use(ElContainer);
|
||||||
|
app.use(ElAside);
|
||||||
|
app.use(ElHeader);
|
||||||
|
app.use(ElMain);
|
||||||
|
app.use(ElMenu);
|
||||||
|
app.use(ElMenuItem);
|
||||||
|
app.use(ElSubMenu);
|
||||||
|
app.use(ElSlider);
|
||||||
|
app.use(ElSelect);
|
||||||
|
app.use(ElTable);
|
||||||
|
app.use(ElPagination);
|
||||||
|
app.use(ElTree);
|
||||||
|
app.use(ElUpload);
|
||||||
|
app.use(ElDatePicker);
|
||||||
|
app.use(ElRadio);
|
||||||
|
app.use(ElLoading);
|
||||||
|
app.use(ElTimePicker);
|
||||||
|
app.use(ElCascader);
|
||||||
|
app.use(ElCheckbox);
|
||||||
|
app.use(ElDialog);
|
||||||
|
app.use(ElInputNumber);
|
||||||
|
}
|
29
企业级管理系统/前端/项目源码/src/router/index.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { createRouter, createWebHashHistory, createWebHistory } from "vue-router";
|
||||||
|
export const routes = [
|
||||||
|
// 根路由
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
redirect: "Login",
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
// 登录
|
||||||
|
{
|
||||||
|
path: "/login",
|
||||||
|
name: "Login",
|
||||||
|
hidden: true,
|
||||||
|
component: () => import("../views/account/Login.vue")
|
||||||
|
},
|
||||||
|
// 路由中转
|
||||||
|
{
|
||||||
|
path: "/admin",
|
||||||
|
name: "Admin",
|
||||||
|
hidden: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHashHistory(),
|
||||||
|
routes
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
118
企业级管理系统/前端/项目源码/src/router/index_back.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { createRouter, createWebHashHistory, createWebHistory } from "vue-router";
|
||||||
|
export const routes = [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
redirect: "Login",
|
||||||
|
hidden: true,
|
||||||
|
aaa: "",
|
||||||
|
bbb:""
|
||||||
|
},
|
||||||
|
// 登录
|
||||||
|
{
|
||||||
|
path: "/login",
|
||||||
|
name: "Login",
|
||||||
|
hidden: true,
|
||||||
|
component: () => import("../views/account/Login.vue")
|
||||||
|
},
|
||||||
|
// 后台首页
|
||||||
|
{
|
||||||
|
path: "/home",
|
||||||
|
name: "Home",
|
||||||
|
meta: {
|
||||||
|
title: "控制台",
|
||||||
|
icon: "home"
|
||||||
|
},
|
||||||
|
component: () => import("../layout/Index.vue"),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/console",
|
||||||
|
name: "Console",
|
||||||
|
meta: {
|
||||||
|
title: "首页"
|
||||||
|
},
|
||||||
|
component: () => import("../views/console/Index.vue"),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/system",
|
||||||
|
name: "System",
|
||||||
|
meta: {
|
||||||
|
title: "系统配置",
|
||||||
|
icon: "system"
|
||||||
|
},
|
||||||
|
component: () => import("../layout/Index.vue"),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/user",
|
||||||
|
name: "User",
|
||||||
|
meta: {
|
||||||
|
title: "用户列表"
|
||||||
|
},
|
||||||
|
component: () => import("../views/system/User.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/role",
|
||||||
|
name: "Role",
|
||||||
|
meta: {
|
||||||
|
title: "角色列表"
|
||||||
|
},
|
||||||
|
component: () => import("../views/system/Role.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/menu",
|
||||||
|
name: "Menu",
|
||||||
|
meta: {
|
||||||
|
title: "菜单列表"
|
||||||
|
},
|
||||||
|
component: () => import("../views/system/Menu.vue"),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/news",
|
||||||
|
name: "News",
|
||||||
|
meta: {
|
||||||
|
title: "信息管理",
|
||||||
|
icon: "information"
|
||||||
|
},
|
||||||
|
component: () => import("../layout/Index.vue"),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/newsIndex",
|
||||||
|
name: "NewsIndex",
|
||||||
|
meta: {
|
||||||
|
title: "信息列表"
|
||||||
|
},
|
||||||
|
component: () => import("../views/info/Index.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/newsCategory",
|
||||||
|
name: "NewsCategory",
|
||||||
|
meta: {
|
||||||
|
title: "信息分类"
|
||||||
|
},
|
||||||
|
component: () => import("../views/info/Category.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/newsDetailed",
|
||||||
|
name: "NewsDetailed",
|
||||||
|
hidden: true,
|
||||||
|
meta: {
|
||||||
|
title: "信息详情"
|
||||||
|
},
|
||||||
|
component: () => import("../views/info/Detailed.vue"),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHashHistory(),
|
||||||
|
routes
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
41
企业级管理系统/前端/项目源码/src/router/permit.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import router from "./index";
|
||||||
|
import store from "../store";
|
||||||
|
// cookie
|
||||||
|
import { getToken } from "@u/cookies";
|
||||||
|
// 全局前置守卫
|
||||||
|
router.beforeEach((to, from, next) => {
|
||||||
|
if(!getToken()) {
|
||||||
|
if(to.name !== "Login") {
|
||||||
|
next("Login");
|
||||||
|
}else{
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(store.state.permission.async_router.length === 0){
|
||||||
|
store.dispatch("permission/getRouterAction").then(response => {
|
||||||
|
// 获取动态路由
|
||||||
|
const async_router_data = store.getters["permission/async_router"];
|
||||||
|
// 获取静态路由
|
||||||
|
const default_router_data = router.options.routes;
|
||||||
|
// 更新静态路由
|
||||||
|
router.options.routes = default_router_data.concat(async_router_data);
|
||||||
|
// 更新动态路由
|
||||||
|
async_router_data.forEach(item => {
|
||||||
|
router.addRoute(item);
|
||||||
|
});
|
||||||
|
if(to.name === "Admin") {
|
||||||
|
const first_router = async_router_data[0]?.children[0] || async_router_data[0];
|
||||||
|
next({ ...first_router, replace: true});
|
||||||
|
}else{
|
||||||
|
// 确认进入下一个路由
|
||||||
|
next({ ...to, replace: true});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 全局后置守卫
|
||||||
|
router.afterEach((to, from) => {
|
||||||
|
})
|
13
企业级管理系统/前端/项目源码/src/store/index.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { createStore } from "vuex";
|
||||||
|
// 引用模块文件
|
||||||
|
import app from "./modules/app";
|
||||||
|
import info from "./modules/info";
|
||||||
|
import permission from "./modules/permission";
|
||||||
|
// 创建Vuex
|
||||||
|
export default createStore({
|
||||||
|
modules: { // 模块化
|
||||||
|
app, // 载入 app 模块
|
||||||
|
info,
|
||||||
|
permission
|
||||||
|
}
|
||||||
|
});
|
63
企业级管理系统/前端/项目源码/src/store/modules/app.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
//cookies
|
||||||
|
import { setToken, setUsername, getUsername, getToken, removeToken, removeUsername } from "@u/cookies";
|
||||||
|
// api
|
||||||
|
import { Login, Logout } from "@a/account";
|
||||||
|
const state = {
|
||||||
|
collapse: JSON.parse(sessionStorage.getItem('collapse')) || false,
|
||||||
|
token: "" || getToken(),
|
||||||
|
username: "" || getUsername(),
|
||||||
|
table_action_request: false
|
||||||
|
};
|
||||||
|
const getters = {}
|
||||||
|
const mutations = {
|
||||||
|
SET_COLLAPSE(state){
|
||||||
|
state.collapse = !state.collapse;
|
||||||
|
sessionStorage.setItem('collapse', JSON.stringify(state.collapse));
|
||||||
|
},
|
||||||
|
SET_TOKEN(state, value){ // 设置 token
|
||||||
|
state.token = value;
|
||||||
|
value && setToken(value);
|
||||||
|
},
|
||||||
|
SET_USERNAME(state, value){ // 设置用户名
|
||||||
|
state.username = value;
|
||||||
|
value && setUsername(value);
|
||||||
|
},
|
||||||
|
SET_TABLE_REQUEST(state){
|
||||||
|
state.table_action_request = !state.table_action_request
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const actions = {
|
||||||
|
loginAction(context, repuestData) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Login(repuestData).then((response) => {
|
||||||
|
let data = response.data;
|
||||||
|
context.commit('SET_TOKEN', data.token);
|
||||||
|
context.commit('SET_USERNAME', data.username);
|
||||||
|
resolve(response);
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 登出
|
||||||
|
logoutAction({ commit }){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Logout().then(response => {
|
||||||
|
removeToken();
|
||||||
|
removeUsername();
|
||||||
|
commit('SET_TOKEN', '');
|
||||||
|
commit('SET_USERNAME', '');
|
||||||
|
resolve(response);
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
mutations,
|
||||||
|
actions
|
||||||
|
};
|
||||||
|
|
23
企业级管理系统/前端/项目源码/src/store/modules/info.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// api
|
||||||
|
import { GetCategory } from "@/api/info";;
|
||||||
|
const state = {};
|
||||||
|
const getters = {}
|
||||||
|
const mutations = {}
|
||||||
|
const actions = {
|
||||||
|
categoryAction() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
GetCategory().then(response => {
|
||||||
|
resolve(response.data)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
mutations,
|
||||||
|
actions
|
||||||
|
};
|
||||||
|
|
94
企业级管理系统/前端/项目源码/src/store/modules/permission.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// API
|
||||||
|
import { GetPermission } from "@a/account";
|
||||||
|
// utils
|
||||||
|
import { formatTree } from "@/utils/format";
|
||||||
|
/** 格式化菜单数据生成路由 */
|
||||||
|
const formatRouterMenu = (data) => {
|
||||||
|
// 检测数据是否存在
|
||||||
|
if(data && (!Array.isArray(data) || data.length === 0)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 监听存储数据
|
||||||
|
const router = [];
|
||||||
|
// 遍历菜单
|
||||||
|
data.forEach(item => {
|
||||||
|
const router_obj = {};
|
||||||
|
// id
|
||||||
|
router_obj.menu_id = item.menu_id;
|
||||||
|
router_obj.parent_id = item.parent_id;
|
||||||
|
// path
|
||||||
|
router_obj.path = item.menu_path;
|
||||||
|
// name
|
||||||
|
router_obj.name = item.menu_router;
|
||||||
|
// hidden
|
||||||
|
if(item.menu_hidden === "1") { router_obj.hidden = true; }
|
||||||
|
// redirect
|
||||||
|
if(item.menu_redirect) { router_obj.redirect = item.menu_redirect; }
|
||||||
|
// meta
|
||||||
|
router_obj.meta = {
|
||||||
|
// 菜单名称
|
||||||
|
title: item.menu_name,
|
||||||
|
// 菜单图标
|
||||||
|
icon: item.menu_icon,
|
||||||
|
// 是否缓存页面
|
||||||
|
keepAlive: item.menu_keep === "1" ? true : false
|
||||||
|
}
|
||||||
|
// component
|
||||||
|
router_obj.component = require(`@/${item.menu_component}`).default;
|
||||||
|
// 添加至router数组
|
||||||
|
router.push(router_obj);
|
||||||
|
})
|
||||||
|
// 树状格式化
|
||||||
|
const tree_data = formatTree(router, "menu_id", "parent_id", "children", 0);
|
||||||
|
// 返回数据
|
||||||
|
return tree_data;
|
||||||
|
}
|
||||||
|
const state = {
|
||||||
|
async_router: [],
|
||||||
|
elem: "",
|
||||||
|
user_type: ""
|
||||||
|
};
|
||||||
|
const getters = {
|
||||||
|
async_router: state => state.async_router,
|
||||||
|
elem: state => state.elem,
|
||||||
|
user_type: state => state.user_type,
|
||||||
|
}
|
||||||
|
const mutations = {
|
||||||
|
SET_ROUTER(state, value){
|
||||||
|
state.async_router = value;
|
||||||
|
},
|
||||||
|
SET_ELEM(state, value){
|
||||||
|
state.elem = value;
|
||||||
|
},
|
||||||
|
SET_USERTYPE(state, value){
|
||||||
|
state.user_type = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const actions = {
|
||||||
|
getRouterAction(context) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
GetPermission().then((response) => {
|
||||||
|
const data = response.data.router_menu;
|
||||||
|
// 格式化菜单数据生成路由
|
||||||
|
const menu = formatRouterMenu(data);
|
||||||
|
// 存储路由
|
||||||
|
context.commit("SET_ROUTER", menu);
|
||||||
|
// 存储元素权限
|
||||||
|
context.commit("SET_ELEM", response.data.elem_data);
|
||||||
|
// 更新用户类型
|
||||||
|
context.commit("SET_USERTYPE", response.data.user);
|
||||||
|
resolve(response);
|
||||||
|
}).catch(error => {
|
||||||
|
reject(error);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
mutations,
|
||||||
|
actions
|
||||||
|
};
|
||||||
|
|
34
企业级管理系统/前端/项目源码/src/styles/elementui.scss
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
.el-button-block {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#layout-aside .el-menu {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
/* 导航菜单高亮 */
|
||||||
|
.is-active { background-color: rgba(254, 108, 108, .2) !important; }
|
||||||
|
.is-opened {
|
||||||
|
.el-sub-menu__title { background-color: #f56c6c !important; }
|
||||||
|
}
|
||||||
|
.el-form-item__content { display: block; }
|
||||||
|
/*上传组件*/
|
||||||
|
.avatar-uploader {
|
||||||
|
overflow: hidden;
|
||||||
|
img { width: 100%; }
|
||||||
|
.el-upload {
|
||||||
|
border: 1px dashed #d9d9d9;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* 日期组件 z-index */
|
||||||
|
.el-popper { z-index: 10002 !important; }
|
||||||
|
.va-top { vertical-align: top; }
|
9
企业级管理系统/前端/项目源码/src/styles/icon.scss
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.aside-menu-svg {
|
||||||
|
margin-right: 5px;
|
||||||
|
margin-top: -2px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-logo {
|
||||||
|
background: url("~@/assets/images/logo.png") no-repeat;
|
||||||
|
}
|
14
企业级管理系统/前端/项目源码/src/styles/main.scss
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@import "./sassConfig.scss";
|
||||||
|
@import "./normalize.scss";
|
||||||
|
@import "./elementui.scss";
|
||||||
|
@import "./icon.scss";
|
||||||
|
|
||||||
|
/* float */
|
||||||
|
.pull-right { float: right; }
|
||||||
|
|
||||||
|
/* margin */
|
||||||
|
.margin-top-20 { margin-top: 20px; }
|
||||||
|
.margin-top-10 { margin-top: 10px; }
|
||||||
|
/* text-color */
|
||||||
|
.text-white { color: white; }
|
||||||
|
|
375
企业级管理系统/前端/项目源码/src/styles/normalize.scss
vendored
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
|
||||||
|
/* Document
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the line height in all browsers.
|
||||||
|
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||||
|
*/
|
||||||
|
/* div的默认样式不存在padding和margin为0的情况*/
|
||||||
|
html, body, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul,
|
||||||
|
fieldset, form, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the margin in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: 'Microsoft YaHei';
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the `main` element consistently in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in Firefox.
|
||||||
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box; /* 1 */
|
||||||
|
height: 0; /* 1 */
|
||||||
|
overflow: visible; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the gray background on active links in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the bottom border in Chrome 57-
|
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none; /* 1 */
|
||||||
|
text-decoration: underline; /* 2 */
|
||||||
|
text-decoration: underline dotted; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
|
* all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the border on images inside links in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Change the font styles in all browsers.
|
||||||
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: inherit; /* 1 */
|
||||||
|
font-size: 100%; /* 1 */
|
||||||
|
margin: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overflow in IE.
|
||||||
|
* 1. Show the overflow in Edge.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input { /* 1 */
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select { /* 1 */
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
[type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner border and padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the focus styles unset by the previous rule.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
padding: 0.35em 0.75em 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out
|
||||||
|
* `fieldset` elements in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
color: inherit; /* 2 */
|
||||||
|
display: table; /* 1 */
|
||||||
|
max-width: 100%; /* 1 */
|
||||||
|
padding: 0; /* 3 */
|
||||||
|
white-space: normal; /* 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the default vertical scrollbar in IE 10+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in IE 10.
|
||||||
|
* 2. Remove the padding in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
* 2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield; /* 1 */
|
||||||
|
outline-offset: -2px; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner padding in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button; /* 1 */
|
||||||
|
font: inherit; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
details {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Misc
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul, li { list-style: none; }
|
12
企业级管理系统/前端/项目源码/src/styles/sassConfig.scss
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
$color_main: white; // 定义
|
||||||
|
|
||||||
|
$danger: #f56c6c;
|
||||||
|
|
||||||
|
@mixin webkit($attr, $value){
|
||||||
|
-webkit-#{$attr}: $value;
|
||||||
|
-moz-#{$attr}: $value;
|
||||||
|
-o-#{$attr}: $value;
|
||||||
|
-ms-#{$attr}: $value;
|
||||||
|
#{$attr}: $value;
|
||||||
|
}
|
||||||
|
|
49
企业级管理系统/前端/项目源码/src/utils/common.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* @param { String } value 时间的值
|
||||||
|
* @param { String } type
|
||||||
|
* @param { Boolean } br true换行、false默认
|
||||||
|
* @param { String } conn 任意字符
|
||||||
|
* @returns 日期格式化
|
||||||
|
*/
|
||||||
|
export function getDate(params){
|
||||||
|
const new_date = params.value ? new Date(params.value) : new Date();
|
||||||
|
let year = new_date.getFullYear(); //年
|
||||||
|
let month = new_date.getMonth() + 1; //月
|
||||||
|
let day = new_date.getDate(); //日
|
||||||
|
let hh = new_date.getHours(); //时
|
||||||
|
let mm = new_date.getMinutes(); //分
|
||||||
|
let ss = new_date.getSeconds(); //分
|
||||||
|
if(month < 10) { month = `0${month}`; }
|
||||||
|
if(day < 10) { day = `0${day}`; }
|
||||||
|
if(hh < 10) { hh = `0${hh}`; }
|
||||||
|
if(mm < 10) { mm = `0${mm}`; }
|
||||||
|
if(ss < 10) { ss = `0${ss}`; }
|
||||||
|
// 连接符
|
||||||
|
const conn = params.connDate || "-";
|
||||||
|
// 格式化
|
||||||
|
const br = params.br ? "<br />" : " ";
|
||||||
|
const date = `${year}${conn}${month}${conn}${day}`;
|
||||||
|
const time = `${hh}:${mm}:${ss}`;
|
||||||
|
// 仅日期
|
||||||
|
if(params.type === "date") { return date; }
|
||||||
|
// 仅时间
|
||||||
|
if(params.type === "time") { return time; }
|
||||||
|
// 整体
|
||||||
|
return `${date}${br}${time}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param { Function } fun 执行的函数
|
||||||
|
* @param { Number } time 延时执行时间,默认500毫秒
|
||||||
|
* @returns 防抖函数
|
||||||
|
*/
|
||||||
|
export function debounce(fun, time = 500) {
|
||||||
|
let timer;
|
||||||
|
return function() {
|
||||||
|
let args = arguments;
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
fun.apply(this, args)
|
||||||
|
}, time)
|
||||||
|
}
|
||||||
|
}
|
18
企业级管理系统/前端/项目源码/src/utils/cookies.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import Cookies from "js-cookie";
|
||||||
|
// 变量
|
||||||
|
const tokenKey = "tokenAdmin";
|
||||||
|
const userNameKey = "username";
|
||||||
|
|
||||||
|
// 获取token
|
||||||
|
export function getToken(){ return Cookies.get(tokenKey); }
|
||||||
|
// 写入token
|
||||||
|
export function setToken(value){ Cookies.set(tokenKey, value); }
|
||||||
|
// 删除token
|
||||||
|
export function removeToken(){ Cookies.remove(tokenKey); }
|
||||||
|
|
||||||
|
// 获取userName
|
||||||
|
export function getUsername(){ return Cookies.get(userNameKey); }
|
||||||
|
// 写入userName
|
||||||
|
export function setUsername(value){ Cookies.set(userNameKey, value); }
|
||||||
|
// 删除userName
|
||||||
|
export function removeUsername(){ Cookies.remove(userNameKey); }
|
42
企业级管理系统/前端/项目源码/src/utils/format.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* @param { responseData } Object 请求参数数据
|
||||||
|
* @param { formData } Object Form表单字段
|
||||||
|
* @returns 枚举匹配key
|
||||||
|
*/
|
||||||
|
export function formatRequestData(responseData, formData){
|
||||||
|
// 判断是否有值存在
|
||||||
|
if(JSON.stringify(responseData) === "{}") { return false; }
|
||||||
|
// 获取form表单字段的所有key
|
||||||
|
const keys = Object.keys(responseData);
|
||||||
|
// 空JSON对象,存储过滤出来的数据
|
||||||
|
const data_json = {};
|
||||||
|
// 执行字段匹配
|
||||||
|
for(let key in formData) {
|
||||||
|
if(keys.includes(key) && formData.hasOwnProperty(key)) {
|
||||||
|
data_json[key]= responseData[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 返回处理后的数据
|
||||||
|
return data_json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns 递归函数格式化树状菜单
|
||||||
|
*/
|
||||||
|
export function formatTree(data, id = "id", pid = "parent_id", child = "children", root){
|
||||||
|
const tree = [];
|
||||||
|
if(data && data.length > 0) {
|
||||||
|
data.forEach(item => {
|
||||||
|
// 获取顶层菜单,parent_id === 0
|
||||||
|
if(item[pid] === root) {
|
||||||
|
const children = formatTree(data, id, pid, child, item[id]);
|
||||||
|
if(children) {
|
||||||
|
item[child] = children;
|
||||||
|
}
|
||||||
|
tree.push(item);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return tree;
|
||||||
|
}
|
59
企业级管理系统/前端/项目源码/src/utils/global.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Element Plus
|
||||||
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
// 命名空间
|
||||||
|
const globalFunction = {}
|
||||||
|
/**
|
||||||
|
* @param { message } String 内容,可选
|
||||||
|
* @param { title } String 标题,可选
|
||||||
|
* @param { thenFun } Function 回调函数,可选
|
||||||
|
* @description 确认弹窗
|
||||||
|
*/
|
||||||
|
globalFunction.deleteConfirm = (params) => {
|
||||||
|
ElMessageBox.confirm(params.message || '确认删除当前数据吗?删除后将无法恢复', params.title || '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
showClose: false, // 取消右上角关闭按钮
|
||||||
|
closeOnClickModal: false, // 取消点击遮罩关闭 MessageBox
|
||||||
|
closeOnPressEscape: false, // 取消按下ESC键关闭MessageBox
|
||||||
|
type: 'warning',
|
||||||
|
beforeClose: (action, instance, done) => {
|
||||||
|
globalFunction.deleteConfirmObj = { instance, done };
|
||||||
|
if(action === "confirm") {
|
||||||
|
// 按钮加载状态
|
||||||
|
globalFunction.confirmButtonLoading(true);
|
||||||
|
// 判断thenFun存在并且是Function类型,是则自动执行函数
|
||||||
|
params.thenFun && Object.prototype.toString.call(params.thenFun) === "[object Function]" && params.thenFun();
|
||||||
|
}else{
|
||||||
|
globalFunction.deleteConfirmClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).then(()=>{}).catch(()=>{})
|
||||||
|
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param { bool } Boolean 加载状态,可选
|
||||||
|
* @description 弹窗确认按钮加载状态
|
||||||
|
*/
|
||||||
|
globalFunction.confirmButtonLoading = (bool) => {
|
||||||
|
globalFunction.deleteConfirmObj.instance.confirmButtonLoading = bool;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param {*} params
|
||||||
|
*/
|
||||||
|
globalFunction.deleteConfirmClose = () => {
|
||||||
|
globalFunction.deleteConfirmObj.done();
|
||||||
|
globalFunction.deleteConfirmObj = null;
|
||||||
|
}
|
||||||
|
/** 函数2 */
|
||||||
|
globalFunction.message = (params) => {
|
||||||
|
console.log(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
install(app){
|
||||||
|
app.config.globalProperties["deleteConfirm"] = globalFunction.deleteConfirm;
|
||||||
|
app.config.globalProperties["deleteConfirmClose"] = globalFunction.deleteConfirmClose;
|
||||||
|
app.config.globalProperties["confirmButtonLoading"] = globalFunction.confirmButtonLoading;
|
||||||
|
app.config.globalProperties["message"] = globalFunction.message;
|
||||||
|
}
|
||||||
|
}
|
61
企业级管理系统/前端/项目源码/src/utils/request.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
// cookies
|
||||||
|
import { getToken, getUsername, removeToken, removeUsername } from "@/utils/cookies"; // 这是封装好的方法
|
||||||
|
// ElementUI 单独引入
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
// vue-router
|
||||||
|
import router from "@/router";
|
||||||
|
// 创建实例
|
||||||
|
const instance = axios.create({
|
||||||
|
baseURL: process.env.VUE_APP_API, // 请求地址
|
||||||
|
timeout: 5000, // 超时
|
||||||
|
});
|
||||||
|
// 拦截器
|
||||||
|
// 添加请求拦截器
|
||||||
|
instance.interceptors.request.use(function (config) {
|
||||||
|
// 在发送请求之前做些什么
|
||||||
|
if(getToken()) {
|
||||||
|
config.headers['Token'] = getToken(); // 携带token
|
||||||
|
}
|
||||||
|
if(getUsername()) {
|
||||||
|
config.headers['Username'] = getUsername(); // 携带用户名
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}, function (error) {
|
||||||
|
// 对请求错误做些什么
|
||||||
|
return Promise.reject(error);
|
||||||
|
});
|
||||||
|
// 添加响应拦截器
|
||||||
|
instance.interceptors.response.use(function (response) {
|
||||||
|
// 对响应数据做点什么
|
||||||
|
const data = response.data;
|
||||||
|
if(data.resCode === 0) {
|
||||||
|
return Promise.resolve(data);
|
||||||
|
}else{
|
||||||
|
ElMessage({
|
||||||
|
message: data.message,
|
||||||
|
type: "error"
|
||||||
|
})
|
||||||
|
return Promise.reject(data);
|
||||||
|
}
|
||||||
|
}, function (error) {
|
||||||
|
const errorData = JSON.parse(error.request.response);
|
||||||
|
if(errorData.message) {
|
||||||
|
ElMessage({
|
||||||
|
message: errorData.message,
|
||||||
|
type: "error"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// token失效自动退出
|
||||||
|
if(errorData.resCode === 1010) {
|
||||||
|
router.replace({
|
||||||
|
name: "Login"
|
||||||
|
})
|
||||||
|
removeToken();
|
||||||
|
removeUsername();
|
||||||
|
}
|
||||||
|
// 对响应错误做点什么
|
||||||
|
return Promise.reject(errorData);
|
||||||
|
});
|
||||||
|
// 暴露instance
|
||||||
|
export default instance;
|
40
企业级管理系统/前端/项目源码/src/utils/validate.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// 校验邮箱
|
||||||
|
export function validate_email(value){
|
||||||
|
let regEmail = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/;
|
||||||
|
return regEmail.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验密码
|
||||||
|
export function validate_password(value){
|
||||||
|
let regPassword = /^(?!\D+$)(?![^a-zA-Z]+$)\S{6,20}$/;
|
||||||
|
return regPassword.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验验证码
|
||||||
|
export function validate_code(value){
|
||||||
|
let regCode = /^[a-z0-9]{6}$/;
|
||||||
|
return regCode.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 密码校验
|
||||||
|
export function checkPassword(rule, value, callback, source, options) {
|
||||||
|
if(!value || value === ""){
|
||||||
|
callback(new Error("请输入用密码"));
|
||||||
|
}else if(!validate_password(value)) {
|
||||||
|
callback(new Error("请输入>=6并且<=20位的密码,包含数字、字母"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户名校验
|
||||||
|
export function checkUser(rule, value, callback, source, options) {
|
||||||
|
if(!value || value === ""){
|
||||||
|
callback(new Error("请输入用户名"));
|
||||||
|
}else if(!validate_email(value)) {
|
||||||
|
callback(new Error("邮箱格式不正确"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
5
企业级管理系统/前端/项目源码/src/views/About.vue
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<div class="about">
|
||||||
|
<h1>This is an about page</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
17
企业级管理系统/前端/项目源码/src/views/Home.vue
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<template>
|
||||||
|
<div class="home">
|
||||||
|
<HelloWorld msg="Welcome to Your Vue.js App" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// @ is an alias to /src
|
||||||
|
import HelloWorld from "@/components/HelloWorld.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Home",
|
||||||
|
components: {
|
||||||
|
HelloWorld
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
346
企业级管理系统/前端/项目源码/src/views/account/Login.vue
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
<!-- eslint-disable prettier/prettier -->
|
||||||
|
<template>
|
||||||
|
<div id="login">
|
||||||
|
<div class="form-wrap">
|
||||||
|
<ul class="menu-tab">
|
||||||
|
<li @click="data.current_menu = item.type" :class="{'current': data.current_menu === item.type}" v-for="item in data.tab_menu" :key="item.type">{{ item.label }}</li>
|
||||||
|
</ul>
|
||||||
|
<el-form ref="account_form" :model="data.form" :rules="data.form_rules">
|
||||||
|
<el-form-item prop="username">
|
||||||
|
<label class="form-label">用户名</label>
|
||||||
|
<el-input v-model="data.form.username"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="password">
|
||||||
|
<label class="form-label">密码</label>
|
||||||
|
<el-input type="password" v-model="data.form.password"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="passwords" v-if="data.current_menu === 'register'">
|
||||||
|
<label class="form-label">确认密码</label>
|
||||||
|
<el-input type="password" v-model="data.form.passwords"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item prop="code">
|
||||||
|
<label class="form-label">验证码</label>
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="14">
|
||||||
|
<el-input v-model="data.form.code"></el-input>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="10">
|
||||||
|
<el-button type="success" class="el-button-block" :loading="data.code_button_loading" :disabled="data.code_button_disabled" @click="handlerGetCode">{{ data.code_button_text }}</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="danger" @click="submitForm" :disabled="data.submit_button_disabled" :loading="data.submit_button_loading" class="el-button-block">
|
||||||
|
{{ data.current_menu === "login" ? "登录": "注册"}}
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, ref, onBeforeUnmount, getCurrentInstance } from 'vue';
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
// 校验类
|
||||||
|
import { validate_email, validate_password, validate_code } from "../../utils/validate";
|
||||||
|
// sha1
|
||||||
|
import sha1 from "js-sha1";
|
||||||
|
// API
|
||||||
|
import { GetCode } from "../../api/common";
|
||||||
|
import { Register, Login } from "../../api/account";
|
||||||
|
export default {
|
||||||
|
name: "Login",
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
setup(props){
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
// store
|
||||||
|
const store = useStore();
|
||||||
|
// router
|
||||||
|
const rotuer = useRouter();
|
||||||
|
// 用户名校验
|
||||||
|
const validate_name_rules = (rule, value, callback) => {
|
||||||
|
let regEmail = validate_email(value);
|
||||||
|
if (value === '') {
|
||||||
|
callback(new Error("请输入邮箱"));
|
||||||
|
} else if(!regEmail) {
|
||||||
|
callback(new Error("邮箱格式不正确"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const validate_password_rules = (rule, value, callback) => {
|
||||||
|
let regPassword = validate_password(value);
|
||||||
|
// 获取“确认密码”
|
||||||
|
const passwordsValue = data.form.passwords;
|
||||||
|
if (value === '') {
|
||||||
|
callback(new Error("请输入密码"));
|
||||||
|
} else if(!regPassword) {
|
||||||
|
callback(new Error("请输入>=6并且<=20位的密码,包含数字、字母"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 校验确认密码
|
||||||
|
const validate_passwords_rules = (rule, value, callback) => {
|
||||||
|
// 如果是登录,不需要校验确认密码,默认通过
|
||||||
|
if(data.current_menu === "login") { callback(); }
|
||||||
|
let regPassword = validate_password(value);
|
||||||
|
// 获取“密码”
|
||||||
|
const passwordValue = data.form.password;
|
||||||
|
if (value === '') {
|
||||||
|
callback(new Error("请输入密码"));
|
||||||
|
} else if(!regPassword) {
|
||||||
|
callback(new Error("请输入>=6并且<=20位的密码,包含数字、字母"));
|
||||||
|
} else if(passwordValue && passwordValue !== value){
|
||||||
|
callback(new Error("两次密码不一致"));
|
||||||
|
}else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const validate_code_rules = (rule, value, callback) => {
|
||||||
|
let regCode = validate_code(value);
|
||||||
|
if (value === '') {
|
||||||
|
callback(new Error("请输入验证码"));
|
||||||
|
} else if(!regCode) {
|
||||||
|
callback(new Error("请输入6位的验证码"));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
form: {
|
||||||
|
username: "", // 用户名
|
||||||
|
password: "", // 密码
|
||||||
|
passwords: "", // 确认密码
|
||||||
|
code: "", // 验证码
|
||||||
|
},
|
||||||
|
form_rules: {
|
||||||
|
username: [
|
||||||
|
{ validator: validate_name_rules, trigger: 'change' }
|
||||||
|
],
|
||||||
|
password: [
|
||||||
|
{ validator: validate_password_rules, trigger: 'change' }
|
||||||
|
],
|
||||||
|
passwords: [
|
||||||
|
{ validator: validate_passwords_rules, trigger: 'change' }
|
||||||
|
],
|
||||||
|
code: [
|
||||||
|
{ validator: validate_code_rules, trigger: 'change' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
tab_menu: [
|
||||||
|
{ type: "login", label: "登录" },
|
||||||
|
{ type: "register", label: "注册" }
|
||||||
|
],
|
||||||
|
current_menu: "login",
|
||||||
|
/**
|
||||||
|
* 获取验证码按钮交互
|
||||||
|
*/
|
||||||
|
code_button_disabled: false,
|
||||||
|
code_button_loading: false,
|
||||||
|
code_button_text: "获取验证码",
|
||||||
|
code_button_timer: null,
|
||||||
|
// 提交按钮
|
||||||
|
submit_button_disabled: true,
|
||||||
|
loading: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
const handlerGetCode = () => {
|
||||||
|
|
||||||
|
const username = data.form.username;
|
||||||
|
const password = data.form.password;
|
||||||
|
const passwords = data.form.passwords;
|
||||||
|
// 校验用户名
|
||||||
|
if(!validate_email(username)) {
|
||||||
|
proxy.$message.error({
|
||||||
|
message: "用户名不能为空 或 格式不正确",
|
||||||
|
type: "error"
|
||||||
|
})
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 校验密码
|
||||||
|
if(!validate_password(password)) {
|
||||||
|
proxy.$message({
|
||||||
|
message: "密码不能为空 或 格式不正确",
|
||||||
|
type: "error"
|
||||||
|
})
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 判断非 登录 时,校验两次密码
|
||||||
|
if(data.current_menu === 'register' && (password !== passwords)) {
|
||||||
|
proxy.$message({
|
||||||
|
message: "两次密码不一致",
|
||||||
|
type: "error"
|
||||||
|
})
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取验证码接口
|
||||||
|
const requestData = {
|
||||||
|
username: data.form.username,
|
||||||
|
module: data.current_menu
|
||||||
|
}
|
||||||
|
data.code_button_loading = true;
|
||||||
|
data.code_button_text = "发送中";
|
||||||
|
GetCode(requestData).then(response => {
|
||||||
|
const resData = response;
|
||||||
|
// 激活提交按钮
|
||||||
|
data.submit_button_disabled = false;
|
||||||
|
// 用户名存在
|
||||||
|
if(resData.resCode === 1024) {
|
||||||
|
proxy.$message.error(resData.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 成功 Elementui 提示
|
||||||
|
proxy.$message({
|
||||||
|
message: resData.message,
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
// 执行倒计时
|
||||||
|
countdown();
|
||||||
|
}).catch(error => {
|
||||||
|
data.code_button_loading = false;
|
||||||
|
data.code_button_text = "获取验证码";
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 倒计时 */
|
||||||
|
const countdown = (time) => {
|
||||||
|
if(time && typeof time !== 'number') { return false; }
|
||||||
|
let second = time || 60; // 默认时间
|
||||||
|
data.code_button_loading = false; // 取消加载
|
||||||
|
data.code_button_disabled = true; // 禁用按钮
|
||||||
|
data.code_button_text = `倒计进${second}秒`; // 按钮文本
|
||||||
|
// 判断是否存在定时器,存在则先清除
|
||||||
|
if(data.code_button_timer) { clearInterval(data.code_button_timer) };
|
||||||
|
// 开启定时器
|
||||||
|
data.code_button_timer = setInterval(() => {
|
||||||
|
second--;
|
||||||
|
data.code_button_text = `倒计进${second}秒`; // 按钮文本
|
||||||
|
if(second <= 0) {
|
||||||
|
data.code_button_text = `重新获取`; // 按钮文本
|
||||||
|
data.code_button_disabled = false; // 启用按钮
|
||||||
|
clearInterval(data.code_button_timer); // 清除倒计时
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
/** 表单提交 */
|
||||||
|
const account_form = ref(null);
|
||||||
|
const submitForm = (formName) => {
|
||||||
|
account_form.value.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
data.current_menu === "login" ? login() : register();
|
||||||
|
} else {
|
||||||
|
alert('表单验证不通过');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 注册 */
|
||||||
|
const register = () => {
|
||||||
|
const requestData = {
|
||||||
|
username: data.form.username,
|
||||||
|
password: data.form.password,
|
||||||
|
code: data.form.code
|
||||||
|
}
|
||||||
|
data.submit_button_loading = true;
|
||||||
|
Register(requestData).then(response => {
|
||||||
|
proxy.$message({
|
||||||
|
message: response.message,
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
reset();
|
||||||
|
}).catch(error => {
|
||||||
|
data.submit_button_loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/** 登录 */
|
||||||
|
const login = () => {
|
||||||
|
const requestData = {
|
||||||
|
username: data.form.username,
|
||||||
|
password: sha1(data.form.password),
|
||||||
|
code: data.form.code
|
||||||
|
}
|
||||||
|
data.submit_button_loading = true;
|
||||||
|
store.dispatch("app/loginAction", requestData).then(response => {
|
||||||
|
data.submit_button_loading = false;
|
||||||
|
proxy.$message({
|
||||||
|
message: response.message,
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
//路由跳转
|
||||||
|
rotuer.push({path: "/admin"});
|
||||||
|
reset();
|
||||||
|
}).catch(error => {
|
||||||
|
data.submit_button_loading = false;
|
||||||
|
console.log("失败");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置 */
|
||||||
|
const reset = () => {
|
||||||
|
// 重置表单
|
||||||
|
proxy.$refs.form.resetFields();
|
||||||
|
// 切回登录模式
|
||||||
|
data.current_menu = "login";
|
||||||
|
// 清除定时器
|
||||||
|
data.code_button_timer && clearInterval(data.code_button_timer);
|
||||||
|
// 获取验证码重置文本
|
||||||
|
data.code_button_text = "获取验证码";
|
||||||
|
// 获取验证码激活
|
||||||
|
data.code_button_disabled = false;
|
||||||
|
// 禁用提交按钮
|
||||||
|
data.submit_button_disabled = true;
|
||||||
|
// 取消提交按钮加载
|
||||||
|
data.submit_button_loading = false;
|
||||||
|
}
|
||||||
|
// 组件销毁之前 - 生命周期
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearInterval(data.code_button_timer); // 清除倒计时
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
handlerGetCode,
|
||||||
|
submitForm,
|
||||||
|
account_form
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
#login {
|
||||||
|
height: 100vh; // 设置高度,居于浏览器可视区高度
|
||||||
|
background-color: #344a5f; // 设置背景颜色
|
||||||
|
}
|
||||||
|
.form-wrap {
|
||||||
|
width: 320px;
|
||||||
|
padding-top: 100px; //上内边距
|
||||||
|
margin: auto; // 块元素水平居中
|
||||||
|
}
|
||||||
|
.menu-tab {
|
||||||
|
text-align: center;
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px 24px;
|
||||||
|
margin: 0 10px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
&.current { background-color: rgba(0, 0, 0, .1);}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.form-label {
|
||||||
|
display: block; // 转为块元素
|
||||||
|
color: #fff; // 设置字体颜色
|
||||||
|
font-size: 14px; // 设置字体大小
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
18
企业级管理系统/前端/项目源码/src/views/console/Index.vue
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<template>
|
||||||
|
<div class="">控制台</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useStore } from 'vuex'
|
||||||
|
export default {
|
||||||
|
name: 'NewsIndex',
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
setup(props){
|
||||||
|
const store = useStore();
|
||||||
|
store.dispatch("app/update_count");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
</style>
|
304
企业级管理系统/前端/项目源码/src/views/info/Category.vue
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
<template>
|
||||||
|
<el-button type="danger" @click="handlerCategory('first_category_add')">添加一级分类</el-button>
|
||||||
|
<hr class="spacing-hr" />
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="7">
|
||||||
|
<el-tree ref="categoryTree" :data="data.tree_data" :props="data.defaultProps" default-expand-all :expand-on-click-node="false">
|
||||||
|
<template #default="{ node, data }">
|
||||||
|
<div class="custom-tree-node">
|
||||||
|
<span>{{ node.label }}</span>
|
||||||
|
<span>
|
||||||
|
<el-button type="danger" round @click="handlerCategory('child_category_add', node)">添加子级</el-button>
|
||||||
|
<el-button type="success" round @click="handlerCategory(node.level === 1 ? 'parent_category_edit' : 'child_category_edit', node)">编辑</el-button>
|
||||||
|
<el-button round @click="handlerCategory('delete_category', node)">删除</el-button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-tree>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="17">
|
||||||
|
<h4 class="column">{{ config[config.type].title }}</h4>
|
||||||
|
<el-form label-width="100px">
|
||||||
|
<el-form-item label="父级分类:">
|
||||||
|
<el-input v-model.trim="data.parent_category" :disabled="config[config.type].parent_disabled" style="width: 20%;"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="子级分类:" v-if="config[config.type].sub_show">
|
||||||
|
<el-input v-model.trim="data.sub_category" :disabled="config[config.type].sub_disabled" style="width: 20%;"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="">
|
||||||
|
<el-button type="danger" :loading="data.button_loading" @click="handlerSubmit">确定</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, reactive, getCurrentInstance, onBeforeMount } from 'vue';
|
||||||
|
import { firstCategoryAdd, GetCategory, ChildCategoryAdd, CategoryEdit, CategoryDel } from "@/api/info";
|
||||||
|
export default {
|
||||||
|
name: 'InfoCategory',
|
||||||
|
components: {},
|
||||||
|
props: {},
|
||||||
|
setup(props){
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const data = reactive({
|
||||||
|
tree_data: [],
|
||||||
|
defaultProps: {
|
||||||
|
children: 'children',
|
||||||
|
label: 'category_name'
|
||||||
|
},
|
||||||
|
parent_category: "父级分类文本演示", // 父级分类
|
||||||
|
sub_category: "子级分类文本演示", // 子级分类
|
||||||
|
button_loading: false, // 按钮加载
|
||||||
|
parent_category_data: {},
|
||||||
|
sub_category_data: {}
|
||||||
|
})
|
||||||
|
const config = reactive({
|
||||||
|
type: "default",
|
||||||
|
default: {
|
||||||
|
title: "添加分类", // 标题
|
||||||
|
parent_disabled: true, // 父级分类禁用/启用
|
||||||
|
sub_disabled: true, // 子级分类禁用/启用
|
||||||
|
sub_show: true, // 子级分类显示/隐藏
|
||||||
|
clear: ["parent_category", "sub_category"]
|
||||||
|
},
|
||||||
|
first_category_add: {
|
||||||
|
title: "一级分类添加", // 标题
|
||||||
|
parent_disabled: false, // 父级分类禁用/启用
|
||||||
|
sub_disabled: true, // 子级分类禁用/启用
|
||||||
|
sub_show: false, // 子级分类显示/隐藏
|
||||||
|
clear: ["parent_category", "sub_category"]
|
||||||
|
},
|
||||||
|
child_category_add: {
|
||||||
|
title: "子级分类添加", // 标题
|
||||||
|
parent_disabled: true, // 父级分类禁用/启用
|
||||||
|
sub_disabled: false, // 子级分类禁用/启用
|
||||||
|
sub_show: true,
|
||||||
|
clear: ["sub_category"],
|
||||||
|
create: ["parent_category"]
|
||||||
|
},
|
||||||
|
parent_category_edit: {
|
||||||
|
title: "父级分类编辑", // 标题
|
||||||
|
parent_disabled: false, // 父级分类禁用/启用
|
||||||
|
sub_disabled: true, // 子级分类禁用/启用
|
||||||
|
sub_show: false,
|
||||||
|
create: ["parent_category"]
|
||||||
|
},
|
||||||
|
child_category_edit: {
|
||||||
|
title: "子级分类编辑", // 标题
|
||||||
|
parent_disabled: true, // 父级分类禁用/启用
|
||||||
|
sub_disabled: false, // 子级分类禁用/启用
|
||||||
|
sub_show: true,
|
||||||
|
create: ["parent_category", "sub_category"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// const handleNodeClick = (data) => {
|
||||||
|
// console.log(data)
|
||||||
|
// }
|
||||||
|
const categoryTree = ref(null);
|
||||||
|
const handlerCategory = (type, category_data) => {
|
||||||
|
console.log(category_data);
|
||||||
|
if(type === "child_category_edit") {
|
||||||
|
data.parent_category_data = category_data.parent || null;
|
||||||
|
data.sub_category_data = category_data || null;
|
||||||
|
}else{
|
||||||
|
data.parent_category_data = category_data || null;
|
||||||
|
}
|
||||||
|
config.type = type === "delete_category" ? "default": type;
|
||||||
|
// 文本清除、还原
|
||||||
|
handlerInputValue();
|
||||||
|
// 弹窗二次提示
|
||||||
|
(type === "delete_category") && handlerDeleteComfirm();
|
||||||
|
}
|
||||||
|
const handlerInputValue = () => {
|
||||||
|
// 获取清除数据的对象
|
||||||
|
const clearObject = config[config.type].clear;
|
||||||
|
// 获取还原数据的对象
|
||||||
|
const createObject = config[config.type].create;
|
||||||
|
// 执行清除动作
|
||||||
|
if(clearObject && clearObject.length > 0) {
|
||||||
|
clearObject.forEach(item => {
|
||||||
|
data[item] = "";
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 执行还原动作
|
||||||
|
if(createObject && createObject.length > 0) {
|
||||||
|
createObject.forEach(item => {
|
||||||
|
data[item] = data[`${item}_data`].data.category_name;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
const handlerSubmit = () => {
|
||||||
|
if(config.type === 'first_category_add') { handlerFirstCategoryAdd(); }
|
||||||
|
if(config.type === 'child_category_add') { handlerChildCategoryAdd(); }
|
||||||
|
if(config.type === 'child_category_edit' || config.type === 'parent_category_edit') { handlerCategoryEdit(); }
|
||||||
|
}
|
||||||
|
// 一级分类添加
|
||||||
|
const handlerFirstCategoryAdd = () => {
|
||||||
|
// 父级为空时提示
|
||||||
|
if(!data.parent_category) {
|
||||||
|
proxy.$message.error("父级分类不能为空");
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
data.button_loading = true;
|
||||||
|
firstCategoryAdd({categoryName: data.parent_category}).then(response => {
|
||||||
|
data.button_loading = false;
|
||||||
|
proxy.$message({
|
||||||
|
message: response.message,
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
data.parent_category = "";
|
||||||
|
}).catch(error => {
|
||||||
|
data.button_loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handlerGetCategory = () => {
|
||||||
|
GetCategory().then(response => {
|
||||||
|
const response_data = response.data
|
||||||
|
data.tree_data = response_data || [];
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 子级分类添加
|
||||||
|
const handlerChildCategoryAdd = () => {
|
||||||
|
// 子级为空时提示
|
||||||
|
if(!data.sub_category) {
|
||||||
|
proxy.$message.error("子级分类不能为空");
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 按钮加载状态
|
||||||
|
data.button_loading = true;
|
||||||
|
// 接口
|
||||||
|
ChildCategoryAdd({
|
||||||
|
categoryName: data.sub_category, // 分类名称参数
|
||||||
|
parentId: data.parent_category_data.data.id // 父级分类ID参数
|
||||||
|
}).then(response => {
|
||||||
|
// 清除加载状态
|
||||||
|
data.button_loading = false;
|
||||||
|
// 成功提示
|
||||||
|
proxy.$message({
|
||||||
|
message: response.message,
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
// 清除子级分类文本
|
||||||
|
data.sub_category = "";
|
||||||
|
// 追加子级数据
|
||||||
|
categoryTree.value.append(response.data, data.parent_category_data);
|
||||||
|
}).catch(error => {
|
||||||
|
// 清除加载状态
|
||||||
|
data.button_loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 分类编辑
|
||||||
|
const handlerCategoryEdit = () => {
|
||||||
|
// 分级为空时提示
|
||||||
|
console.log(!data.parent_category);
|
||||||
|
console.log(data.sub_category);
|
||||||
|
if(data.parent_category == "" || data.sub_category == "") {
|
||||||
|
const message = config.type === "parent_category_edit" ? "父级" : "子级";
|
||||||
|
proxy.$message.error(`${message}分类不能为空`);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 按钮加载状态
|
||||||
|
data.button_loading = true;
|
||||||
|
const node_parent = data.parent_category_data.data
|
||||||
|
const node_sub = data.sub_category_data.data
|
||||||
|
// 接口
|
||||||
|
CategoryEdit({
|
||||||
|
categoryName: config.type === "parent_category_edit" ? data.parent_category : data.sub_category, // 分类名称参数
|
||||||
|
id: config.type === "parent_category_edit" ? node_parent.id : node_sub.id // 分类ID参数
|
||||||
|
}).then(response => {
|
||||||
|
// 清除加载状态
|
||||||
|
data.button_loading = false;
|
||||||
|
// 成功提示
|
||||||
|
proxy.$message({
|
||||||
|
message: response.message,
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
// 同步更新树形菜单节点
|
||||||
|
const node_date = config.type === "parent_category_edit" ? node_parent : node_sub;
|
||||||
|
node_date.category_name = response.data.category_name;
|
||||||
|
}).catch(error => {
|
||||||
|
// 清除加载状态
|
||||||
|
data.button_loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handlerDeleteComfirm = () => {
|
||||||
|
proxy.$confirm('确认删除该分类吗?删除后将无法恢复', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
showClose: false, // 取消右上角关闭按钮
|
||||||
|
closeOnClickModal: false, // 取消点击遮罩关闭 MessageBox
|
||||||
|
closeOnPressEscape: false, // 取消按下ESC键关闭MessageBox
|
||||||
|
type: 'warning',
|
||||||
|
beforeClose: (action, instance, done) => {
|
||||||
|
if(action === "confirm") {
|
||||||
|
instance.confirmButtonLoading = true;
|
||||||
|
CategoryDel({categoryId: data.parent_category_data.data.id}).then(response => {
|
||||||
|
// 成功提示
|
||||||
|
proxy.$message({
|
||||||
|
message: response.message,
|
||||||
|
type: "success"
|
||||||
|
})
|
||||||
|
instance.confirmButtonLoading = false;
|
||||||
|
done();
|
||||||
|
// 删除交互
|
||||||
|
categoryTree.value.remove(data.parent_category_data);
|
||||||
|
}).catch(error => {
|
||||||
|
instance.confirmButtonLoading = false;
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onBeforeMount(() => {
|
||||||
|
handlerGetCategory();
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
// handleNodeClick,
|
||||||
|
handlerCategory,
|
||||||
|
handlerSubmit,
|
||||||
|
config,
|
||||||
|
categoryTree
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.spacing-hr {
|
||||||
|
border: none; // 设置无边框
|
||||||
|
border-top: 1px solid #e9e9e9; // 底部1像素,实线边框,颜色为 e9e9e9
|
||||||
|
margin:30px 0; // 上下边距为30像素,左右为0
|
||||||
|
}
|
||||||
|
.custom-tree-node {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
:deep(.el-tree-node__content) {
|
||||||
|
height: auto;
|
||||||
|
button {
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin: 8px 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.column {
|
||||||
|
height: 44px;
|
||||||
|
padding: 0 20px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
line-height: 44px;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
}
|
||||||
|
</style>
|
120
企业级管理系统/前端/项目源码/src/views/info/Detailed.vue
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<template>
|
||||||
|
<BasisForm @callback="handlerSubmitForm" :item="form_config.form_item" :button="form_config.form_button" label-width="120px" :field="form_config.form_data"/>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { reactive, onBeforeMount, getCurrentInstance } from "vue";
|
||||||
|
import { useRouter, useRoute } from "vue-router";
|
||||||
|
import BasisForm from "@c/form";
|
||||||
|
import { InfoCreate, GetDetailed, InfoEdit } from "@/api/info";
|
||||||
|
// 全局数据
|
||||||
|
import globalData from "@/js/data";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
export default {
|
||||||
|
name: 'InfoDetailed',
|
||||||
|
components: { BasisForm },
|
||||||
|
props: {},
|
||||||
|
setup(props){
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
// router
|
||||||
|
const { go } = useRouter();
|
||||||
|
const { query } = useRoute();
|
||||||
|
const data = reactive({
|
||||||
|
row_id: query.id,
|
||||||
|
})
|
||||||
|
const form_config = reactive({
|
||||||
|
form_item: [
|
||||||
|
{
|
||||||
|
type: "cascader",
|
||||||
|
label: "信息分类",
|
||||||
|
prop: "category_id",
|
||||||
|
props: {
|
||||||
|
label: "category_name",
|
||||||
|
value: "id"
|
||||||
|
},
|
||||||
|
url: "category",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
label: "信息标题",
|
||||||
|
prop: "title",
|
||||||
|
width: "300px",
|
||||||
|
placeholder: "请输入标题",
|
||||||
|
max_length: 50, // 最大输入长度
|
||||||
|
min_length: 1, // 最小输入长度
|
||||||
|
required: true,
|
||||||
|
message: "请务必填写标题"
|
||||||
|
},
|
||||||
|
{ type: "upload", label: "缩略图", prop: "image_url" },
|
||||||
|
{ type: "date", label: "发布日期", prop: "create_date" },
|
||||||
|
{
|
||||||
|
type: "radio",
|
||||||
|
label: "是否发布",
|
||||||
|
prop: "status",
|
||||||
|
options: globalData.whether,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{ type: "wangeditor", label: "内容描述", prop: "content" }
|
||||||
|
],
|
||||||
|
form_data: {
|
||||||
|
image_url: "",
|
||||||
|
category_id: "",
|
||||||
|
title: "",
|
||||||
|
create_date: "",
|
||||||
|
content: "",
|
||||||
|
status: "1",
|
||||||
|
},
|
||||||
|
form_button: [
|
||||||
|
{ label: "提交", type: "danger", key: "submit" },
|
||||||
|
// { label: "重置", type: "primary", key: "reset" },
|
||||||
|
// { label: "关闭", type: "primary", key: "close", callback: () => handlerClose() },
|
||||||
|
]
|
||||||
|
})
|
||||||
|
onBeforeMount(() => {
|
||||||
|
// 获取详情
|
||||||
|
data.row_id && handlerGetDetailed();
|
||||||
|
})
|
||||||
|
const handlerSubmitForm = (formName) => {
|
||||||
|
data.row_id ? handlerEditInfo() : handlerAddInfo()
|
||||||
|
}
|
||||||
|
// 新增信息
|
||||||
|
const handlerAddInfo = () => {
|
||||||
|
// 深度拷贝
|
||||||
|
const request_data = JSON.parse(JSON.stringify(form_config.form_data));
|
||||||
|
// 日期处理
|
||||||
|
request_data.create_date = dayjs(request_data.create_date).format("YYYY-MM-DD HH:mm:ss");
|
||||||
|
InfoCreate(request_data).then(response => {
|
||||||
|
// 弹窗提示
|
||||||
|
proxy.$message.success(response.message);
|
||||||
|
// 重置表单
|
||||||
|
go(-1);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 编辑信息
|
||||||
|
const handlerEditInfo = () => {
|
||||||
|
console.log(22222)
|
||||||
|
// 深度拷贝
|
||||||
|
const request_data = JSON.parse(JSON.stringify(form_config.form_data));
|
||||||
|
InfoEdit(request_data).then(response => {
|
||||||
|
// 弹窗提示
|
||||||
|
proxy.$message.success(response.message);
|
||||||
|
// 重置表单
|
||||||
|
go(-1);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取详情
|
||||||
|
const handlerGetDetailed = () => {
|
||||||
|
GetDetailed({id:data.row_id}).then(response => {
|
||||||
|
form_config.form_data = response.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
handlerSubmitForm,
|
||||||
|
form_config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
169
企业级管理系统/前端/项目源码/src/views/info/Index.vue
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
<template>
|
||||||
|
<BasisTable :search="false" :columns="table_config.table_header" :config="table_config.config" :request="table_config.request">
|
||||||
|
<template v-slot:operation="slotData">
|
||||||
|
<el-button type="danger" @click="handlerDetailed(slotData.data.id)" v-has-button="'init:edit'">编辑</el-button>
|
||||||
|
</template>
|
||||||
|
</BasisTable>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import{ reactive, provide } from "vue";
|
||||||
|
import { getDate } from "@/utils/common";
|
||||||
|
import { categoryHook } from "@/hook/infoHook";
|
||||||
|
// components
|
||||||
|
import BasisTable from "@c/table";
|
||||||
|
// 全局数据`
|
||||||
|
import globalData from "@/js/data";
|
||||||
|
export default {
|
||||||
|
name: 'InfoIndex',
|
||||||
|
components: { BasisTable },
|
||||||
|
props: {},
|
||||||
|
setup(props){
|
||||||
|
const search_config = reactive({
|
||||||
|
label_width: "100px",
|
||||||
|
form_button_group: [
|
||||||
|
{ label: "新增", type: "danger", callback: () => addInfo() },
|
||||||
|
{ label: "其他按钮", callback: () => {} }
|
||||||
|
],
|
||||||
|
form_button: {
|
||||||
|
reset_button: true
|
||||||
|
},
|
||||||
|
form_item: [
|
||||||
|
{
|
||||||
|
type: "cascader",
|
||||||
|
label: "类别",
|
||||||
|
prop: "category_id",
|
||||||
|
props: {
|
||||||
|
label: "category_name",
|
||||||
|
value: "id"
|
||||||
|
},
|
||||||
|
url: "category",
|
||||||
|
label_width: 80,
|
||||||
|
col: 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "select",
|
||||||
|
label: "发布状态",
|
||||||
|
prop: "status",
|
||||||
|
options: globalData.whether,
|
||||||
|
col: 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "keyword",
|
||||||
|
label: "关键字",
|
||||||
|
prop: "keyword",
|
||||||
|
options: [
|
||||||
|
{ label: "ID", value: "id" },
|
||||||
|
{ label: "标题", value: "title" }
|
||||||
|
],
|
||||||
|
col: 8
|
||||||
|
},
|
||||||
|
],
|
||||||
|
button_col: 6,
|
||||||
|
form_data: {
|
||||||
|
category_id: "",
|
||||||
|
status: ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
provide("search_config", search_config);
|
||||||
|
|
||||||
|
// router
|
||||||
|
const { push } = useRouter();
|
||||||
|
// hook
|
||||||
|
const { infoData: category_data, handlerGetCategory: getList } = categoryHook();
|
||||||
|
const data = reactive({
|
||||||
|
category: 0,
|
||||||
|
keyword_options: [
|
||||||
|
{ label: "ID", value: "id" },
|
||||||
|
{ label: "标题", value: "title" }
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const request_data = reactive({
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
category_id: [],
|
||||||
|
key: "",
|
||||||
|
keyword: ""
|
||||||
|
})
|
||||||
|
const table_config = reactive({
|
||||||
|
table_header: [
|
||||||
|
{ label: "标题", prop: "title", width: "500" },
|
||||||
|
{
|
||||||
|
label: "类别",
|
||||||
|
prop: "category_name",
|
||||||
|
width: "200",
|
||||||
|
type: "function",
|
||||||
|
callback: (row) => {
|
||||||
|
return `<a href="http://www.web-jshtml.cn" title="手把手撸码前端">${row.category_name}</a>`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "日期",
|
||||||
|
prop: "createDate",
|
||||||
|
type: "function",
|
||||||
|
callback: (row) => {
|
||||||
|
return getDate({ value: row.createDate * 1000 });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "发布状态",
|
||||||
|
prop: "status",
|
||||||
|
type: "switch",
|
||||||
|
key_id: "id",
|
||||||
|
api_module: "info",
|
||||||
|
api_key: "info_status",
|
||||||
|
options: globalData.whether
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "操作",
|
||||||
|
type: "slot",
|
||||||
|
slot_name: "operation",
|
||||||
|
width: "200",
|
||||||
|
delete_elem: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
config: {},
|
||||||
|
request: {
|
||||||
|
url: "info",
|
||||||
|
data: {
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
|
delete_key: "id"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 详情页
|
||||||
|
const handlerDetailed = (id) => {
|
||||||
|
push({
|
||||||
|
path: "/newsDetailed",
|
||||||
|
query: { id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const addInfo = () => {
|
||||||
|
push({
|
||||||
|
path: "/newsDetailed"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlerOnload = (data) => {
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
category_data,
|
||||||
|
request_data,
|
||||||
|
table_config,
|
||||||
|
handlerDetailed,
|
||||||
|
handlerOnload,
|
||||||
|
addInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.width-160 { width: 160px; }
|
||||||
|
.width-100 { width: 100px; }
|
||||||
|
.width-180 { width: 180px; }
|
||||||
|
</style>
|
324
企业级管理系统/前端/项目源码/src/views/system/Menu.vue
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
<template>
|
||||||
|
<BasisTable
|
||||||
|
:columns="table_config.table_header"
|
||||||
|
:config="table_config.config"
|
||||||
|
:request="table_config.request"
|
||||||
|
>
|
||||||
|
<template v-slot:operation="slotData">
|
||||||
|
<el-button type="danger" @click="handlerMenu('edit', slotData.data.menu_id)" v-has-button="'menu:edit'">编辑</el-button>
|
||||||
|
<el-button type="danger" @click="handlerMenu('add_sub', slotData.data.menu_id)" v-has-button="'menu:add_sub'">添加子菜单</el-button>
|
||||||
|
</template>
|
||||||
|
</BasisTable>
|
||||||
|
<el-dialog :title="data.title" @closed="dislogClose" @open="dialogOpen" v-model="dialogVisible" width="30%" :close-on-click-modal="false" :close-on-press-escape="false">
|
||||||
|
<BasisForm
|
||||||
|
ref="basisFormRef"
|
||||||
|
label-width="100px"
|
||||||
|
:item="form_config.form_item"
|
||||||
|
:button="form_config.form_button"
|
||||||
|
:field="form_config.form_data"
|
||||||
|
:loading="form_config.form_loading"
|
||||||
|
@callback="handlerSubmit"
|
||||||
|
>
|
||||||
|
<template v-slot:menu_function>
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col :span="9">页面元素</el-col>
|
||||||
|
<el-col :span="9">标识符</el-col>
|
||||||
|
<el-col :span="4">操作</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="10" v-for="(item, index) in form_config.page_item" :key="item.id">
|
||||||
|
<el-col :span="9"><el-input v-model.trim="item.label" size="small" /></el-col>
|
||||||
|
<el-col :span="9"><el-input v-model.trim="item.value" size="small" /></el-col>
|
||||||
|
<el-col :span="4"><el-button size="small" @click="handlerDel(index)">删除</el-button></el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-button type="primary" @click="handlerPush">添加功能</el-button>
|
||||||
|
</template>
|
||||||
|
</BasisForm>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
import{ reactive, provide, ref } from "vue";
|
||||||
|
// store
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
// components
|
||||||
|
import BasisTable from "@c/table";
|
||||||
|
import BasisForm from "@c/form";
|
||||||
|
// 全局数据
|
||||||
|
import globalData from "@/js/data";
|
||||||
|
// API
|
||||||
|
import { MenuCreate, MenuDetailed, MenuUpdate } from "@/api/menu";
|
||||||
|
// utils
|
||||||
|
import { formatRequestData, formatTree } from "@/utils/format";
|
||||||
|
export default {
|
||||||
|
name: 'MenuIndex',
|
||||||
|
components: { BasisTable, BasisForm },
|
||||||
|
props: {},
|
||||||
|
setup(props){
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
// router
|
||||||
|
const { push } = useRouter();
|
||||||
|
// store
|
||||||
|
const store = useStore();
|
||||||
|
// 页面功能初始参数
|
||||||
|
const page_fun_json = { value: "", label: "" };
|
||||||
|
const data = reactive({
|
||||||
|
menu_handler_flag: "",
|
||||||
|
row_id: 0,
|
||||||
|
title: "",
|
||||||
|
title_item: {
|
||||||
|
add: "添加一级菜单",
|
||||||
|
edit: "编辑菜单",
|
||||||
|
add_sub: "添加子级菜单"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 列表表格配置
|
||||||
|
const table_config = reactive({
|
||||||
|
table_header: [
|
||||||
|
{ label: "菜单名称", prop: "menu_name" },
|
||||||
|
{ label: "菜单路径", prop: "menu_path" },
|
||||||
|
{ label: "映射组件", prop: "menu_component" },
|
||||||
|
{ label: "重定向", prop: "menu_redirect" },
|
||||||
|
{
|
||||||
|
label: "是否隐藏",
|
||||||
|
prop: "menu_hidden",
|
||||||
|
type: "switch",
|
||||||
|
key_id: "menu_id",
|
||||||
|
api_module: "menu",
|
||||||
|
api_key: "hidden_status",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "是否禁用",
|
||||||
|
prop: "menu_disabled",
|
||||||
|
type: "switch",
|
||||||
|
key_id: "menu_id",
|
||||||
|
api_module: "menu",
|
||||||
|
api_key: "disabled_status",
|
||||||
|
},
|
||||||
|
{ label: "操作", type: "slot", slot_name: "operation", width: "280", delete_elem: true }
|
||||||
|
],
|
||||||
|
config: {
|
||||||
|
selection: false,
|
||||||
|
batch_delete: false,
|
||||||
|
pagination: false,
|
||||||
|
action_request: true,
|
||||||
|
row_key: "menu_id"
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
url: "menu",
|
||||||
|
data: {},
|
||||||
|
delete_key: "menu_id",
|
||||||
|
format_data: (data) => formatTree(data, "menu_id", "parent_id", "children", 0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const search_config = reactive({
|
||||||
|
label_width: "70px",
|
||||||
|
form_button_group: [
|
||||||
|
{ label: "新增一级菜单", type: "danger", callback: () => handlerMenu('add') },
|
||||||
|
],
|
||||||
|
form_button: {
|
||||||
|
reset_button: true
|
||||||
|
},
|
||||||
|
form_item: [
|
||||||
|
{
|
||||||
|
type: "select",
|
||||||
|
label: "禁启用",
|
||||||
|
prop: "menu_disabled",
|
||||||
|
width: "100px",
|
||||||
|
options: globalData.whether
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "keyword",
|
||||||
|
label: "关键字",
|
||||||
|
prop: "keyword",
|
||||||
|
options: [
|
||||||
|
{ label: "菜单名称", value: "menu_name" },
|
||||||
|
{ label: "菜单路径", value: "menu_path" },
|
||||||
|
{ label: "组件名称", value: "menu_component" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
form_data: {
|
||||||
|
menu_disabled: ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
provide("search_config", search_config);
|
||||||
|
const form_config = reactive({
|
||||||
|
form_item: [
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
label: "菜单名称",
|
||||||
|
prop: "menu_name",
|
||||||
|
width: "300px",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
label: "菜单路径",
|
||||||
|
prop: "menu_path",
|
||||||
|
width: "300px",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
label: "路由名称",
|
||||||
|
prop: "menu_router",
|
||||||
|
width: "300px",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
label: "映射组件",
|
||||||
|
prop: "menu_component",
|
||||||
|
width: "300px",
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
{ type: "upload", label: "图标", prop: "menu_icon" },
|
||||||
|
{ type: "inputNumber", label: "排序", prop: "menu_sort", required: true },
|
||||||
|
{
|
||||||
|
type: "radio",
|
||||||
|
label: "是否禁用",
|
||||||
|
prop: "menu_disabled",
|
||||||
|
options: globalData.whether
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "radio",
|
||||||
|
label: "是否隐藏",
|
||||||
|
prop: "menu_hidden",
|
||||||
|
options: globalData.whether
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "radio",
|
||||||
|
label: "是否缓存",
|
||||||
|
prop: "menu_keep",
|
||||||
|
options: globalData.whether
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
label: "重定向",
|
||||||
|
prop: "menu_redirect",
|
||||||
|
width: "300px"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "slot",
|
||||||
|
label: "页面功能",
|
||||||
|
slot_name: "menu_function"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
form_button: [
|
||||||
|
{ label: "确认提交", type: "danger", key: "submit" }
|
||||||
|
],
|
||||||
|
form_data: {
|
||||||
|
menu_name: "",
|
||||||
|
menu_path: "",
|
||||||
|
menu_router: "",
|
||||||
|
menu_component: "",
|
||||||
|
menu_sort: 0,
|
||||||
|
menu_disabled: "2",
|
||||||
|
menu_hidden: "2",
|
||||||
|
menu_keep: "2",
|
||||||
|
menu_redirect: "",
|
||||||
|
menu_icon: ""
|
||||||
|
},
|
||||||
|
form_loading: false,
|
||||||
|
page_item: [JSON.parse(JSON.stringify(page_fun_json))]
|
||||||
|
})
|
||||||
|
|
||||||
|
const handlerSubmit = (value) => {
|
||||||
|
if(data.menu_handler_flag === "edit" && data.row_id) {
|
||||||
|
handlerMenuEdit();
|
||||||
|
}
|
||||||
|
if(data.menu_handler_flag === "add" || data.menu_handler_flag === "add_sub") {
|
||||||
|
handlerMenuCreate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const basisFormRef = ref(null);
|
||||||
|
const dislogClose = () => {
|
||||||
|
form_config.page_item = [JSON.parse(JSON.stringify(page_fun_json))];
|
||||||
|
data.row_id = "";
|
||||||
|
data.menu_handler_flag = "";
|
||||||
|
basisFormRef.value && basisFormRef.value.handlerFormReset();
|
||||||
|
dialogVisible.value = false;
|
||||||
|
}
|
||||||
|
const dialogOpen = () => {
|
||||||
|
if(data.menu_handler_flag === "edit" && data.row_id) {
|
||||||
|
handlerMenuDetailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handlerPush = () => {
|
||||||
|
form_config.page_item.push(JSON.parse(JSON.stringify(page_fun_json)));
|
||||||
|
}
|
||||||
|
const handlerDel = (index) => {
|
||||||
|
form_config.page_item.splice(index, 1);
|
||||||
|
}
|
||||||
|
const formatPageItem = () => {
|
||||||
|
const data = Object.assign([], form_config.page_item);
|
||||||
|
const dataItem = data.filter(item => item.label && item.value);
|
||||||
|
return JSON.stringify(dataItem);
|
||||||
|
}
|
||||||
|
const handlerMenu = (type, id = "") => {
|
||||||
|
data.menu_handler_flag = type;
|
||||||
|
data.row_id = id;
|
||||||
|
dialogVisible.value = true;
|
||||||
|
// 更新标题
|
||||||
|
data.title = data.title_item[type];
|
||||||
|
}
|
||||||
|
const handlerMenuDetailed = () => {
|
||||||
|
form_config.form_loading = true;
|
||||||
|
MenuDetailed({menu_id: data.row_id}).then(response => {
|
||||||
|
form_config.form_loading = false;
|
||||||
|
// form表单赋值
|
||||||
|
form_config.form_data = formatRequestData(response.data, form_config.form_data);
|
||||||
|
// 页面功能选值还原
|
||||||
|
const pageItemInit = response.data.menu_fun;
|
||||||
|
pageItemInit && (form_config.page_item = JSON.parse(pageItemInit));
|
||||||
|
}).catch(error => {
|
||||||
|
form_config.form_loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handlerMenuEdit = () => {
|
||||||
|
form_config.form_loading = true;
|
||||||
|
MenuUpdate({
|
||||||
|
...form_config.form_data,
|
||||||
|
menu_fun: formatPageItem(),
|
||||||
|
menu_id: data.row_id
|
||||||
|
}).then(response => {
|
||||||
|
form_config.form_loading = false;
|
||||||
|
dislogClose();
|
||||||
|
store.commit("app/SET_TABLE_REQUEST");
|
||||||
|
}).catch(error => {
|
||||||
|
form_config.form_loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handlerMenuCreate = () => {
|
||||||
|
form_config.form_loading = true;
|
||||||
|
const request_data = {
|
||||||
|
...form_config.form_data,
|
||||||
|
menu_fun: formatPageItem()
|
||||||
|
}
|
||||||
|
if(data.menu_handler_flag === "add_sub") { request_data.parent_id = data.row_id; }
|
||||||
|
MenuCreate(request_data).then(response => {
|
||||||
|
form_config.form_loading = false;
|
||||||
|
dislogClose();
|
||||||
|
store.commit("app/SET_TABLE_REQUEST");
|
||||||
|
}).catch(error => {
|
||||||
|
form_config.form_loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
table_config,
|
||||||
|
dialogVisible,
|
||||||
|
form_config,
|
||||||
|
basisFormRef,
|
||||||
|
handlerSubmit,
|
||||||
|
dislogClose,
|
||||||
|
dialogOpen,
|
||||||
|
handlerDel,
|
||||||
|
handlerPush,
|
||||||
|
handlerMenu,
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
100
企业级管理系统/前端/项目源码/src/views/system/Role.vue
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<BasisTable :columns="table_config.table_header" :config="table_config.config" :request="table_config.request">
|
||||||
|
<template v-slot:operation="slotData">
|
||||||
|
<el-button type="danger" @click="handlerRole(slotData.data.role_id)">编辑</el-button>
|
||||||
|
</template>
|
||||||
|
</BasisTable>
|
||||||
|
<DialogRole v-model:flag="data.dialogFlag" v-model:row-id="data.row_id" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import{ reactive, provide } from "vue";
|
||||||
|
// components
|
||||||
|
import BasisTable from "@c/table";
|
||||||
|
import DialogRole from "./components/dialogRole";
|
||||||
|
// 全局数据
|
||||||
|
import globalData from "@/js/data";
|
||||||
|
export default {
|
||||||
|
name: 'InfoIndex',
|
||||||
|
components: { BasisTable, DialogRole },
|
||||||
|
props: {},
|
||||||
|
setup(props){
|
||||||
|
const data = reactive({
|
||||||
|
dialogFlag: false,
|
||||||
|
row_id: ""
|
||||||
|
})
|
||||||
|
const table_config = reactive({
|
||||||
|
table_header: [
|
||||||
|
{ label: "角色名称", prop: "role_name" },
|
||||||
|
{
|
||||||
|
label: "是否禁用",
|
||||||
|
prop: "role_disabled",
|
||||||
|
type: "switch",
|
||||||
|
key_id: "role_id",
|
||||||
|
api_module: "role",
|
||||||
|
api_key: "status"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "操作",
|
||||||
|
type: "slot",
|
||||||
|
slot_name: "operation",
|
||||||
|
width: "200",
|
||||||
|
delete_elem: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
config: {
|
||||||
|
action_request: true,
|
||||||
|
has_button_delete: "role:delete",
|
||||||
|
has_button_batch_delete: "role:batch_delete"
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
url: "role",
|
||||||
|
data: {
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
|
delete_key: "role_id"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const search_config = reactive({
|
||||||
|
label_width: "80px",
|
||||||
|
form_button_group: [
|
||||||
|
{ label: "添加角色", type: "danger", callback: () => handlerRole() },
|
||||||
|
],
|
||||||
|
form_button: {
|
||||||
|
reset_button: true
|
||||||
|
},
|
||||||
|
form_item: [
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
label: "角色名称",
|
||||||
|
prop: "role_name",
|
||||||
|
placeholder: "请输入角色名称"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "select",
|
||||||
|
label: "禁用状态",
|
||||||
|
prop: "role_disabled",
|
||||||
|
width: "100px",
|
||||||
|
options: globalData.whether
|
||||||
|
},
|
||||||
|
],
|
||||||
|
form_data: {
|
||||||
|
role_name: "",
|
||||||
|
role_disabled: ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
provide("search_config", search_config);
|
||||||
|
const handlerRole = (id = "") => {
|
||||||
|
data.row_id = id;
|
||||||
|
data.dialogFlag = true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
table_config,
|
||||||
|
data,
|
||||||
|
handlerRole
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
115
企业级管理系统/前端/项目源码/src/views/system/User.vue
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
<template>
|
||||||
|
<BasisTable
|
||||||
|
:columns="table_config.table_header"
|
||||||
|
:config="table_config.config"
|
||||||
|
:request="table_config.request"
|
||||||
|
>
|
||||||
|
<template v-slot:operation="slotData">
|
||||||
|
<el-button type="danger" @click="handlerDialog(slotData.data.id)" v-has-button="'user:edit'">编辑</el-button>
|
||||||
|
<el-button type="danger" @click="handlerPassword(slotData.data.id)" v-has-button="'user:password'">修改密码</el-button>
|
||||||
|
</template>
|
||||||
|
</BasisTable>
|
||||||
|
<DialogUser v-model:flag="dialogFlag" v-model:row-id="row_id" />
|
||||||
|
<DialogPass v-model:flag="dialogPassFlag" v-model:row-id="row_id" title="修改密码" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { reactive, provide, toRefs } from "vue";
|
||||||
|
// components
|
||||||
|
import BasisTable from "@c/table";
|
||||||
|
import DialogUser from "./components/dialogUser";
|
||||||
|
import DialogPass from "./components/dialogPassword";
|
||||||
|
// 全局数据
|
||||||
|
import globalData from "@/js/data";
|
||||||
|
export default {
|
||||||
|
name: "SystemUser",
|
||||||
|
components: { BasisTable, DialogUser, DialogPass },
|
||||||
|
props: {},
|
||||||
|
setup(props){
|
||||||
|
const data = reactive({
|
||||||
|
dialogFlag: false,
|
||||||
|
dialogPassFlag: false,
|
||||||
|
row_id: ""
|
||||||
|
})
|
||||||
|
// 列表表格配置
|
||||||
|
const table_config = reactive({
|
||||||
|
table_header: [
|
||||||
|
{ label: "用户名", prop: "username" },
|
||||||
|
{ label: "真实姓名", prop: "truename" },
|
||||||
|
{ label: "角色类型", prop: "role_type" },
|
||||||
|
{
|
||||||
|
label: "帐号状态",
|
||||||
|
prop: "user_disabled",
|
||||||
|
type: "switch",
|
||||||
|
key_id: "id",
|
||||||
|
api_module: "user",
|
||||||
|
api_key: "status"
|
||||||
|
},
|
||||||
|
{ label: "创建时间", prop: "user_createtime" },
|
||||||
|
{ label: "操作", type: "slot", slot_name: "operation", width: "280", delete_elem: true }
|
||||||
|
],
|
||||||
|
config: {
|
||||||
|
action_request: true,
|
||||||
|
has_button_delete: "user:delete",
|
||||||
|
has_button_batch_delete: "user:batch_delete"
|
||||||
|
},
|
||||||
|
request: {
|
||||||
|
url: "user",
|
||||||
|
data: {
|
||||||
|
pageSize: 10,
|
||||||
|
pageNumber: 1
|
||||||
|
},
|
||||||
|
delete_key: "id"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 搜索项配置
|
||||||
|
const search_config = reactive({
|
||||||
|
label_width: "70px",
|
||||||
|
form_button_group: [
|
||||||
|
{ label: "添加用户", type: "danger", callback: () => handlerDialog() },
|
||||||
|
],
|
||||||
|
form_button: {
|
||||||
|
reset_button: true
|
||||||
|
},
|
||||||
|
form_item: [
|
||||||
|
{
|
||||||
|
type: "select",
|
||||||
|
label: "禁启用",
|
||||||
|
prop: "user_disabled",
|
||||||
|
width: "100px",
|
||||||
|
options: globalData.whether
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "keyword",
|
||||||
|
label: "关键字",
|
||||||
|
prop: "keyword",
|
||||||
|
options: [
|
||||||
|
{ label: "用户名", value: "username" },
|
||||||
|
{ label: "真实姓名", value: "truename" },
|
||||||
|
{ label: "角色类型", value: "role_type" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
],
|
||||||
|
form_data: {
|
||||||
|
user_disabled: ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
provide("search_config", search_config);
|
||||||
|
const handlerDialog = (id = '') => {
|
||||||
|
data.row_id = id;
|
||||||
|
data.dialogFlag = true;
|
||||||
|
}
|
||||||
|
const handlerPassword = (id) => {
|
||||||
|
data.row_id = id;
|
||||||
|
data.dialogPassFlag = true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
table_config,
|
||||||
|
handlerDialog,
|
||||||
|
handlerPassword,
|
||||||
|
...toRefs(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
@ -0,0 +1,95 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="title"
|
||||||
|
:width="width"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
@close="dialogClose"
|
||||||
|
@open="dialogOpen"
|
||||||
|
>
|
||||||
|
<BasisForm @callback="handlerSubmit" ref="basisFormRef" label-width="100px" :item="form_config.form_item" :button="form_config.form_button" :field="form_config.form_data" :loading="form_config.form_loading">
|
||||||
|
</BasisForm>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch, reactive, getCurrentInstance, defineProps, defineEmits } from "vue";
|
||||||
|
// components
|
||||||
|
import BasisForm from "@c/form";
|
||||||
|
// validate
|
||||||
|
import { checkPassword } from "@/utils/validate";
|
||||||
|
// hook
|
||||||
|
import { propsType, dialogHook } from "@/hook/dialogHook.js";
|
||||||
|
// sha1
|
||||||
|
import sha1 from "js-sha1";
|
||||||
|
// API
|
||||||
|
import { UpdatePass } from "@/api/user";
|
||||||
|
// store
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
// Props对象
|
||||||
|
const props = defineProps({
|
||||||
|
...propsType,
|
||||||
|
rowId: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits(["update:flag"])
|
||||||
|
// 变量
|
||||||
|
const dialogVisible = ref(props.flag);
|
||||||
|
const width = ref(props.width);
|
||||||
|
const title = ref(props.title);
|
||||||
|
const basisFormRef = ref(null);
|
||||||
|
// 获取实例上下文
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
// dialog
|
||||||
|
const { close } = dialogHook(emit);
|
||||||
|
// store
|
||||||
|
const store = useStore();
|
||||||
|
// form表单配置
|
||||||
|
const form_config = reactive({
|
||||||
|
form_item: [
|
||||||
|
{
|
||||||
|
type: "input",
|
||||||
|
label: "密码",
|
||||||
|
prop: "password",
|
||||||
|
width: "300px",
|
||||||
|
value_type: "password",
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
form_button: [
|
||||||
|
{ label: "确认修改", type: "danger", key: "submit" }
|
||||||
|
],
|
||||||
|
form_data: {
|
||||||
|
password: "",
|
||||||
|
},
|
||||||
|
form_loading: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const dialogClose = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
close(basisFormRef);
|
||||||
|
}
|
||||||
|
const dialogOpen = () => {}
|
||||||
|
watch(() => props.flag, (newValue, oldValue) => {
|
||||||
|
dialogVisible.value = newValue;
|
||||||
|
})
|
||||||
|
/** 表单提交 */
|
||||||
|
const handlerSubmit = () => {
|
||||||
|
if(!props.rowId) { return false; } // 不存在ID
|
||||||
|
form_config.form_loading = true; // 添加表单遮罩
|
||||||
|
UpdatePass({
|
||||||
|
password: sha1(form_config.form_data.password),
|
||||||
|
id: props.rowId
|
||||||
|
}).then(response => {
|
||||||
|
form_config.form_loading = false; // 清除表单遮罩
|
||||||
|
proxy.$message.success(response.message); // 成功弹窗提示
|
||||||
|
dialogClose(); // 关闭弹窗
|
||||||
|
}).catch(error => {
|
||||||
|
form_config.form_loading = false; // 清除表单遮罩
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang='scss' scoped></style>
|