保存进度!
							
								
								
									
										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>
 | 
			
		||||