diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000000000000000000000000000000000000..214388fe43cdfd7ce1c29cd3e401541ded620dba --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,3 @@ +> 1% +last 2 versions +not dead diff --git a/.env.development b/.env.development new file mode 100644 index 0000000000000000000000000000000000000000..cf089272862e8b8cdf2dcf55cd9b698aa1c54ea6 --- /dev/null +++ b/.env.development @@ -0,0 +1,6 @@ +# just a flag +ENV = 'development' + +# base api +VUE_APP_BASE_API = '/dev-api' +VUE_APP_REMOTE_URL = '/' \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 0000000000000000000000000000000000000000..631d57a6d855cbc661aa90875c09afbe7024ac19 --- /dev/null +++ b/.env.production @@ -0,0 +1,5 @@ +# just a flag +ENV = 'production' + +# base api +VUE_APP_BASE_API = '/' \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000000000000000000000000000000000..dd4b0c2b5ba30d4cf449b77fda58fcb1b55e608e --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,14 @@ +module.exports = { + root: true, + env: { + node: true + }, + extends: ["plugin:vue/essential", "eslint:recommended"], + parserOptions: { + parser: "babel-eslint" + }, + rules: { + "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", + "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off" + } +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..403adbc1e527906a4aa59558cd582c20bcd1d738 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/dist + + +# 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? diff --git a/README.md b/README.md index 34f07e23d1a97c9a19cb5e7669acd9851f61024c..fd3e0ecd1c745d8a1d82bf2fe18c6bd7d67ca7ce 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,40 @@ # CountingDreams -鏁版ⅵ鏅烘収涓ゆ睙 \ No newline at end of file +鏁版ⅵ鏅烘収涓ゆ睙 + +# vue2.x 妯℃澘浠撳簱 + +妯℃澘浠撳簱 + +- [x] vuex 鑷姩娣诲姞妯″潡锛歴tore 涓嬫ā鍧楁枃浠跺す index.js +- [x] axios +- [x] vue-router 鑷姩娣诲姞璺敱锛歷iews 鏂囦欢澶逛笅姣忎竴涓枃浠跺す涓嬮兘 index.vue,宓屽璺敱涓嬪繀椤绘湁 index.vue router-view +- [x] sass && scss + +## 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/). diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000000000000000000000000000000000000..397abca88c5a451f06a407b93469db551efaa6de --- /dev/null +++ b/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ["@vue/cli-plugin-babel/preset"] +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000000000000000000000000000000000000..aee0ddfb36dec4488837f87ee0e2e1954cb9e32c --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "name": "templat", + "version": "0.1.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "axios": "^0.21.0", + "core-js": "^3.6.5", + "dayjs": "^1.9.7", + "echarts": "^5.4.3", + "element-ui": "^2.14.0", + "gho-menu": "^1.0.1", + "loadash": "^1.0.0", + "mockjs": "^1.1.0", + "vue": "^2.6.11", + "vue-functional-data-merge": "^3.1.0", + "vue-router": "^3.2.0", + "vuex": "^3.4.0" + }, + "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/eslint-config-prettier": "^6.0.0", + "babel-eslint": "^10.1.0", + "eslint": "^6.7.2", + "eslint-plugin-prettier": "^3.1.3", + "eslint-plugin-vue": "^6.2.2", + "lint-staged": "^9.5.0", + "node-sass": "^6.0.0", + "prettier": "^1.19.1", + "sass-loader": "^10.2.0", + "script-ext-html-webpack-plugin": "^2.1.5", + "vue-template-compiler": "^2.6.11", + "webpack-bundle-analyzer": "^4.1.0" + }, + "gitHooks": { + "pre-commit": "lint-staged" + }, + "lint-staged": { + "*.{js,jsx,vue}": [ + "vue-cli-service lint", + "git add" + ] + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000000000000000000000000000000000000..2e3f165ad40bd20c6b905931a3d27eff125df10d --- /dev/null +++ b/public/index.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<html lang="en"> + <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"> + <link rel="icon" href="<%= BASE_URL %>favicon.ico"> + <title><%= htmlWebpackPlugin.options.title %></title> + <script src="http://at.alicdn.com/t/font_2273126_oy1g7zvosu.js"></script> + </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> diff --git a/public/js/dept.json b/public/js/dept.json new file mode 100644 index 0000000000000000000000000000000000000000..96c01cd4c1db2e564a89725da485c49d8b74ee57 --- /dev/null +++ b/public/js/dept.json @@ -0,0 +1,24 @@ +{ + "绉戝鏁版嵁": "", + "state": true, + "message": "SUCCESS", + "body": [ + { + "name": "鑲惧唴绉�", + "id": 1 + }, + { + "name": "鍛煎惛鍐呯", + "id": 2 + }, + { + "name": "鏅绉�", + "id": 3 + }, + { + "name": "娉屽翱澶栫", + "id": 4 + } + ], + "cause": null +} diff --git a/public/js/event.json b/public/js/event.json new file mode 100644 index 0000000000000000000000000000000000000000..2747b9a730158c6056c74bf26d3802012feafcf0 --- /dev/null +++ b/public/js/event.json @@ -0,0 +1,64 @@ +{ + "浜嬩欢鏁版嵁": "", + "state": true, + "message": "SUCCESS", + "body": [ + { + "name": "澶氳仈鎶楃敓绱犱娇鐢�", + "id": 1 + }, + { + "name": "鐗规畩鎶楃敓绱犱娇鐢�", + "id": 2 + }, + { + "name": "鎶㈡晳", + "id": 3 + }, + { + "name": "閲嶅ぇ鍙婄壒娈婃不鐤�", + "id": 4 + }, + { + "name": "鐗规畩绫诲垏鍙f姉鑿岀礌浣跨敤", + "id": 5 + }, + { + "name": "瓒呮湡浣跨敤鎶楄弻绱�", + "id": 6 + }, + { + "name": "鍗辨€ュ€间汉鏁�", + "id": 7 + }, + { + "name": "鍗遍噸鎮h€�", + "id": 8 + }, + { + "name": "杞嵄鎮h€�", + "id": 9 + }, + { + "name": "閲嶇偣鐤剧梾", + "id": 10 + }, + { + "name": "闄㈠唴鎰熸煋", + "id": 11 + }, + { + "name": "浣忛櫌瓒呰繃30澶╀汉鏁�", + "id": 12 + }, + { + "name": "浼犳煋鐥�", + "id": 13 + }, + { + "name": "姝讳骸鎮h€�", + "id": 14 + } + ], + "cause": null +} diff --git a/public/js/keyDiseases.json b/public/js/keyDiseases.json new file mode 100644 index 0000000000000000000000000000000000000000..2f71d66170ce9ea9cc0ae6488761fd5438c5cfec --- /dev/null +++ b/public/js/keyDiseases.json @@ -0,0 +1,206 @@ +{ + "閲嶇偣鐤剧梾鏁版嵁": "", + "state": true, + "message": "SUCCESS", + "body": { + "琛ㄥご鏁版嵁": "", + "headers": [ + { + "field": "index", + "dataField": "index", + "fieldName": "搴忓彿", + "fixed": true, + "sorted": false, + "index": 1 + }, + { + "field": "name", + "dataField": "name", + "fieldName": "濮撳悕", + "fixed": true, + "sorted": false, + "index": 2 + }, + { + "field": "sex", + "dataField": "sex", + "fieldName": "鎬у埆", + "fixed": true, + "sorted": false, + "index": 3 + }, + { + "field": "age", + "dataField": "age", + "fieldName": "骞撮緞", + "fixed": true, + "sorted": false, + "index": 4 + }, + { + "field": "rtime", + "dataField": "rtime", + "fieldName": "鍏ラ櫌鏃ユ湡", + "fixed": true, + "sorted": false, + "index": 5 + }, + { + "field": "ctime", + "dataField": "ctime", + "fieldName": "鍑洪櫌鏃ユ湡", + "fixed": true, + "sorted": false, + "index": 6 + }, + { + "field": "rdept", + "dataField": "rdept", + "fieldName": "鍏ラ櫌绉戝", + "fixed": true, + "sorted": false, + "index": 7 + }, + { + "field": "cdept", + "dataField": "cdept", + "fieldName": "鍑洪櫌鏃ユ湡", + "fixed": true, + "sorted": false, + "index": 8 + }, + { + "field": "infoName", + "dataField": "infoName", + "fieldName": "璇婃柇鍚嶇О", + "fixed": true, + "sorted": false, + "index": 11 + }, + { + "field": "infoTime", + "dataField": "infoTime", + "fieldName": "璇婃柇鏃堕棿", + "fixed": true, + "sorted": false, + "index": 10 + }, + { + "field": "doctor", + "dataField": "doctor", + "fieldName": "绠″簥鍖荤敓", + "fixed": true, + "sorted": false, + "index": 12 + } + ], + "pages": 1, + "total": 1, + "pageNum": 1, + "pageSize": 20, + "list": [ + { + "index": "1", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "infoTime": "2020-06-25", + "infoName": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "2", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "infoTime": "2020-06-25", + "infoName": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "3", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "infoTime": "2020-06-25", + "infoName": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "4", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "infoTime": "2020-06-25", + "infoName": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "5", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "infoTime": "2020-06-25", + "infoName": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "6", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "infoTime": "2020-06-25", + "infoName": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "7", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "infoTime": "2020-06-25", + "infoName": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + } + ], + "prePage": 0, + "nextPage": 0, + "extData": {} + }, + "cause": null +} diff --git a/public/js/warningPatient.json b/public/js/warningPatient.json new file mode 100644 index 0000000000000000000000000000000000000000..96e1d1f76803cb4e5dcff240883edb4287a98d61 --- /dev/null +++ b/public/js/warningPatient.json @@ -0,0 +1,214 @@ +{ + "鍗遍噸鎮h€呮暟鎹�": "", + "state": true, + "message": "SUCCESS", + "body": { + "琛ㄥご鏁版嵁": "", + "headers": [ + { + "field": "index", + "dataField": "index", + "fieldName": "搴忓彿", + "fixed": true, + "sorted": false, + "index": 1 + }, + { + "field": "name", + "dataField": "name", + "fieldName": "濮撳悕", + "fixed": true, + "sorted": false, + "index": 2 + }, + { + "field": "sex", + "dataField": "sex", + "fieldName": "鎬у埆", + "fixed": true, + "sorted": false, + "index": 3 + }, + { + "field": "age", + "dataField": "age", + "fieldName": "骞撮緞", + "fixed": true, + "sorted": false, + "index": 4 + }, + { + "field": "rtime", + "dataField": "rtime", + "fieldName": "鍏ラ櫌鏃ユ湡", + "fixed": true, + "sorted": false, + "index": 5 + }, + { + "field": "ctime", + "dataField": "ctime", + "fieldName": "鍑洪櫌鏃ユ湡", + "fixed": true, + "sorted": false, + "index": 6 + }, + { + "field": "rdept", + "dataField": "rdept", + "fieldName": "鍏ラ櫌绉戝", + "fixed": true, + "sorted": false, + "index": 7 + }, + { + "field": "cdept", + "dataField": "cdept", + "fieldName": "鍑洪櫌鏃ユ湡", + "fixed": true, + "sorted": false, + "index": 8 + }, + { + "field": "state", + "dataField": "state", + "fieldName": "鐘舵€�", + "fixed": true, + "sorted": false, + "index": 9 + }, + { + "field": "startTime", + "dataField": "startTime", + "fieldName": "寮€濮嬫椂闂�", + "fixed": true, + "sorted": false, + "index": 10 + }, + { + "field": "info", + "dataField": "info", + "fieldName": "璇婃柇", + "fixed": true, + "sorted": false, + "index": 11 + }, + { + "field": "doctor", + "dataField": "doctor", + "fieldName": "绠″簥鍖荤敓", + "fixed": true, + "sorted": false, + "index": 12 + } + ], + "pages": 1, + "total": 1, + "pageNum": 1, + "pageSize": 20, + "list": [ + { + "index": "1", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "startTime": "2020-06-25", + "info": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "2", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "startTime": "2020-06-25", + "info": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "3", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "startTime": "2020-06-25", + "info": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "4", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "startTime": "2020-06-25", + "info": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "5", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "startTime": "2020-06-25", + "info": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "6", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "startTime": "2020-06-25", + "info": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + }, + { + "index": "7", + "name": "璧垫檽宄�", + "sex": "鐢�", + "age": "42宀�", + "rtime": "2020-06-25", + "ctime": "2020-06-25", + "rdept": "鎬ヨ瘖绉�", + "cdept": "鎬ヨ瘖绉�", + "state": "绱ф€�", + "startTime": "2020-06-25", + "info": "鑵块儴楠ㄨ川鍧忔", + "doctor": "鐜嬫檽姊�" + } + ], + "prePage": 0, + "nextPage": 0, + "extData": {} + }, + "cause": null +} diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000000000000000000000000000000000000..8d4fcb1e3785296b322bc47f1135f8afdccd1157 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,124 @@ +<template> + <div id="app"> + <InnerView v-if="!isLogin"> + <AppHeader @changeCollapse="changeCollapse"></AppHeader> + <div class="main-view"> + <SubHeader></SubHeader> + <div class="flex content-view"> + <SideBar :isCollapse="isCollapse"></SideBar> + <div class="right-main"> + <PaddingView class="flex-col"> + <BreadCrumb ref="BreadCrumb"> </BreadCrumb> + <!-- <transition :name="transition"> --> + <keep-alive :include="cacheRoutes"> + <router-view class="child-view"></router-view> + </keep-alive> + <!-- </transition> --> + </PaddingView> + </div> + </div> + </div> + </InnerView> + <InnerView v-else> + <router-view class="child-view"></router-view> + </InnerView> + </div> +</template> +<script> +import { mapState } from "vuex"; +import { + // RouteView, + InnerView, +} from "@/components/Layout"; + +import { SideBar, AppHeader, SubHeader, BreadCrumb } from "@/components/App"; +export default { + name: "App", + components: { + SideBar, + AppHeader, + // RouteView, + InnerView, + SubHeader, + BreadCrumb, + }, + data() { + return { + transition: "", + lastRouteIndex: 0, + isCollapse: false, + }; + }, + computed: { + ...mapState({ + cacheRoutes: (state) => state.app.cacheRoutes, + }), + isLogin() { + return this.$route.path == "/login"; + }, + }, + watch: { + $route(val) { + // console.log(val); + const index = val?.meta?.index || 0; + if (val.meta.index >= this.lastRouteIndex) { + this.transition = "right-slide-in"; + } else { + this.transition = "left-slide-in"; + } + this.lastRouteIndex = index; + }, + }, + methods: { + changeCollapse(val) { + this.isCollapse = val; + }, + }, +}; +</script> + +<style lang="scss"> +* { + box-sizing: border-box; +} + +html, +body, +#app { + margin: 0; + width: 100vw; + height: 100vh; + overflow: hidden; + + background: #f5f5f5; +} + +#app { + display: flex; +} +.main-view { + display: flex; + flex-flow: column; + position: relative; + z-index: 2; + width: 1200px; + margin: 0 auto; + height: calc(100vh - 136px); + margin-top: 22px; + overflow: hidden; +} +.content-view { + width: 100%; + height: 100%; + overflow-y: hidden; + padding-top: 20px; +} +.right-main { + width: 100%; + margin-left: 18px; + border-radius: 8px; + background-color: #fff; + overflow-y: auto; + overflow-x: hidden; +} +</style> diff --git a/src/api/auth/index.js b/src/api/auth/index.js new file mode 100644 index 0000000000000000000000000000000000000000..fa0400e386c68bf5bbfde77e15ae92ff7b34fad7 --- /dev/null +++ b/src/api/auth/index.js @@ -0,0 +1,12 @@ +import request from "@/utils/request"; + +export default { + //鑾峰彇鐢ㄦ埛淇℃伅 + getUserInfo(params) { + return request({ + url: "/mock/getUserInfo", + method: "get", + params + }); + }, +}; \ No newline at end of file diff --git a/src/api/common/index.js b/src/api/common/index.js new file mode 100644 index 0000000000000000000000000000000000000000..7c2d11b1d5948bfd855346dc4aca884eca162e76 --- /dev/null +++ b/src/api/common/index.js @@ -0,0 +1,20 @@ +import request from "@/utils/request"; + +export default { + //鐧诲綍 + login(params) { + return request({ + url: "/mock/login", + method: "post", + params + }); + }, + //閫€鍑虹櫥褰� + loginOut(params) { + return request({ + url: "/mock/loginOut", + method: "post", + params + }); + }, +}; diff --git a/src/api/index.js b/src/api/index.js new file mode 100644 index 0000000000000000000000000000000000000000..6b7a9fe4b51ee9a78255d7ff7d3c89db218bf9b9 --- /dev/null +++ b/src/api/index.js @@ -0,0 +1,7 @@ +import common from "./common"; +import auth from "./auth"; + +export { + common, + auth +}; \ No newline at end of file diff --git a/src/assets/css/app.scss b/src/assets/css/app.scss new file mode 100644 index 0000000000000000000000000000000000000000..b9eee026e3c43f9794d00d33c1f287b9ee68be76 --- /dev/null +++ b/src/assets/css/app.scss @@ -0,0 +1,171 @@ +@import "./variables.scss"; +@import "~element-ui/packages/theme-chalk/src/index"; + +::-webkit-scrollbar { + /*婊氬姩鏉℃暣浣撴牱寮�*/ + width: 6px; + /*楂樺鍒嗗埆瀵瑰簲妯珫婊氬姩鏉$殑灏哄*/ + height: 2px; +} + +::-webkit-scrollbar-thumb { + /*婊氬姩鏉¢噷闈㈠皬鏂瑰潡*/ + border-radius: 10px; + box-shadow: inset 0 0 5px rgba(97, 184, 179, 0.1); + background: #2171FF; +} + +::-webkit-scrollbar-track { + /*婊氬姩鏉¢噷闈㈣建閬�*/ + box-shadow: inset 0 0 5px rgba(87, 175, 187, 0.1); + border-radius: 10px; + background: #ededed; +} + +.flex { + display: flex; +} + +.flex-center { + display: flex; + align-items: center; + justify-content: center; +} + +.flex-between { + display: flex; + align-items: center; + justify-content: space-between; +} + +.flex-end { + display: flex; + align-items: center; + justify-content: flex-end; +} + +.hidden-text { + opacity: 0; +} + +.flex-col { + display: flex; + flex-flow: column; +} + +.content-title { + font-size: 12px; + line-height: 18px; + height: 18px; + padding-left: 15px; + position: relative; + color: #2171FF; + display: flex; + align-items: center; + margin-left: 14px; + margin-top: 20px; + + &::before { + content: ''; + left: 0; + position: absolute; + width: 4px; + height: 12px; + border-radius: 3px; + background: #3182FF; + + } +} + +.el-button--primary.is-plain { + background-color: transparent; + border-color: #2171FF; + + &:hover { + background-color: #2171FF; + color: #fff; + } +} + +.el-button--warning.is-plain { + background-color: transparent; + border-color: #FF8D1A; + + &:hover { + // background-color: #FF8D1A; + // color: #fff; + } +} + +.el-menu { + + &.el-menu--horizontal { + background: transparent; + padding-left: 5px; + padding-top: 20px; + flex-shrink: 0; + + .el-menu-item { + padding: 0 0; + margin-right: 100px; + height: 36px; + line-height: 36px; + border-bottom: none; + + &::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 4px; + background-color: #2171FF; + transition: all .3s; + opacity: 0; + border-radius: 2px; + } + + &.is-active { + color: #2171FF; + border-bottom: none; + position: relative; + + &::after { + opacity: 1; + } + } + } + + } + +} + +.el-descriptions { + .el-descriptions__body { + background-color: transparent; + padding-top: 24px; + font-size: 12px; + color: #666; + line-height: 18px; + } + + :not(.is-bordered) .el-descriptions-item__cell { + padding-bottom: 22px; + } + +} + +.el-input { + width: 325px; +} + +.el-input__inner { + background-color: transparent; + padding: 0px 9px; +} + +.el-input--small .el-input__inner { + height: 30px; + line-height: 30px; + border-radius: 1px; +} \ No newline at end of file diff --git a/src/assets/css/mixin.scss b/src/assets/css/mixin.scss new file mode 100644 index 0000000000000000000000000000000000000000..06fa06125834695b9ca9b679faaf46c574168c46 --- /dev/null +++ b/src/assets/css/mixin.scss @@ -0,0 +1,66 @@ +@mixin clearfix { + &:after { + content: ""; + display: table; + clear: both; + } +} + +@mixin scrollBar { + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } +} + +@mixin relative { + position: relative; + width: 100%; + height: 100%; +} + +@mixin pct($pct) { + width: #{$pct}; + position: relative; + margin: 0 auto; +} + +@mixin triangle($width, $height, $color, $direction) { + $width: $width/2; + $color-border-style: $height solid $color; + $transparent-border-style: $width solid transparent; + height: 0; + width: 0; + + @if $direction==up { + border-bottom: $color-border-style; + border-left: $transparent-border-style; + border-right: $transparent-border-style; + } + + @else if $direction==right { + border-left: $color-border-style; + border-top: $transparent-border-style; + border-bottom: $transparent-border-style; + } + + @else if $direction==down { + border-top: $color-border-style; + border-left: $transparent-border-style; + border-right: $transparent-border-style; + } + + @else if $direction==left { + border-right: $color-border-style; + border-top: $transparent-border-style; + border-bottom: $transparent-border-style; + } +} diff --git a/src/assets/css/variables.scss b/src/assets/css/variables.scss new file mode 100644 index 0000000000000000000000000000000000000000..48c4f489c499c46e036eda3e5fc246d21070ab01 --- /dev/null +++ b/src/assets/css/variables.scss @@ -0,0 +1,177 @@ +/* 鏀瑰彉涓婚鑹插彉閲� */ +/* Color +-------------------------- */ +/// color|1|Brand Color|0 +$--color-primary: #3182FF; +/// color|1|Background Color|4 +$--color-white: #f9f9f9; +/// color|1|Background Color|4 +$--color-black: #333333; +$--color-primary-light-1: mix( + $--color-white, + $--color-primary, + 10% +); /* 53a8ff */ +$--color-primary-light-2: mix( + $--color-white, + $--color-primary, + 20% +); /* 66b1ff */ +$--color-primary-light-3: mix( + $--color-white, + $--color-primary, + 30% +); /* 79bbff */ +$--color-primary-light-4: mix( + $--color-white, + $--color-primary, + 40% +); /* 8cc5ff */ +$--color-primary-light-5: mix( + $--color-white, + $--color-primary, + 50% +); /* a0cfff */ +$--color-primary-light-6: mix( + $--color-white, + $--color-primary, + 60% +); /* b3d8ff */ +$--color-primary-light-7: mix( + $--color-white, + $--color-primary, + 70% +); /* c6e2ff */ +$--color-primary-light-8: mix( + $--color-white, + $--color-primary, + 80% +); /* d9ecff */ +$--color-primary-light-9: mix( + $--color-white, + $--color-primary, + 90% +); /* ecf5ff */ +/// color|1|Functional Color|1 +$--color-success: #67c23a; +/// color|1|Functional Color|1 +$--color-warning: #FF8D1A; +/// color|1|Functional Color|1 +$--color-danger: #f56c6c; +/// color|1|Functional Color|1 +$--color-info: #dddfd4; + +$--color-success-light: mix($--color-white, $--color-success, 80%); +$--color-warning-light: mix($--color-white, $--color-warning, 80%); +$--color-danger-light: mix($--color-white, $--color-danger, 80%); +$--color-info-light: mix($--color-white, $--color-info, 80%); + +$--color-success-lighter: mix($--color-white, $--color-success, 90%); +$--color-warning-lighter: mix($--color-white, $--color-warning, 90%); +$--color-danger-lighter: mix($--color-white, $--color-danger, 90%); +$--color-info-lighter: mix($--color-white, $--color-info, 90%); +/// color|1|Font Color|2 +$--color-text-primary: #303133; +/// color|1|Font Color|2 +$--color-text-regular: #666666; +/// color|1|Font Color|2 +$--color-text-secondary: #909399; +/// color|1|Font Color|2 +$--color-text-placeholder: #c0c4cc; +/// color|1|Border Color|3 +$--border-color-base: #dcdfe6; +/// color|1|Border Color|3 +$--border-color-light: #e4e7ed; +/// color|1|Border Color|3 +$--border-color-lighter: #ebeef5; +/// color|1|Border Color|3 +$--border-color-extra-light: #f2f6fc; + +// Background +/// color|1|Background Color|4 +$--background-color-base: #f5f7fa; + +/* 鏀瑰彉 icon 瀛椾綋璺緞鍙橀噺锛屽繀闇€ */ +$--font-path: "~element-ui/lib/theme-chalk/fonts"; + + +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, + 'Liberation Mono', 'Courier New', monospace; + +$dialog-content-max-height: 70vh; + +$app-header-height: 40px; +$app-router-view-margin: 6px; +$app-router-view-padding: 20px; +/* $app-header-height + router-view margin-top & margin-bottom 20px */ +$router-view-offset-height: $app-header-height + $app-router-view-margin * 2; + + +$--color-text-primary: #333333; + +// base color +$blue: #173e43; +$light-blue: #3a71a8; +$red: #c03639; +$pink: #e65d6e; +$green: #30b08f; +$tiffany: #4ab7bd; +$yellow: #fec171; +$panGreen: #30b08f; + +$--color-blue: #1da1f2 !default; +$--color-purple: #6c5ce7 !default; +$--color-green: #0ad300 !default; +$--color-blue-light: mix($--color-white, $--color-blue, 80%) !default; +$--color-purple-light: mix($--color-white, $--color-purple, 80%) !default; +$--color-blue-lighter: mix($--color-white, $--color-blue, 90%) !default; +$--color-purple-lighter: mix($--color-white, $--color-purple, 90%) !default; + +// sidebar +$menuText: $--color-text-primary; +$menuActiveText: #ffffff; +$subMenuActiveText: $--color-primary; // https://github.com/ElemeFE/element/issues/12951 + +$menuBg: #fff; +// $menuHover: $--color-primary-light-9; +$menuHover: #0AB2C1; + +$subMenuBg: rgba(0, 0, 0, 0.03); +$subMenuHover: $--color-primary-light-9; + +$sideBarWidth: 130px; + +// the :export directive is the magic sauce for webpack +// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass +:export { + menuText: $menuText; + menuActiveText: $menuActiveText; + subMenuActiveText: $subMenuActiveText; + menuBg: $menuBg; + menuHover: $menuHover; + subMenuBg: $subMenuBg; + subMenuHover: $subMenuHover; + sideBarWidth: $sideBarWidth; + primary: $--color-primary; + primaryLight: $--color-primary-light-8; + primaryLighter: $--color-primary-light-9; + success: $--color-success; + successLight: $--color-success-light; + successLighter: $--color-success-lighter; + warning: $--color-warning; + warningLight: $--color-warning-light; + warningLighter: $--color-warning-lighter; + danger: $--color-danger; + dangerLight: $--color-danger-light; + dangerLighter: $--color-danger-lighter; + info: $--color-info; + infoLight: $--color-info-light; + infoLighter: $--color-info-lighter; + blue: $--color-blue; + blueLight: $--color-blue-light; + blueLighter: $--color-blue-lighter; + purple: $--color-purple; + purpleLight: $--color-purple-light; + purpleLighter: $--color-purple-lighter; + bottomOffset: $app-router-view-margin + $app-router-view-padding; +} \ No newline at end of file diff --git a/src/assets/img/avatar-test.png b/src/assets/img/avatar-test.png new file mode 100644 index 0000000000000000000000000000000000000000..0ed19cbd168690709a650dbf6316e125858575eb Binary files /dev/null and b/src/assets/img/avatar-test.png differ diff --git a/src/assets/img/avatar.png b/src/assets/img/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..93373bc21304e07d8bb0ba343c1c0d78c73e15a3 Binary files /dev/null and b/src/assets/img/avatar.png differ diff --git a/src/assets/img/common/avatar.png b/src/assets/img/common/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..93373bc21304e07d8bb0ba343c1c0d78c73e15a3 Binary files /dev/null and b/src/assets/img/common/avatar.png differ diff --git a/src/assets/img/common/gohome.png b/src/assets/img/common/gohome.png new file mode 100644 index 0000000000000000000000000000000000000000..fa4c03cb3815783ac52403198f2d15cc446d1a07 Binary files /dev/null and b/src/assets/img/common/gohome.png differ diff --git "a/src/assets/img/common/logo - \345\211\257\346\234\254.png" "b/src/assets/img/common/logo - \345\211\257\346\234\254.png" new file mode 100644 index 0000000000000000000000000000000000000000..e94e4a5f3246cccf274a236b5a294ab065208e45 Binary files /dev/null and "b/src/assets/img/common/logo - \345\211\257\346\234\254.png" differ diff --git a/src/assets/img/common/top_out.png b/src/assets/img/common/top_out.png new file mode 100644 index 0000000000000000000000000000000000000000..e0e0a2744d751de3dd78ee7c493cd6bb8787cd87 Binary files /dev/null and b/src/assets/img/common/top_out.png differ diff --git a/src/assets/img/edit.png b/src/assets/img/edit.png new file mode 100644 index 0000000000000000000000000000000000000000..a3c3c8c5c13cd107bffb25c7b63d8c26f5b1d1ec Binary files /dev/null and b/src/assets/img/edit.png differ diff --git a/src/assets/img/idcard1.png b/src/assets/img/idcard1.png new file mode 100644 index 0000000000000000000000000000000000000000..733738267d70ca51066be21077310095c4642d69 Binary files /dev/null and b/src/assets/img/idcard1.png differ diff --git a/src/assets/img/idcard2.png b/src/assets/img/idcard2.png new file mode 100644 index 0000000000000000000000000000000000000000..9e0b543cfe57b92e3d62a6220ae0232f8e0a8a4f Binary files /dev/null and b/src/assets/img/idcard2.png differ diff --git a/src/assets/img/login-out.png b/src/assets/img/login-out.png new file mode 100644 index 0000000000000000000000000000000000000000..81cc516dcc71bd111a1de599d2ad02cb5463beca Binary files /dev/null and b/src/assets/img/login-out.png differ diff --git a/src/assets/img/logo.png b/src/assets/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e94e4a5f3246cccf274a236b5a294ab065208e45 Binary files /dev/null and b/src/assets/img/logo.png differ diff --git a/src/assets/img/nav/feedback.png b/src/assets/img/nav/feedback.png new file mode 100644 index 0000000000000000000000000000000000000000..5639ac96e246f876b462f84e93eebe234ef18432 Binary files /dev/null and b/src/assets/img/nav/feedback.png differ diff --git a/src/assets/img/nav/feedbackActive.png b/src/assets/img/nav/feedbackActive.png new file mode 100644 index 0000000000000000000000000000000000000000..eaebdce645af36a28fc2243d230d0338c8e235f3 Binary files /dev/null and b/src/assets/img/nav/feedbackActive.png differ diff --git a/src/assets/img/nav/footprint.png b/src/assets/img/nav/footprint.png new file mode 100644 index 0000000000000000000000000000000000000000..676ac98933eb53f7002e472b1ab0e335cbad1c19 Binary files /dev/null and b/src/assets/img/nav/footprint.png differ diff --git a/src/assets/img/nav/footprintActive.png b/src/assets/img/nav/footprintActive.png new file mode 100644 index 0000000000000000000000000000000000000000..d51b1fac82cb2f27a27e650de0160ccc48299248 Binary files /dev/null and b/src/assets/img/nav/footprintActive.png differ diff --git a/src/assets/img/nav/photo.png b/src/assets/img/nav/photo.png new file mode 100644 index 0000000000000000000000000000000000000000..300bddf19c0abef4213d453f6df69fe20d93cad4 Binary files /dev/null and b/src/assets/img/nav/photo.png differ diff --git a/src/assets/img/nav/photoActive.png b/src/assets/img/nav/photoActive.png new file mode 100644 index 0000000000000000000000000000000000000000..3737af1e70a527b693d841b5a1b27d5d2a145a3d Binary files /dev/null and b/src/assets/img/nav/photoActive.png differ diff --git a/src/assets/img/nav/profile.png b/src/assets/img/nav/profile.png new file mode 100644 index 0000000000000000000000000000000000000000..f64be8dc18751a65bc812aba520335d0cafdbc6e Binary files /dev/null and b/src/assets/img/nav/profile.png differ diff --git a/src/assets/img/nav/profileActive.png b/src/assets/img/nav/profileActive.png new file mode 100644 index 0000000000000000000000000000000000000000..3d3586edb3897cc9ea8111b58f6f78c4c83fe90d Binary files /dev/null and b/src/assets/img/nav/profileActive.png differ diff --git a/src/assets/img/nav/serviceData.png b/src/assets/img/nav/serviceData.png new file mode 100644 index 0000000000000000000000000000000000000000..668851804eb3886e34e1a2aac67bcd1313df7605 Binary files /dev/null and b/src/assets/img/nav/serviceData.png differ diff --git a/src/assets/img/nav/serviceDataActive.png b/src/assets/img/nav/serviceDataActive.png new file mode 100644 index 0000000000000000000000000000000000000000..1036c2fceba7f11a0a214458e37b484c142831d5 Binary files /dev/null and b/src/assets/img/nav/serviceDataActive.png differ diff --git a/src/assets/img/nav/spaceIndex.png b/src/assets/img/nav/spaceIndex.png new file mode 100644 index 0000000000000000000000000000000000000000..32e9287ce89ad1c1c675bd8de4b6a24ca5712b86 Binary files /dev/null and b/src/assets/img/nav/spaceIndex.png differ diff --git a/src/assets/img/nav/spaceIndexActive.png b/src/assets/img/nav/spaceIndexActive.png new file mode 100644 index 0000000000000000000000000000000000000000..88b485b320f7226c9507751d37b367091a2bb043 Binary files /dev/null and b/src/assets/img/nav/spaceIndexActive.png differ diff --git a/src/assets/img/property.png b/src/assets/img/property.png new file mode 100644 index 0000000000000000000000000000000000000000..415bcdd1b01a2208b192a80cf298378d1dba1888 Binary files /dev/null and b/src/assets/img/property.png differ diff --git a/src/assets/img/save.png b/src/assets/img/save.png new file mode 100644 index 0000000000000000000000000000000000000000..4d992ce69663e383a77ab775d8d999d63f8ad68d Binary files /dev/null and b/src/assets/img/save.png differ diff --git a/src/assets/img/sub-header-bg.png b/src/assets/img/sub-header-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..3a41cd0ae4ed1ba89a8a789775fd32182f6c74dc Binary files /dev/null and b/src/assets/img/sub-header-bg.png differ diff --git a/src/assets/img/test-card-photo.png b/src/assets/img/test-card-photo.png new file mode 100644 index 0000000000000000000000000000000000000000..f65006142160d81e2f3634baf26871a63d28602c Binary files /dev/null and b/src/assets/img/test-card-photo.png differ diff --git a/src/assets/img/user.png b/src/assets/img/user.png new file mode 100644 index 0000000000000000000000000000000000000000..cd6f71f49099978c777d66aa155f29a1219157da Binary files /dev/null and b/src/assets/img/user.png differ diff --git a/src/components/App/AppHeader/index.vue b/src/components/App/AppHeader/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..314a9ac443d33b7815e0fcb5726c0e601f1a9f1b --- /dev/null +++ b/src/components/App/AppHeader/index.vue @@ -0,0 +1,100 @@ +<template> + <div class="app-header"> + <div class="header-left"><img src="@/assets/img/logo.png" alt="" /></div> + <div class="header-right"> + <span class="welcome">娆㈣繋鏉ュ埌鏁板瓧绌洪棿锛�</span> + + <img src="@/assets/img/user.png" alt="" /> + <span class="user-name">鍒樹簯</span> + <img src="@/assets/img/login-out.png" alt="" /> + </div> + </div> +</template> +<script> +import dayjs from "dayjs"; +// import { appName } from "@/config"; +// import { asyncRoutesSort } from "@/router"; +// import cloneDeep from "lodash/cloneDeep"; +// console.log(asyncRoutes); + +export default { + name: "AppHeader", + data() { + return { + now: { + date: "", + time: "", + week: "", + }, + // appName, + timmer: null, + // isCollapse: false, + }; + }, + computed: { + // menus() { + // return cloneDeep(asyncRoutesSort); + // }, + // activeRouteName() { + // return this.$route.matched[0]?.name; + // }, + }, + created() { + this.timmer = setInterval(() => this.updateTime(), 1000); + }, + beforeDestroy() { + if (this.timmer) clearInterval(this.timmer); + }, + methods: { + updateTime() { + const now = dayjs(); + this.now = { + date: now.format("YYYY-MM-DD"), + time: now.format("HH:mm:ss"), + week: now.format("dddd"), + }; + }, + }, +}; +</script> +<style lang="scss" scoped> +@import "@/assets/css/variables.scss"; + +.app-header { + width: 100%; + height: 80px; + display: flex; + background-color: #2171ff; + color: #fff; + + justify-content: space-between; + align-items: center; + position: relative; + z-index: 0; +} +.header-left { + padding-left: calc(50% - 600px); +} + +.header-right { + position: relative; + z-index: 1; + display: flex; + justify-content: center; + align-items: center; + color: #fff; + padding-right: 33px; + height: 30px; + .avatar { + width: 28px; + height: 28px; + margin-left: 20px; + } + .user-name { + padding: 0 10px; + } + .date { + padding-right: 20px; + } +} +</style> diff --git a/src/components/App/BackTitle/index.vue b/src/components/App/BackTitle/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..d9bdc2a809a440f8e639e75b6b402600788f2741 --- /dev/null +++ b/src/components/App/BackTitle/index.vue @@ -0,0 +1,45 @@ +<template> + <div class="back-title"> + <i class="el-icon-arrow-left" @click="backRouter"></i> + <span>{{ title }}</span> + </div> +</template> + +<script> +export default { + name: "SubHeader", + data() { + return {}; + }, + props: { + title: { + type: String, + default: () => "鏍囬", + }, + }, + computed: {}, + watch: {}, + methods: { + backRouter() { + this.$router.back(-1); + }, + }, +}; +</script> + +<style lang="scss" scoped> +@import "@/assets/css/variables.scss"; +.back-title { + height: 56px; + line-height: 36px; + padding-top: 20px; + // cursor: pointer; + flex-shrink: 0; + span { + padding-left: 5px; + } + i { + cursor: pointer; + } +} +</style> diff --git a/src/components/App/BreadCrumb/index.vue b/src/components/App/BreadCrumb/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..fd3b388b382835026cc2a71f12f5671708892108 --- /dev/null +++ b/src/components/App/BreadCrumb/index.vue @@ -0,0 +1,166 @@ +<template> + <div class="app-bread-crumb"> + {{ pageName }} + <!-- <el-tabs + v-model="activeName" + @tab-click="handleClick" + @edit="handleTabsEdit" + > + <el-tab-pane + :label="item.meta.title" + :name="item.path" + v-for="item in pathList" + closable + :key="item.path" + ></el-tab-pane> + </el-tabs> --> + <slot></slot> + </div> +</template> + +<script> +export default { + name: "BreadCrumb", + data() { + return { + activeName: "second", + pathList: [], + }; + }, + computed: { + paths() { + const matched = this.$route.matched.filter( + (item) => item.meta && item.meta.title + ); + this.changeRouter(matched); + // console.log(matched.filter((item) => item.meta && item.meta.title)); + return matched.filter((item) => (item.meta ? item.meta.title : "")); + }, + pageName() { + return this.$route.matched[this.$route.matched.length - 1]?.meta?.title; + }, + }, + watch: { + paths() { + this.$nextTick(() => { + // console.log(this.paths); + }); + }, + }, + methods: { + changeRouter(matched) { + // console.log(matched); + if (matched.length > 1) { + matched = [matched[matched.length - 1]]; + } + if (matched[0].meta.disTab) { + return; + } + //浠庡乏渚у鑸墦寮€椤甸潰鏃舵坊鍔犲湪澶撮儴瀵艰埅锛屾病鏈夊垯鍙畾浣� + let paths = this.pathList.map((item) => item.path); + if (paths.includes(matched[0].path)) { + this.activeName = matched[0].path; + } else { + this.pathList = [...this.pathList, ...matched]; + this.activeName = matched[0].path; + } + // this.pathList = [...this.pathList, ...matched]; + // console.log(this.pathList); + }, + handleTabsEdit(targetName, action) { + // console.log(targetName); + if (action === "remove") { + if (this.pathList.length == 1) { + this.$message.info("宸茬粡鏄渶鍚庣殑椤甸潰浜嗭紝鏃犳硶鍏抽棴"); + return; + } + //鍒犻櫎缂撳瓨椤甸潰 + let findItem = this.pathList.find((item) => item.path == targetName); + // console.log(findItem); + this.$store.dispatch("app/removeCacheRoutes", findItem.name); + if (findItem.parent) { + this.$store.dispatch("app/removeCacheRoutes", findItem.parent.name); + } + //浠庡垪琛ㄥ幓鎺� + this.pathList = this.pathList.filter((item) => item.path != targetName); + if (this.$route.path == targetName) { + //鍏抽棴褰撳墠椤甸潰璺宠浆鍒版渶鍚庝竴涓〉闈� + this.$router.replace(this.pathList[this.pathList.length - 1].path); + // this.activeName = matched[0].path; + } + } + }, + handleClick(tab) { + // console.log(tab.name, event); + this.$router.push(tab.name); + }, + }, +}; +</script> + +<style lang="scss" scoped> +@import "@/assets/css/variables.scss"; + +.app-bread-crumb { + display: flex; + // margin-bottom: 20px; + // margin-bottom: 15px; + align-items: center; + justify-content: space-between; + background-color: #fff; + height: 50px; + + height: 28px; + line-height: 28px; + font-size: 18px; + font-weight: 700; + color: rgba(49, 130, 255, 1); + + // padding: 0 16px; + .app-home { + display: flex; + font-size: 20px; + color: #8d8d8d; + margin-right: 20px; + &:hover { + color: $--color-primary; + } + } + &::v-deep { + .el-tabs { + max-width: 80%; + } + .el-tabs__nav-prev, + .el-tabs__nav-next { + height: 50px; + line-height: 50px; + } + .el-tabs__header { + margin: 0; + height: 100%; + } + .el-tabs__nav-wrap { + &::after { + display: none; + } + } + .el-tabs__item, + .el-tabs, + .el-tabs__nav { + height: 50px; + line-height: 50px; + } + .router-link-active { + font-weight: 500; + color: #333333; + &:hover { + color: $--color-primary; + } + } + .el-breadcrumb__separator { + color: #333333; + margin: 0; + } + } +} +</style> diff --git a/src/components/App/Empty/index.vue b/src/components/App/Empty/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..94c67716b77a6666d41a7c6c2923e1341d8daf7c --- /dev/null +++ b/src/components/App/Empty/index.vue @@ -0,0 +1,26 @@ +<script> +export default { + functional: true, + render(h, { props, children, data }) { + return ( + <div class="c__empty" {...data}> + {children || [ + <svg-icon icon-class="empty" />, + <p>{props.tips || "鏆傛棤鏁版嵁"}</p> + ]} + </div> + ); + } +}; +</script> + +<style lang="scss"> +.c__empty { + text-align: center; + color: #8c8c8c; + + .svg-icon { + font-size: 60px; + } +} +</style> diff --git a/src/components/App/FuncComponent/index.vue b/src/components/App/FuncComponent/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..8065ee2da90410a51b1c5ab70492a960d37b03f9 --- /dev/null +++ b/src/components/App/FuncComponent/index.vue @@ -0,0 +1,25 @@ +<script> +/* +@author +@name FuncComponent +@desc render鍑芥暟缁勪欢銆愬洜涓簍emplate涓啓jsx涓嶈鑼冦€� +@props params any render鍑芥暟鎵€闇€鍙傛暟 + renderFunc function render鍑芥暟 +@emit +*/ +export default { + name: "FuncComponent", + props: { + params: { + type: [String, Number, Boolean, Array, Object, undefined] + }, + renderFunc: { + type: Function, + required: true + } + }, + render() { + return this.renderFunc(this.params); + } +}; +</script> diff --git a/src/components/App/ImgUploader/index.vue b/src/components/App/ImgUploader/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..99e60a67f7bf2129d70cd806cdfc502a248a42a9 --- /dev/null +++ b/src/components/App/ImgUploader/index.vue @@ -0,0 +1,172 @@ +<template> + <div class="ImgUploader"> + <div class="img-list"> + <div class="img-item" v-for="(item, index) in imgList" :key="index"> + <img :src="item" alt="" /> + <div class="mask"> + <i class="el-icon-search" @click="preView(item)"></i> + <i class="el-icon-delete" @click="deleteImg(item, index)"></i> + </div> + </div> + </div> + <el-upload + action="" + :before-upload=" + (file) => { + beforeUpload(file); + return false; + } + " + v-if="!readOnly" + > + <i class="el-icon-plus"></i> + <span>涓婁紶鍥剧墖</span> + </el-upload> + <el-image-viewer + v-if="dialogVisible" + :on-close=" + () => { + dialogVisible = false; + } + " + :url-list="[dialogImageUrl]" + /> + <!-- <el-dialog :visible.sync="dialogVisible" width="600px" append-to-body> + <img width="100%" :src="dialogImageUrl" alt="" /> + </el-dialog> --> + </div> +</template> +<script> +import ElImageViewer from "element-ui/packages/image/src/image-viewer"; +export default { + name: "ImgUploader", + components: { ElImageViewer }, + data: () => { + return { + dialogImageUrl: "", + dialogVisible: false, + }; + }, + props: { + value: { + type: Array, + default: () => [], + }, + readOnly: { + type: Boolean, + default: () => false, + }, + }, + computed: { + imgList: { + get: function() { + return this.value; + }, + set: function(newValue) { + this.$emit("input", newValue); + }, + }, + }, + methods: { + async beforeUpload(file) { + // console.log(file); + + let url = await this.$utils.file2Base64(file); + + this.imgList = [...this.value, url]; + return false; + // console.log(url); + // this.$set(this.form, field, url); + // return false; + // const reader = new FileReader(); + // reader.readAsDataURL(file); + // reader.onload = () => { + // const base64 = reader.result; + // // console.log(base64); + // this.imgList = [...this.value, base64]; + // }; + // reader.onerror = (error) => { + // console.log(error); + // }; + }, + deleteImg(item, index) { + this.imgList = this.imgList.filter((fitem, findex) => findex != index); + }, + preView(item) { + this.dialogImageUrl = item; + this.dialogVisible = true; + }, + }, +}; +</script> +<style lang="scss" scoped> +.ImgUploader { + display: flex; + flex-wrap: wrap; + max-width: 100%; + // padding-top: 24px; + .img-list { + display: flex; + .img-item { + width: 72px; + height: 72px; + border: 1px solid #e5e5e5; + overflow: hidden; + margin-right: 20px; + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + position: relative; + .mask { + display: none; + width: 100%; + position: absolute; + height: 100%; + left: 0; + top: 0; + color: #fff; + font-size: 22px; + background-color: rgba($color: #000000, $alpha: 0.3); + justify-content: space-around; + padding: 0 20px; + align-items: center; + ::v-deep { + i { + cursor: pointer; + } + } + } + &:hover { + .mask { + display: flex; + } + } + img { + width: 100%; + height: 100%; + } + } + } + ::v-deep { + .el-upload { + width: 72px; + height: 72px; + border: 1px dashed #e5e5e5; + display: flex; + flex-flow: column; + justify-content: center; + align-items: center; + font-size: 12px; + line-height: 22px; + color: #808080; + span { + padding-top: 6px; + } + i { + font-size: 18px; + } + } + } +} +</style> diff --git a/src/components/App/PubDialog/index.vue b/src/components/App/PubDialog/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..3875851fa01aaff7475e57b011a218b7d06d46a8 --- /dev/null +++ b/src/components/App/PubDialog/index.vue @@ -0,0 +1,155 @@ +<template> + <el-dialog + :title="title" + width="720px" + append-to-body + :visible.sync="dialogVisible" + :before-close="beforeClose" + class="PubDialog" + > + <div class="dialog-main"> + <div class="slot-box"> + <slot></slot> + </div> + </div> + <!-- <span slot="footer" class="dialog-footer"> + <el-button @click="dialogVisible = false">鍙� 娑�</el-button> + <el-button type="primary" @click="dialogVisible = false">纭� 瀹�</el-button> + </span> --> + </el-dialog> +</template> +<script> +export default { + name: "VideoDialog", + data: () => { + return { + // dialogVisible: false, + }; + }, + props: { + value: { + type: Boolean, + default: () => false, + }, + title: { + type: String, + default: () => "鏍囬", + }, + }, + computed: { + dialogVisible: { + get: function(that) { + return that.value; + }, + set: function(newValue) { + this.$emit("input", newValue); + }, + }, + }, + methods: { + beforeClose() { + // console.log('beforeClose'); + // this.dialogVisible = false; + this.$emit("beforeClose"); + }, + }, +}; +</script> +<style lang="scss" scoped> +// .PubDialog { +::v-deep { + .el-dialog { + border-radius: 8px; + } + .el-dialog__header { + height: 52px; + display: flex; + justify-content: space-between; + align-items: center; + + padding: 0 16px 0 20px; + border-bottom: 1px solid #e5e5e5; + .el-dialog__title { + font-size: 14px; + color: #000; + } + .el-dialog__headerbtn .el-dialog__close { + font-size: 20px; + color: #c4c4c4; + } + } +} +// .el-dialog__header { +// padding: 0; +// } +// .el-dialog__body { +// padding: 24px; +// background: #041740; +// // border: 3px solid #c6e7ff; +// box-shadow: inset 0px 0px 26px #289aff; +// color: #fff; +// position: relative; +// min-height: 460px; +// .dialog-back { +// position: absolute; +// z-index: 1; +// width: 100%; +// height: 100%; +// left: 0; +// top: 0; +// img { +// width: 100%; +// height: 100%; +// } +// } +// } +// .dialog-btns { +// display: flex; +// justify-content: flex-end; +// padding-top: 24px; +// } +// .el-button { +// height: 28px; +// line-height: 28px; +// padding: 0 30px; +// } +// .el-button--primary.is-plain { +// background-color: transparent; +// border-color: #1e81ff; +// &:hover { +// background-color: #1e81ff; +// color: #fff; +// } +// } +// } + +// .dialog-main { +// position: relative; +// z-index: 2; +// .header { +// width: 100%; +// height: 52px; +// background: linear-gradient(90deg, #289aff 0%, rgba(#289aff, 0) 100%); +// padding: 0 20px; +// display: flex; +// justify-content: space-between; +// align-items: center; + +// font-size: 18px; +// font-weight: bold; +// letter-spacing: 2px; +// .box-icon { +// margin-right: 12px; +// } +// .close { +// width: 25px; +// height: 25px; +// cursor: pointer; +// } +// } +// } +// .slot-box { +// padding: 34px 26px; +// } +// } +</style> diff --git a/src/components/App/SideBar/index.vue b/src/components/App/SideBar/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..4f1d27d3143a8b0369761033ca38de0aa2741f71 --- /dev/null +++ b/src/components/App/SideBar/index.vue @@ -0,0 +1,326 @@ +<script> +// import { appName } from "@/config"; +import { asyncRoutesSort } from "@/router"; +import cloneDeep from "lodash/cloneDeep"; +// import logo from "@/assets/img/logo.png"; + +export default { + name: "SideBar", + data() { + return { + // appName, + }; + }, + props: { + isCollapse: { + type: Boolean, + default: () => false, + }, + }, + computed: { + menus() { + let allMenu = this.treeMap(cloneDeep(asyncRoutesSort)); + console.log(allMenu); + // let findFatherItem = allMenu; + + return allMenu; + // let findFatherItem = allMenu.find( + // (item) => item.name == this.mainMenuName + // ); + // if (findFatherItem) { + // return findFatherItem.children || []; + // } else { + // return []; + // } + }, + + mainMenuName() { + return this.$route.matched[0]?.name; + }, + + activeRouteName() { + const { name } = this.$route; + // console.log(name, this.$route); + if(this.$route?.meta?.activeName){ + return this.$route.meta.activeName + } + return name; + }, + }, + methods: { + treeMap(list) { + // console.log(list); + let res = list.map((item) => { + if (item.children) { + return { + ...item, + children: this.treeMap(item.children), + }; + } else { + return { + ...item, + }; + } + }); + // console.log(res); + res = res.filter((item) => !item.meta.hidden); + return res.length ? res : null; + }, + routeTo(indexs) { + let path = ""; + let route = this.menus; + indexs = indexs.split("-"); + indexs.forEach((index) => { + route = route[index] || route.children[index]; + if (/^\//.test(route.path)) { + path = path + route.path; + } else { + path = path + "/" + route.path; + } + }); + // path = "/" + path; + // path = "/" + this.mainMenuName + path; + // console.log(path); + this.$router.push(path); + }, + getImgPath(iconImg) { + try { + let file = require(`../../../assets/img/nav/${iconImg}.png`); + return file; + } catch (error) { + return ""; + } + // return require(`../../../assets/img/nav/${iconImg}.png`); + + // <span class="title-span" slot="title"> + // <div class="icon-box"> + // {item.meta.iconImg ? ( + // <img src={getImgPath(item.meta.iconImg)}></img> + // ) : ( + // <span></span> + // )} + // </div> + // {item.meta.title} + // </span> + }, + + renderMenus(menus, propIndex = "") { + let getImgPath = this.getImgPath; + return menus.map((item, index) => { + return item.children ? ( + <el-submenu index={item.name} key={propIndex + index}> + <span class="title-span" slot="title"> + {item.meta.icon ? <i class={item.meta.icon}></i> : <span></span>} + {item.meta.title} + </span> + {item.children + ? this.renderMenus(item.children, propIndex + index + "-") + : null} + </el-submenu> + ) : ( + <el-menu-item + key={propIndex + index} + index={item.name} + onClick={() => this.routeTo(String(propIndex + index))} + > + {item.meta.iconImg ? ( + <span class="title-span" slot="title"> + <div class="icon-box"> + {item.meta.iconImg ? ( + <div class="flex-center"> + <img + src={getImgPath(item.meta.iconImg)} + class="img-icon" + ></img> + <img + src={getImgPath( + item.meta.iconImgActive + ? item.meta.iconImgActive + : item.meta.iconImg + )} + class="img-icon-active" + ></img> + </div> + ) : ( + <span></span> + )} + </div> + {item.meta.title} + </span> + ) : ( + <div> + {item.meta.icon ? ( + <i class={item.meta.icon}></i> + ) : ( + <span></span> + )} + {item.meta.title} + </div> + )} + </el-menu-item> + ); + }); + }, + }, + render() { + const menus = this.menus; + // const appName = this.appName; + return ( + <div class={menus.length ? "side-bar" : "side-bar hide"}> + <div class="side-bar-body"> + <el-menu + collapse={this.isCollapse} + defaultActive={this.activeRouteName} + // default-active="1-4-1" + > + {this.renderMenus(menus)} + </el-menu> + </div> + </div> + ); + }, +}; +</script> +<style lang="scss" scoped> +@import "@/assets/css/variables.scss"; + +.side-bar { + width: 240px; + height: calc(100%); + border-radius: 8px; + box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05); + display: flex; + flex-shrink: 0; + flex-direction: column; + transition: all 0.2s; + background-color: #fff; + position: relative; + padding-top: 14px; + &.hide { + width: 0; + } + ::v-deep { + .el-menu { + width: 240px; + background: transparent; + + &.el-menu--collapse { + width: 60px; + } + } + } +} +.side-bar-body { + width: 100%; + height: 100%; + display: block; + &::v-deep { + .el-menu { + border-right: none; + } + .el-submenu__title { + transition: all 0.3s; + width: 200px; + height: 35px; + line-height: 35px; + background: rgba(82, 162, 255, 0.2); + color: #5e5e5e; + font-size: 14px; + display: flex; + } + // li { + // line-height: 40px; + // } + .el-menu-item { + transition: all 0.3s; + width: 200px; + height: 35px; + line-height: 35px; + // background: rgba(82, 162, 255, 0.2); + background: transparent; + border-radius: 8px; + color: #5e5e5e; + font-size: 14px; + display: flex; + align-items: center; + + margin: 6px auto; + } + + .el-menu-item:hover, + .el-menu-item:focus, + .el-submenu__title:hover, + .el-submenu__title:focus { + color: #3182ff; + position: relative; + i { + color: #3182ff; + } + + .icon-box { + img { + &.img-icon { + display: none; + } + &.img-icon-active { + display: inline-block; + } + } + } + } + .el-menu-item.is-active, + .el-submenu .el-menu-item.is-active, + .el-submenu__title.is-active { + background: rgba($color: #52a2ff, $alpha: 0.2); + color: #3182ff; + position: relative; + i { + color: #3182ff; + } + } + .el-menu-item [class^="el-icon-"] { + margin-right: 10px; + } + + .el-submenu__title i { + } + } +} +.title-span { + display: flex; + align-items: center; +} +.icon-box { + display: flex; + align-items: center; + vertical-align: middle; + // width: 40px; + height: 100%; + margin-left: 3px; + margin-right: 14px; + img { + width: 18px; + height: 18px; + &.img-icon-active { + display: none; + } + &.img-icon { + display: inline-block; + } + } +} +::v-deep { + .is-active { + .icon-box { + img { + &.img-icon { + display: none; + } + &.img-icon-active { + display: inline-block; + } + } + } + } +} +</style> diff --git a/src/components/App/SubHeader/index.vue b/src/components/App/SubHeader/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..f93b913c7dd280012d1a223c6c5da95155d6008f --- /dev/null +++ b/src/components/App/SubHeader/index.vue @@ -0,0 +1,86 @@ +<template> + <div class="sub-header"> + <div class="user-info flex"> + <div class="avatar"> + <img src="@/assets/img/avatar-test.png" alt="" /> + </div> + <div class="info"> + <div>鎮ㄥソ锛屾杩庣櫥褰晘</div> + <div class="name">鏉庝簯</div> + <div class="level"> + <span>璁よ瘉绛夌骇锛�</span> + <div class="level-box">鍥涚骇璁よ瘉</div> + </div> + </div> + </div> + </div> +</template> + +<script> +export default { + name: "SubHeader", + data() { + return {}; + }, + computed: {}, + watch: {}, + methods: {}, +}; +</script> + +<style lang="scss" scoped> +@import "@/assets/css/variables.scss"; + +.sub-header { + width: 1200px; + height: 196px; + flex-shrink: 0; + background: url("../../../assets/img/sub-header-bg.png"); + background-size: 100% 100%; + color: #fff; + .user-info { + align-items: center; + height: 100%; + width: 100%; + padding-left: 54px; + } + .avatar { + width: 80px; + height: 80px; + border-radius: 50%; + overflow: hidden; + + box-shadow: 0px 2px 6px rgba($color: #000000, $alpha: 0.2); + img { + width: 100%; + height: 100%; + } + } + .info { + padding-left: 20px; + font-size: 18px; + line-height: 28px; + .name { + font-size: 20px; + } + .level { + font-size: 12px; + color: rgba($color: #fff, $alpha: 0.7); + display: flex; + align-items: center; + .level-box { + width: 67px; + height: 20px; + opacity: 1; + border-radius: 10px; + background: #ffffff; + display: flex; + justify-content: center; + align-items: center; + font-size: 12px; + color: rgba(0, 59, 161, 1); + } + } + } +} +</style> diff --git a/src/components/App/Table/TableHeader/index.vue b/src/components/App/Table/TableHeader/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..71b5f0f9a4bb3be6373b6faf9f356755c7505a4a --- /dev/null +++ b/src/components/App/Table/TableHeader/index.vue @@ -0,0 +1,578 @@ +<template> + <el-form + class="table-header" + ref="form" + v-if="paramsGroups || params.length || showHeader" + > + <div class="table-header-row"> + <!-- <slot v-if="$slots.default"></slot> --> + <template v-if="paramsGroups"> + <!-- 閫夋嫨 --> + <el-form-item class="group-item" v-if="paramsGroups.select"> + <el-select + class="label-select" + v-model="select.key" + @change="changeHandler($event, 'select')" + > + <el-option + v-for="item in paramsGroups.select" + :value="item.value" + :label="item.label" + :key="item.value" + > + </el-option> + </el-select> + <component + class="value-input" + @change="updateData()" + v-model="select.val" + :is="select.component" + v-if="select.component" + v-bind="{ ...select.elAttrs }" + > + </component> + <el-select + v-else + class="value-input" + v-model="select.val" + @change="updateData()" + > + <el-option + v-for="item in paramsGroups.options[select.key]" + :label="item.label" + :value="item.value" + :key="item.value" + > + </el-option> + </el-select> + </el-form-item> + <!-- 杈撳叆 --> + <el-form-item class="group-item" v-if="paramsGroups.inputs"> + <el-select + class="label-select" + v-model="inputs.key" + @change="changeHandler($event, 'input')" + > + <el-option + v-for="item in paramsGroups.inputs" + :label="item.label" + :value="item.value" + :key="item.value" + > + </el-option> + </el-select> + <el-input + class="value-input" + maxlength="20" + v-model="inputs.val" + @change="updateData()" + ></el-input> + </el-form-item> + <!-- 鑼冨洿 --> + <el-form-item class="group-item" v-if="paramsGroups.ranges"> + <el-select + class="label-select" + v-model="ranges.label" + @change="changeHandler($event, 'ranges')" + > + <el-option + v-for="item in paramsGroups.ranges" + :value="item.label" + :label="item.label" + :key="item.label" + > + </el-option> + </el-select> + <component + @change="updateData()" + v-model="ranges.val" + :is="ranges.component" + v-bind="{ ...ranges.elAttrs }" + > + </component> + </el-form-item> + </template> + <template v-else> + <div + v-for="(item, index) in params" + :key="index" + style="display: inline-block;" + > + <el-form-item :class="{ empty: !item.label }" :label="item.label"> + <FuncComponent + v-if="item.renderFunc" + :renderFunc="item.renderFunc" + ></FuncComponent> + <component + v-else + :type="item.type" + clearable + size="small" + @change="search(1)" + :options="item.options" + v-model="data[item._key]" + v-bind="{ ...item.elAttrs }" + :placeholder="item.placeholder" + :is="item.component || 'el-input'" + > + <template v-if="item.component === 'el-select'"> + <template v-if="options[item._key]"> + <el-option + v-for="(_it, _i) in options[item._key]" + :key="index + '-' + _i" + :label="_it.label" + :value="_it.value" + ></el-option> + </template> + <template v-else> + <el-option + v-for="(_it, _i) in item.options" + :key="index + '-' + _i" + :label="_it.label" + :value="_it.value" + ></el-option> + </template> + </template> + </component> + </el-form-item> + </div> + </template> + <template v-if="paramsGroups || params.length"> + <el-form-item class="btn-item"> + <el-button + v-if="searchBtn" + type="primary" + size="small" + @click="search()" + >鏌ヨ</el-button + > + </el-form-item> + <el-form-item class="btn-item"> + <el-button + v-if="resetBtn" + size="small" + type="primary" + @click="reset" + plain + >閲嶇疆</el-button + > + </el-form-item> + </template> + <slot name="tableHeaderSlot"></slot> + </div> + + <!-- <div class="btns"> + + </div> --> + <div class="btn-right"><slot name="btnRight"></slot></div> + </el-form> +</template> +<script> +/* +@author +@name TableHeader +@desc 琛ㄥご绛涢€夌粍浠� +@props params Array< + label string label + default string|number 榛樿鍊� + key string form鐨刱ey + type string 缁勪欢浼犻€掔殑type鍊� + component string 缁勪欢鍚嶇О锛屽锛歟l-input + placeholder string placeholder + renderFunc function:VNode 鑷畾涔夋覆鏌撳嚱鏁� + elAttrs object element瀵瑰簲缁勪欢鐨勫睘鎬э紙閰嶇疆锛� + options object<{ el-select鏃剁殑options + label string 閫夐」label + value string 閫夐」value + }> + }> + paramsGroups object< 鍙傛暟缁� + inputs Array<{ 杈撳叆鍙傛暟锛堥粯璁ょ涓€涓� + label string 閫夋嫨鐨刲abel + value string 閫夋嫨鐨剉alue + }> + select Array<{ 閫夋嫨鍙傛暟锛堥粯璁ょ涓€涓� + label string 閫夋嫨鐨刲abel + value string 閫夋嫨鐨剉alue + elAttrs object 瀵瑰簲缁勪欢鐨勫睘鎬� + component string 鎸囧畾缁勪欢鐨勫悕绉帮紝浼樺厛浣跨敤璇ラ厤缃� + }> + ranges Array<{ + label string 閫夋嫨鐨刲abel + keys Array<string> 鍙傛暟瀵瑰簲鐨刱ey锛岄『搴忔帓鍒� + elAttrs object 瀵瑰簲缁勪欢鐨勫睘鎬� + component string 瀵瑰簲鐨勭粍浠跺悕绉� + }> + options object<Val> select瀵瑰簲鐨勯€夐」瀵硅薄锛宬ey涓簊elect瀵瑰簲鐨剉alue + Array<{ select瀵瑰簲鐨勯€夐」 + label string 閫夐」鐨刲abel + value strine 閫夐」鐨剉alue + }> + > + searchBtn boolean 鏄惁鏄剧ず鎼滅储鎸夐挳[true] + resetBtn boolean 鏄惁鏄剧ず閲嶇疆鎸夐挳[true] + showHeader boolean 鏄惁鍦ㄦ病鏈塰eaders鐨勬椂鍊欐樉绀哄ご閮� +@slot slot 鎺ュ彈涓€涓粯璁ゆ彃妲� +@desc header鍐呭浼樺厛绾� slot> paramsGroup >params +@emit +*/ +// 涓嶄娇鐢� import {} 鏄洜涓篈pp閲岄潰鐨凙reaSelect涓緷璧朙inkageSelect锛屼細浜х敓寰幆寮曠敤 +import cloneDeep from "lodash/cloneDeep"; +import FuncComponent from "@/components/App/FuncComponent"; + +export default { + name: "TableHeader", + components: { + FuncComponent, + }, + props: { + params: { + type: Array, + default: () => [], + }, + options: { + type: Object, + default: () => { + return {}; + }, + }, + + showHeader: { + type: Boolean, + default: true, + }, + searchBtn: { + type: Boolean, + default: true, + }, + resetBtn: { + type: Boolean, + default: true, + }, + paramsGroups: { + type: Object, + default: null, + }, + }, + data() { + return { + data: {}, + inputs: { + key: "", + val: "", + }, + select: { + key: "", + val: "", + elAttrs: {}, + component: "", + }, + ranges: { + val: [], + keys: [], + elAttrs: {}, + component: "", + }, + }; + }, + created() { + this.initParams(); + this.initParamsGroups(); + }, + methods: { + reset() { + console.log(this.data); + for (let p in this.data) { + // if (Array.isArray(this.data[p])) { + // // const index = parseInt(p.substring(6)); + // // if (this.params[index] && this.params[index].default) { + // // this.$set(this.data, p, this.params[index].default); + // // } else { + // // this.$set(this.data, p, []); + // // } + // this.$set(this.data, p, []); + // } + if (/^param-/.test(p)) { + const index = parseInt(p.substring(6)); + if (this.params[index] && this.params[index].default) { + this.$set(this.data, p, this.params[index].default); + } else { + this.$set(this.data, p, []); + } + } else if (Array.isArray(this.data[p])) { + this.$set(this.data, p, []); + } else if (typeof this.data[p] === "object") { + this.$set(this.data, p, {}); + } else { + this.$set(this.data, p, ""); + } + } + this.inputs.val = ""; + this.select.val = ""; + this.ranges.val = []; + this.$emit("search"); + }, + search(force) { + // console.log(this.data); + if (force) { + if (!this.searchBtn) { + this.$emit("search"); + } + } else { + this.$emit("search"); + } + }, + initParams() { + const data = {}; + this.params.forEach((item, index) => { + item.elAttrs = item.elAttrs || {}; + if (typeof item.key === "string") { + data[item.key] = item.default || ""; + item._key = item.key; + } else { + item._key = "param-" + index; + data["param-" + index] = item.default || ""; + } + }); + this.data = data; + // console.log(this.params); + // console.log(this.data); + }, + initParamsGroups() { + if (!this.paramsGroups) return; + if (this.paramsGroups.inputs && this.paramsGroups.inputs.length) { + this.inputs = { + val: "", + key: this.paramsGroups.inputs[0].value, + }; + } + if (this.paramsGroups.select && this.paramsGroups.select.length) { + this.select = { + val: "", + key: this.paramsGroups.select[0].value, + elAttrs: this.paramsGroups.select[0].elAttrs || {}, + component: this.paramsGroups.select[0].component || "", + }; + } + if (this.paramsGroups.ranges && this.paramsGroups.ranges.length) { + const range = this.paramsGroups.ranges[0]; + this.ranges = { + keys: range.keys, + label: range.label, + component: range.component, + elAttrs: range.elAttrs || {}, + val: range.keys.map(() => ""), + }; + } + this.updateData(true); + }, + changeHandler(value, type) { + if (type === "input") { + this.$set(this.inputs, "val", ""); + } else if (type === "select") { + this.$set(this.select, "val", ""); + const item = this.paramsGroups.select.find((it) => it.value === value); + this.$set(this.select, "component", item.component); + this.$set(this.select, "elAttrs", item.elAttrs || {}); + } else { + const item = this.paramsGroups.ranges.find((it) => it.label === value); + const val = item.keys.map(() => ""); + this.$set(this.ranges, "val", val); + this.$set(this.ranges, "keys", item.keys); + this.$set(this.ranges, "component", item.component); + this.$set(this.ranges, "elAttrs", item.elAttrs || {}); + } + this.updateData(); + }, + // stop:boolean 鏄惁鏆傚仠鎼滅储 + updateData(stop = false) { + const paramsRanges = {}; + let selectVal = this.select.val; + // console.log(this.ranges); + // setTimeout(() => { + // console.log(this.ranges); + // }, 2000); + this.ranges.keys.forEach((key, index) => { + paramsRanges[key] = this.ranges.val ? this.ranges.val[index] : ""; + }); + if ( + selectVal === "鍏ㄩ儴" && + this.select.component === "ModelAreaTreeSelect" + ) { + selectVal = ""; + } + + this.data = { + [this.inputs.key]: this.inputs.val, + [this.select.key]: selectVal, + ...paramsRanges, + }; + if (stop) return; + this.search(1); + }, + setParamsVal(o) { + const data = cloneDeep(this.data); + for (let p in o) { + const index = this.params.findIndex( + (item) => JSON.stringify(item.key) === p + ); + if (index === -1) continue; + data[this.params[index]._key] = o[p]; + } + this.data = data; + }, + }, +}; +</script> +<style lang="scss" scoped> +@import "@/assets/css/variables.scss"; +.label-select { + ::v-deep { + .el-input__inner { + border: none; + padding-left: 0; + border-radius: 2px; + background-color: transparent; + } + } +} +.table-header { + padding: 22px 15px 0 0; + ::v-deep { + .el-tag.el-tag--info { + display: flex; + max-width: 90px; + } + } + // display: flex; + // .btns { + // margin-top: 15px; + // } + .table-header-row { + display: flex; + flex: 1; + margin-right: -30px; + flex-wrap: wrap; + } + .table-header-btns { + .el-button { + width: 56px; + height: 32px; + background: #0071e3; + border-radius: 2px; + line-height: 32px; + padding: 0; + } + } + .table-header-btns { + display: flex; + } + &::v-deep { + .el-form-item { + display: flex; + margin-bottom: 0; + align-items: center; + margin-right: 30px; + margin-bottom: 27px; + height: 32px; + &.btn-item { + margin-right: 10px; + } + } + .el-form-item__label { + // width: 96px; + font-size: 12px; + height: 32px; + line-height: 32px; + padding-right: 22px; + } + .el-form-item__content { + .el-input, + .el-select { + width: 180px; + height: 32px; + display: flex; + .el-input__inner { + height: 32px; + line-height: 30px; + border-radius: 2px; + background-color: transparent; + } + .el-input__suffix { + top: 1px; + height: 30px; + line-height: 30px; + } + } + .el-date-editor { + height: 32px; + display: flex; + padding: 0 10px; + } + } + .el-select .el-input .el-select__caret, + .el-cascader .el-input .el-icon-arrow-down { + line-height: 30px; + } + .empty { + .el-form-item__label { + display: none; + } + } + .area-select { + width: 318px; + } + .flex-input { + .el-select { + width: 96px; + } + .el-input { + margin-left: 0; + } + } + + .group-item { + // flex: 1; + margin-right: 20px; + &:last-child { + flex: 2; + } + .el-form-item__content { + width: 100%; + display: flex; + } + .el-select:first-child { + width: 120px; + } + .el-slider { + flex: 1; + height: 32px; + margin-left: 20px; + } + .el-slider__runway { + margin: 13px 0; + } + .el-date-editor--daterange.el-input__inner, + .el-date-editor--datetimerange.el-input__inner { + // flex: 1; + // width: auto; + border-radius: 2px; + width: 480px; + } + } + .table_select { + display: flex; + align-items: center; + padding-top: 15px; + .select_title { + font-size: 14px; + margin-right: 15px; + color: $--color-text-regular; + } + } + } +} +.btn-right { + margin-bottom: 18px; +} +</style> diff --git a/src/components/App/Table/index.vue b/src/components/App/Table/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..958f675ffa7d7a93e672256c9d4fb955127c90bd --- /dev/null +++ b/src/components/App/Table/index.vue @@ -0,0 +1,546 @@ +<template> + <div class="base-table"> + <div class="base-table-header"> + <TableHeader + :params="params" + :options="options" + @search="loadData(1)" + ref="refTableHeader" + :resetBtn="resetBtn" + :searchBtn="searchBtn" + :paramsGroups="paramsGroups" + :showHeader="showHeader" + > + <slot name="tableHeader"></slot> + <template slot="tableHeaderRight"> + <slot name="tableHeaderRight"></slot> + </template> + <template slot="btnRight"> + <slot name="btnRight"></slot> + </template> + <template slot="tableHeaderSlot"> + <slot name="tableHeaderSlot"></slot> + </template> + </TableHeader> + </div> + <div class="add-line"><slot name="tableAdd"></slot></div> + <div class="base-table-body" ref="refTableBody" v-loading="loading"> + <el-table + :height="height" + :data="tableData" + ref="refInnerTable" + size="small" + stripe + v-bind="{ ...table }" + @sort-change="sortChange" + @selection-change="$emit('selection-change', $event)" + > + <el-table-column + v-if="table.selection" + type="selection" + width="55" + :selectable="checkboxSelect" + > + </el-table-column> + <template v-for="(column, index) in tableColumns"> + <el-table-column + v-if="column.renderFun" + v-bind="{ ...column }" + :key="index" + > + <template slot-scope="scope"> + <FuncComponent + :params="scope" + :renderFunc="column.renderFun" + ></FuncComponent> + </template> + </el-table-column> + + <template v-else> + <el-table-column + :key="index" + v-bind="{ ...column }" + ></el-table-column> + </template> + </template> + </el-table> + </div> + <div v-if="pagination" class="base-table-footer" ref="refTableFooter"> + <slot name="tableFooter"></slot> + <el-pagination + background + :total="total" + :current-page="page" + :page-size="pageSize" + :page-sizes="pageSizes" + prev-text="涓婁竴椤�" + next-text="涓嬩竴椤�" + @size-change="handleSizeChange" + @current-change="handleCurrentChange" + layout="prev,pager,next" + > + </el-pagination> + </div> + </div> +</template> +<script> +/* +@author +@name Table +@desc 鍩虹琛ㄦ牸缁勪欢[鎼滅储鏉′欢+鍐呭+缈婚〉鍖哄煙] +@props table object<{ 琛ㄦ牸閰嶇疆锛屽弬鑰僥l-table;鏃犻渶瀹氫箟data锛屽惁鍒欏皢瑕嗙洊缁勪欢鍐卍ata,浠呮墿灞曚互涓嬪睘鎬� + page number 榛樿椤电爜[1] + pageSize number 榛樿椤电爜鏉℃暟[10] + selection boolean 鏄惁鍙瓫閫� + }> + checkboxSelect function 褰搒election涓簍rue鍗冲彲绛涢€夋椂鐨勭鐢� + + params Array<{ 琛ㄦ牸璇锋眰鎵€闇€鍙傛暟锛岀粍浠跺皢鑷姩娣诲姞椤电爜 + component string 鍏ㄥ眬缁勪欢 global-component 鍙� TableHeader 宸插鍏ョ粍浠� + label string 琛ㄥ崟椤筶abel + type string 缁勪欢type灞炴€� + key string 鍙傛暟key + placeholder string placeholder + options array<{ + label string label + value string value + }> + }> + options object<{ options + label string label + value string value + }> + + paramsGroups object< 鍙傛暟缁� + inputs Array<{ 杈撳叆鍙傛暟锛堥粯璁ょ涓€涓� + label string 閫夋嫨鐨刲abel + value string 閫夋嫨鐨剉alue + }> + select Array<{ 閫夋嫨鍙傛暟锛堥粯璁ょ涓€涓� + label string 閫夋嫨鐨刲abel + value string 閫夋嫨鐨剉alue + }> + ranges Array<{ + label string 閫夋嫨鐨刲abel + keys Array<string> 鍙傛暟瀵瑰簲鐨刱ey锛岄『搴忔帓鍒� + component string 瀵瑰簲鐨勭粍浠跺悕绉� + }> + options object<Val> select瀵瑰簲鐨勯€夐」瀵硅薄锛宬ey涓簊elect瀵瑰簲鐨剉alue + Array<{ select瀵瑰簲鐨勯€夐」 + label string 閫夐」鐨刲abel + value strine 閫夐」鐨剉alue + }> + > + + headers array<{ 鑷畾涔夎〃澶� + field string 瀛楁鍚� + dataField string 瀛楁鍚� + fieldName string 瀛楁涓枃鍚� + sort boolean 鏄惁鍙帓搴� + sortBy String/Array/Function(row, index) 鍙傝€僥l-table + sortMethod Function(a, b) 鍙傝€僥l-table + }> + + columns object<{ 琛ㄦ牸鍒楅厤缃紝鍙傝€僥l-table锛涘鎺ュ彛杩斿洖琛ㄥご锛屽垯灏嗕細瀵硅〃澶磋繘琛屽悎骞讹紝鏃犻渶閲嶅瀹氫箟label锛屽鏋渉eaders涓湭鍖呭惈colums涓殑灞炴€э紝鍒欎細灏嗘湭鍖呭惈鐨勫睘鎬ф斁缃埌鏈€鍚庛€備粎鎵╁睍浠ヤ笅灞炴€� + renderFun function render鍑芥暟锛宻cope 浣滀负鍏ュ弬 + }> + + pageKeys object<{ 椤电爜鍜屾瘡椤垫暟閲忕殑key + page string 椤电爜 default page + size string 姣忛〉鏁伴噺 default pageSize + }> + + fetcher function 鑾峰彇鏁版嵁鐨勬柟娉� + + searchBtn boolean 鏄惁鏄剧ず鎼滅储鎸夐挳[true] + + resetBtn boolean 鏄惁鏄剧ず閲嶇疆鎸夐挳[true] + + showHeader boolean 鏄惁鍦ㄦ病鏈塰eaders鐨勬椂鍊欐樉绀哄ご閮� + + pagination boolean 鏄惁闇€瑕佸垎椤礫true] + +@slot tableHeader 琛ㄥごslot + tableHeaderRight 琛ㄥご鎼滅储鎸夐挳鏃乻lot锛岀敤浜庢坊鍔犳寜閽瓑 + tableFooter 琛ㄨ剼鍐呭锛岀敤浜庢坊鍔犲簳閮ㄦ寜閽瓑 +@refMethod setParamsVal object 璁剧疆params鍙傛暟鍊�,key涓簆arams鐨刱ey(蹇呴』杞琂SON)锛寁al涓簆arams鐨勫€硷紝浼氳嚜鍔ㄦ牴鎹甼ey鐨勭被鍨嬭繘琛岃祴鍊� +@emit +@waring 涓婃柟閮ㄥ垎灞炴€ф毚闇插嚭鏉ラ渶瑕佺洿鎺ョ粦瀹氾紝鍒囧嬁鍏ㄩ儴浣跨敤 elAttr ,瀛樺湪灞炴€ц鐩栧鑷存煇浜涘睘鎬х粦瀹氬け璐� +*/ +import TableHeader from "./TableHeader"; +import FuncComponent from "@/components/App/FuncComponent"; +export default { + name: "Table", + props: { + table: { + type: Object, + default: () => ({}), + }, + params: { + type: Array, + default: () => [], + }, + options: { + type: Object, + default: () => ({}), + }, + headers: { + type: Array, + default: () => [], + }, + columns: { + type: Object, + default: () => ({}), + }, + fetcher: { + type: Function, + }, + searchBtn: { + type: Boolean, + default: true, + }, + resetBtn: { + type: Boolean, + default: true, + }, + pageKeys: { + type: Object, + default: () => ({ + page: "current", + size: "size", + }), + }, + paramsGroups: { + type: Object, + default: () => null, + }, + pagination: { + type: Boolean, + default: true, + }, + showHeader: { + type: Boolean, + default: false, + }, + checkboxSelect: { + type: Function, + default: () => { + return true; + }, + }, + }, + components: { + TableHeader, + FuncComponent, + }, + data() { + return { + total: 0, + fixed: false, + height: null, + tableData: [], + fieldName: "", + fieldSort: "", + loading: false, + tableColumns: [], + page: this.table.page || 1, + pageSize: this.table.pageSize || 10, + pageSizes: this.table.pageSizes || [10, 20, 50, 100], + }; + }, + activated() { + this.calcHeight(); + this.scrollTop(); + }, + mounted() { + for (let p in this.columns) { + if (this.columns[p].fixed) { + this.fixed = true; + break; + } + } + if (this.fetcher) this.loadData(); + if (this.fixed) this.scrollHandler(1); + window.addEventListener("resize", this.calcHeight); + }, + + beforeDestroy() { + if (this.fixed) this.scrollHandler(0); + window.removeEventListener("resize", this.calcHeight); + }, + methods: { + mergeColumns(res) { + if (this.headers.length) { + const fields = []; + const tableColumns = this.headers.map((item) => { + fields.push(item.field); + // console.log(item); + return { + ...item, + prop: item.field, + // sortable: item.sort, + label: item.fieldName, + "sort-by": item.sortBy, + ...this.columns[item.field], + "sort-method": item.sortMethod, + // sortable: item.sort ? "custom" : false, + // sortable:'custom', + type: item.field === "index" ? "index" : null, + width: item.field === "index" ? "62px" : item.width, + index: item.field === "index" ? this.indexMethod : null, + }; + }); + for (let p in this.columns) { + if (!fields.includes(p)) { + tableColumns.push(this.columns[p]); + } + } + this.tableColumns = tableColumns; + // console.log(this.tableColumns); + } else { + if (!this.tableColumns.length) { + const fields = []; + const tableColumns = res.headers.map((item) => { + fields.push(item.field); + return { + ...item, + prop: item.field, + // sortable: item.sort, + label: item.fieldName, + "sort-by": item.sortBy, + ...this.columns[item.field], + "sort-method": item.sortMethod, + type: item.field === "index" ? "index" : null, + width: item.field === "index" ? "62px" : item.width, + index: item.field === "index" ? this.indexMethod : null, + }; + }); + for (let p in this.columns) { + if (!fields.includes(p)) { + tableColumns.push(this.columns[p]); + } + } + this.tableColumns = tableColumns; + } + } + }, + + async loadData(page) { + this.loading = true; + if (page) this.page = page; + try { + const params = { + [this.pageKeys.page]: this.page, + [this.pageKeys.size]: this.pageSize, + }; + if (this.fieldSort) { + params.orderBy = this.fieldName; + params.orderByType = this.fieldSort; + } + if (this.$refs.refTableHeader) { + const data = this.$refs.refTableHeader.data; + for (let p in data) { + if (/^param-/.test(p)) { + const index = parseInt(p.substring(6)); + if (this.params[index] && Array.isArray(this.params[index].key)) { + this.params[index].key.forEach((key, _index) => { + params[key] = data[p]?.[_index] || ""; + }); + } else { + for (let _p in data[p]) { + params[_p] = data[p][_p]; + } + } + } else { + params[p] = data[p]; + // eslint-disable-next-line valid-typeof + if (typeof data[p] == "object" || typeof data[p] == "array") { + params[p] = data[p].join(","); + } + } + } + // console.log(data); + } + //console.log(params); + let res = await this.fetcher(params); + setTimeout(() => { + if (!res) { + res = { data: [] }; + } + this.tableData = res.data || res.records; + this.total = res.total; + this.loading = false; + this.mergeColumns(res); + this.calcHeight(); + this.scrollTop(); + }, 300); + } catch (e) { + // console.log(e); + this.loading = false; + } + }, + //鎵嬪姩淇敼data + async changeData(data) { + this.tableData = data; + this.mergeColumns(); + this.calcHeight(); + this.scrollTop(); + // console.log('鎵嬪姩淇敼data',data); + }, + + sortChange({ column, prop, order }) { + // console.log(column, prop, order); + this.fieldName = column.sortBy || prop; + if (order === "ascending") { + this.fieldSort = "ASC"; + } else if (order === "descending") { + this.fieldSort = "DESC"; + } else { + this.fieldSort = order; + } + this.handleCurrentChange(1); + }, + handleSizeChange(pageSize) { + this.pageSize = pageSize; + this.loadData(); + }, + handleCurrentChange(page) { + this.page = page; + this.loadData(); + }, + // 搴忓彿 + indexMethod(index) { + // return (this.page - 1) * this.pageSize + index + 1; + return index + 1; + }, + // 璁剧疆params鍙傛暟鍊� + setParamsVal(val) { + this.$refs.refTableHeader.setParamsVal(val); + }, + // 璁$畻楂樺害 + calcHeight() { + this.height = ""; + setTimeout(() => { + const _offsetHeight = this.$refs.refTableBody.offsetHeight; + this.height = _offsetHeight - 4 + "px"; + }, 1); + }, + // 婊氬姩鍒伴《閮� + scrollTop() { + const innerTable = this.$refs.refInnerTable.$el; + const bodyWrapper = innerTable.querySelector(".el-table__body-wrapper"); + bodyWrapper.scrollTop = 0; + }, + // 婊氬姩澶勭悊鍑芥暟 + scrollHandler(bind) { + const _self = this; + const innerTable = this.$refs.refInnerTable.$el; + const doLayout = () => { + _self.$nextTick(() => _self.$refs.refInnerTable.doLayout()); + }; + const bodyWrapper = innerTable.querySelector(".el-table__body-wrapper"); + if (bind) { + bodyWrapper.addEventListener("scroll", doLayout); + } else { + bodyWrapper.removeEventListener("scroll", doLayout); + } + }, + clearSelection() { + this.$refs.refInnerTable.clearSelection(); + }, + toggleSelection(rows) { + if (rows) { + rows.forEach((row) => { + this.$refs.refInnerTable.toggleRowSelection(row); + }); + } else { + this.$refs.refInnerTable.clearSelection(); + } + }, + }, +}; +</script> +<style lang="scss" scoped> +.base-table { + height: 100%; + display: flex; + overflow: hidden; + position: relative; + flex-direction: column; + + ::v-deep { + .el-table { + background-color: transparent; + tr { + background-color: transparent; + } + .el-table__row { + td { + &:first-child { + border-left: 1px solid #e5e5e5; + } + &:last-child { + border-right: 1px solid #e5e5e5; + } + } + } + } + .el-table th.el-table__cell { + background-color: #e3edfc; + color: #182233; + } + + .el-table__fixed::before, + .el-table__fixed-right::before { + display: none; + } + + .el-table::before { + display: none; + } + } +} + +.base-table-body { + flex: 1; + overflow: hidden; + // padding-bottom: 72px; + background-color: #fff; + // border-bottom: 1px solid #e4e7ed; +} + +.base-table-footer { + bottom: 0; + width: 100%; + padding: 15px 0; + background-color: #fff; + + &::v-deep { + .el-pagination { + padding: 0px 5px; + display: flex; + justify-content: flex-start; + font-weight: initial; + } + + .el-pager li, + .el-pagination button { + min-width: 28px; + margin: 0 4px; + border-radius: 2px; + } + + .el-pagination .btn-prev, + .el-pagination .btn-next { + padding-right: 6px; + padding-left: 6px; + } + + .el-pagination .el-pagination__sizes .el-input__inner { + border: none; + background: #eee; + color: #666666; + } + } +} +</style> diff --git a/src/components/App/index.js b/src/components/App/index.js new file mode 100644 index 0000000000000000000000000000000000000000..e7893499311f4132cbb4937554d425288efceecb --- /dev/null +++ b/src/components/App/index.js @@ -0,0 +1,8 @@ +import AppHeader from "./AppHeader"; +import SubHeader from "./SubHeader"; +import BreadCrumb from "./BreadCrumb"; +import Empty from "./Empty"; +import SideBar from "./SideBar"; +import Table from "./Table"; +import ImgUploader from "./ImgUploader"; +export { AppHeader, SubHeader, BreadCrumb, Empty, SideBar, Table, ImgUploader }; diff --git a/src/components/Layout/InnerView/index.vue b/src/components/Layout/InnerView/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..228f290082393f1f57b095427b3c78e9f690c223 --- /dev/null +++ b/src/components/Layout/InnerView/index.vue @@ -0,0 +1,18 @@ +<template> + <div class="inner-view"> + <slot></slot> + </div> +</template> +<script> +export default { + name: "InnerView" +}; +</script> +<style lang="scss" scoped> +.inner-view { + width: 100%; + height: 100%; + // overflow: hidden; + position: relative; +} +</style> diff --git a/src/components/Layout/PaddingView/index.vue b/src/components/Layout/PaddingView/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..b6c67ea74b844bd31e65bb4524b0a9f079167b1a --- /dev/null +++ b/src/components/Layout/PaddingView/index.vue @@ -0,0 +1,19 @@ +<template> + <div class="padding-view"> + <slot></slot> + </div> +</template> +<script> +export default { + name: "InnerView" +}; +</script> +<style lang="scss" scoped> +.padding-view { + width: 100%; + height: 100%; + // overflow: hidden; + position: relative; + padding: 32px 44px; +} +</style> diff --git a/src/components/Layout/RouteView/index.vue b/src/components/Layout/RouteView/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..ad81748618cf26d377ec16f2d93806da00745992 --- /dev/null +++ b/src/components/Layout/RouteView/index.vue @@ -0,0 +1,21 @@ +<template> + <div class="route-view"> + <slot></slot> + </div> +</template> +<script> +export default {}; +</script> +<style lang="scss" scoped> +.route-view { + flex: 1; + width: 100%; + height: 100%; + overflow-y: auto; + // padding: 12px; + padding-top: 0; + overflow: hidden; + position: relative; + // background: #f2f2f2; +} +</style> diff --git a/src/components/Layout/ScrollView/index.vue b/src/components/Layout/ScrollView/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..c269201f52177b4bc3e55c077d0c655b5eb24806 --- /dev/null +++ b/src/components/Layout/ScrollView/index.vue @@ -0,0 +1,20 @@ +<template> + <div class="ScrollView"> + <slot></slot> + </div> +</template> +<script> +export default {}; +</script> +<style lang="scss" scoped> +.ScrollView { + width: 100%; + height: 100%; + overflow-y: auto; + // padding: 12px; + padding-top: 0; + // overflow: hidden; + position: relative; + // background: #f2f2f2; +} +</style> diff --git a/src/components/Layout/index.js b/src/components/Layout/index.js new file mode 100644 index 0000000000000000000000000000000000000000..2b8c0967f2aeb8a4a2418885579637cd24252f67 --- /dev/null +++ b/src/components/Layout/index.js @@ -0,0 +1,5 @@ +import RouteView from "./RouteView"; +import InnerView from "./InnerView"; +import PaddingView from "./PaddingView"; + +export { RouteView, InnerView ,PaddingView}; diff --git a/src/config/index.js b/src/config/index.js new file mode 100644 index 0000000000000000000000000000000000000000..8acf4b5e36b4065c116963b1f5119f17ba1a48bc --- /dev/null +++ b/src/config/index.js @@ -0,0 +1 @@ +export const appName = ""; diff --git a/src/directives/el-table/adaptive.js b/src/directives/el-table/adaptive.js new file mode 100644 index 0000000000000000000000000000000000000000..c1018664047f30ae666e149c285e45a2e62f69e6 --- /dev/null +++ b/src/directives/el-table/adaptive.js @@ -0,0 +1,45 @@ +import { + addResizeListener, + removeResizeListener +} from "element-ui/src/utils/resize-event"; + +/** + * How to use + * <el-table height="100px" v-el-height-adaptive-table="{bottomOffset: 30}">...</el-table> + * el-table height is must be set + * bottomOffset: 30(default) // The height of the table from the bottom of the page. + */ + +const doResize = (el, binding, vnode) => { + const { componentInstance: $table } = vnode; + + const { value } = binding; + + if (!$table.height) { + throw new Error(`el-$table must set the height. Such as height='100px'`); + } + const bottomOffset = (value && value.bottomOffset) || 30; + + if (!$table) return; + + const height = + window.innerHeight - el.getBoundingClientRect().top - bottomOffset; + $table.layout.setHeight(height); + $table.doLayout(); +}; + +export default { + bind(el, binding, vnode) { + el.resizeListener = () => { + doResize(el, binding, vnode); + }; + // parameter 1 is must be "Element" type + addResizeListener(el, el.resizeListener); + }, + inserted(el, binding, vnode) { + doResize(el, binding, vnode); + }, + unbind(el) { + removeResizeListener(el, el.resizeListener); + } +}; diff --git a/src/directives/el-table/index.js b/src/directives/el-table/index.js new file mode 100644 index 0000000000000000000000000000000000000000..ad0577f7c6117caf5f0a455826c879866c76c255 --- /dev/null +++ b/src/directives/el-table/index.js @@ -0,0 +1,13 @@ +import adaptive from "./adaptive"; + +const install = function(Vue) { + Vue.directive("el-height-adaptive-table", adaptive); +}; + +if (window.Vue) { + window["el-height-adaptive-table"] = adaptive; + Vue.use(install); // eslint-disable-line +} + +adaptive.install = install; +export default adaptive; diff --git a/src/directives/index.js b/src/directives/index.js new file mode 100644 index 0000000000000000000000000000000000000000..6b74181301828636f657db16e66170eed31720d0 --- /dev/null +++ b/src/directives/index.js @@ -0,0 +1,16 @@ +import Vue from "vue"; + +Vue.use(Vue => { + (requireContext => { + const arr = requireContext.keys().map(requireContext); + (arr || []).forEach(directive => { + directive = + directive.__esModule && directive.default + ? directive.default + : directive; + Object.keys(directive).forEach(key => { + Vue.directive(key, directive[key]); + }); + }); + })(require.context("./", true, /^\.\/.*\/index\.js$/)); +}); diff --git a/src/filters/index.js b/src/filters/index.js new file mode 100644 index 0000000000000000000000000000000000000000..c57c83b2265ddc8dfc81171938c1dada051ff9ad --- /dev/null +++ b/src/filters/index.js @@ -0,0 +1,13 @@ +import Vue from "vue"; + +Vue.use(Vue => { + (requireContext => { + const arr = requireContext.keys().map(requireContext); + (arr || []).forEach(filter => { + filter = filter.__esModule && filter.default ? filter.default : filter; + Object.keys(filter).forEach(key => { + Vue.filter(key, filter[key]); + }); + }); + })(require.context("./", true, /^\.\/.*\/index\.js$/)); +}); diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000000000000000000000000000000000000..862207284310c3ef4be38c0ed2977074e04bb065 --- /dev/null +++ b/src/main.js @@ -0,0 +1,45 @@ +import Vue from "vue"; +import Element from "element-ui"; + +import "./filters"; +import "./directives"; +import App from "./App.vue"; +import store from "./store"; +import router from "./router"; +import "./assets/css/app.scss"; +import "./mock/index.js"; +import plugins from "./plugins"; +import * as utils from "./utils"; // +import echarts from "./utils/echarts"; // npm install echarts --save + +// require("./mock"); + +import dayjs from "dayjs"; +import "dayjs/locale/zh-cn"; +import updateLocale from "dayjs/plugin/updateLocale"; + +dayjs.locale("zh-cn"); +dayjs.extend(updateLocale); +dayjs.updateLocale("zh-cn", { + weekdays: [ + "鏄熸湡澶�", + "鏄熸湡涓€", + "鏄熸湡浜�", + "鏄熸湡涓�", + "鏄熸湡鍥�", + "鏄熸湡浜�", + "鏄熸湡鍏�", + ], +}); + +Vue.prototype.$utils = utils; +Vue.prototype.$echarts = echarts; +Vue.use(plugins); +Vue.use(Element); +Vue.config.productionTip = false; + +new Vue({ + store, + router, + render: (h) => h(App), +}).$mount("#app"); diff --git a/src/mock/index.js b/src/mock/index.js new file mode 100644 index 0000000000000000000000000000000000000000..597d768437a14301cf462637bf343b4498b854b0 --- /dev/null +++ b/src/mock/index.js @@ -0,0 +1,9 @@ +const Mock = require("mockjs"); +let services = require.context("./services/", true, /\.js$/); //寮曞叆services鍐呮墍鏈塲s +services.keys().forEach((key) => { + services(key); //鐢熸垚modal +}); + +Mock.setup({ + timeout: 200, // setter delay time +}); diff --git a/src/mock/services/test.js b/src/mock/services/test.js new file mode 100644 index 0000000000000000000000000000000000000000..c2091ce3dd5edeaecefc922f9d80ba12df3314c1 --- /dev/null +++ b/src/mock/services/test.js @@ -0,0 +1,8 @@ +import Mock from "mockjs"; +Mock.mock("/mock/tagCloudData", "get", { + status: "0", + msg: "璁块棶鎴愬姛", + data: {}, + errCode: null, + errMsg: null, +}); diff --git a/src/mock/util.js b/src/mock/util.js new file mode 100644 index 0000000000000000000000000000000000000000..41b4e54a54b53b581957adb0585a7fce93ae45d3 --- /dev/null +++ b/src/mock/util.js @@ -0,0 +1,27 @@ +const responseBody = { + body: "", + cause: null, + state: true, + timestamp: 0, + message: "SUCCESS", +}; +//妯℃嫙鎺ュ彛杩斿洖 +export const builder = (data, message, code = 0, headers = {}) => { + responseBody.body = data; + if (message !== undefined && message !== null) { + responseBody.message = message; + } + if (code !== undefined && code !== 0) { + responseBody.code = code; + responseBody._status = code; + } + if ( + headers !== null && + typeof headers === "object" && + Object.keys(headers).length > 0 + ) { + responseBody._headers = headers; + } + responseBody.timestamp = new Date().getTime(); + return responseBody; +}; diff --git a/src/plugins/index.js b/src/plugins/index.js new file mode 100644 index 0000000000000000000000000000000000000000..9f7d803ff579f5166538dbc05d3f6c1089db0b30 --- /dev/null +++ b/src/plugins/index.js @@ -0,0 +1,41 @@ +// import dayjs from 'dayjs'; + +import Table from "@/components/App/Table"; +import PaddingView from "@/components/Layout/PaddingView"; +import InnerView from "@/components/Layout/InnerView"; +// import TableView from "@/components/Layout/TableView"; +import ScrollView from "@/components/Layout/ScrollView"; +// import PubCard from "@/components/App/PubCard"; +// import AlarmNum from "@/components/App/AlarmNum"; +import BackTitle from "@/components/App/BackTitle"; + +// import CardView from '@/components/Layout/CardView'; +// import RouteView from '@/components/Layout/RouteView'; + +/* eslint-disable no-new */ +// export const buildQuery = (data) => qs.stringify(data); + +export default { + install(app) { + // app.config.globalProperties.$filters = { + // formatDate(value = Date.now(), reg = 'YYYY-MM-DD HH:mm:ss') { + // return dayjs(value).format(reg); + // }, + // }; + /** + * 娉ㄥ唽鍏ㄥ眬閫氱敤缁勪欢 + */ + app.component("PaddingView", PaddingView); + app.component("InnerView", InnerView); + // app.component("TableView", TableView); + app.component("ScrollView", ScrollView); + + app.component("pub-table", Table); + app.component("BackTitle", BackTitle); + // app.component("PubCard", PubCard); + // app.component("AlarmNum", AlarmNum); + + // app.component('CardView', CardView); + // app.component('RouteView', RouteView); + }, +}; diff --git a/src/router/index.js b/src/router/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a2619263bf970f0fd24669bb8e065bbdd4275ce0 --- /dev/null +++ b/src/router/index.js @@ -0,0 +1,112 @@ +import Vue from "vue"; +import VueRouter from "vue-router"; +import store from "@/store"; + +const originalPush = VueRouter.prototype.push; +VueRouter.prototype.push = function push(location) { + return originalPush.call(this, location).catch(() => {}); +}; + +Vue.use(VueRouter); + +const recursion = function(paths, root, requireContext) { + const dirs = paths.map((item) => item.split("/")[0]); + const sets = Array.from(new Set(dirs)); + const router = sets.map((it) => { + const reg = new RegExp("^" + it + "/"); + const _paths = paths + .filter((item) => item !== it) + .filter((item) => reg.test(item)) + .map((item) => item.substring(it.length + 1)); + const component = requireContext(root + it + "/index.vue").default; + const children = recursion(_paths, root + it + "/", requireContext); + const routerItem = { + path: it, + children, + component, + name: component.name || it, + meta: component.meta || {}, + redirect: component.meta?.redirect, + }; + if (!routerItem.children.length) delete routerItem.children; + if (!routerItem.redirect === undefined) delete routerItem.redirect; + return routerItem; + }); + return router; +}; + +const genRouter = function(requireContext) { + // 涓嶈鍙朿omponents鏂囦欢澶逛笅鐨勬枃浠� + const paths = requireContext + .keys() + .map((item) => item.slice(2, -10)) + .filter((item) => !/components/.test(item)); + const router = recursion(paths, "./", requireContext).map((item) => ({ + ...item, + path: "/" + item.path, + })); + return router; +}; + +const mapSort = function(menus) { + console.log(menus); + //閫掑綊锛屽璺敱杩涜鎺掑簭锛屾坊鍔爊ame鍜宨con + const _menus = menus + .sort((a, b) => { + return a.meta.sort - b.meta.sort; + }) + .filter((item) => !item.meta.hideMenu); + + _menus.forEach((element) => { + if (element.children && element.children.length) { + element.children = element.children.filter((item) => !item.meta.hideMenu); + if (element.children.length) { + element.children = mapSort(element.children); + } else { + delete element.children; + } + } + }); + return _menus; +}; +const routes = [ + { + path: "", + redirect: "/index", + }, + { + path: "/login", + component: () => + import(/* webpackChunkName: "accout" */ "@/views/login.vue"), + // redirect: "/index" + }, +]; + +const requireContext = require.context( + "@/views/", + true, + /^\.\/.*\/index\.vue$/ +); + +const asyncRoutes = genRouter(requireContext); // +const asyncRoutesSort = mapSort(asyncRoutes); //绛涢€夋帓搴忓悗鐨勮矾鐢� + +const router = new VueRouter({ + routes: routes, + base: process.env.BASE_URL, +}); + +router.beforeEach((to, from, next) => { + // console.log(to, from); + if (to.meta.keepAlive) { + store.dispatch("app/addCacheRoutes", to.name); + } + next(); +}); + +router.addRoutes(asyncRoutes); +console.log(router); +export default router; +export { asyncRoutes, asyncRoutesSort }; + +// this.$store.dispatch("app/removeCacheRoutes", findItem.parent.name); diff --git a/src/store/app/index.js b/src/store/app/index.js new file mode 100644 index 0000000000000000000000000000000000000000..d41d5d76849e3362fc9ab3a834f1c8d286113f31 --- /dev/null +++ b/src/store/app/index.js @@ -0,0 +1,35 @@ +export default { + namespaced: true, + state: { + + cacheRoutes: [], // 褰撳墠缂撳瓨鐨勮矾鐢� + }, + actions: { + + //娣诲姞缂撳瓨璺敱 + addCacheRoutes({ + state, + commit + }, paylod) { + if (!state.cacheRoutes.includes(paylod)) { + state.cacheRoutes.push(paylod); + commit("SET_CACHE_ROUTES", state.cacheRoutes); + } + }, + //鍒犻櫎闇€瑕佺紦瀛樼殑璺敱 + removeCacheRoutes({ + state, + commit + }, paylod) { + const data = state.cacheRoutes.filter(item => item !== paylod); + commit("SET_CACHE_ROUTES", data); + }, + }, + mutations: { + + //璁剧疆缂撳瓨璺敱 + SET_CACHE_ROUTES(state, data = []) { + state.cacheRoutes = data; + }, + } +}; \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js new file mode 100644 index 0000000000000000000000000000000000000000..24f2617c4f60e084054325bae63dd11cb16dcd4d --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,19 @@ +import Vue from "vue"; +import Vuex from "vuex"; + +Vue.use(Vuex); + +const modules = {}; +const requireContext = require.context("./", true, /^\.\/.*\/index\.js$/); +requireContext.keys().forEach(key => { + const _module = requireContext(key); + modules[key.slice(2, -9)] = + _module.__esModule && _module.default ? _module.default : _module; +}); + +export default new Vuex.Store({ + state: {}, + actions: {}, + mutations: {}, + modules: modules +}); diff --git a/src/store/tabledata/index.js b/src/store/tabledata/index.js new file mode 100644 index 0000000000000000000000000000000000000000..b8eb2ece0636e92727942ca1cf36485aaf224d0b --- /dev/null +++ b/src/store/tabledata/index.js @@ -0,0 +1,30 @@ +import testCardPhoto from "@/assets/img/test-card-photo.png"; +export default { + namespaced: true, + state: { + //鎴戠殑璇佺収鍒楄〃鏁版嵁 + photo: [ + { + id: 1, + name: "鐢靛瓙绀句繚鍗�", + pic: testCardPhoto, + picList: [testCardPhoto], + time: "2023-01-13", + }, + ], + }, + actions: { + //淇敼鍒楄〃鏁版嵁 + changeTableData({ commit }, paylod) { + const { field, data } = paylod; + console.log(field, data); + commit("SET_TABLE_DATA", { field, data }); + }, + }, + mutations: { + //璁剧疆缂撳瓨璺敱 + SET_TABLE_DATA(state, { field, data = [] }) { + state[field] = data; + }, + }, +}; diff --git a/src/utils/echarts.js b/src/utils/echarts.js new file mode 100644 index 0000000000000000000000000000000000000000..8f3621612bd8512e8b197ff209794377e8e04583 --- /dev/null +++ b/src/utils/echarts.js @@ -0,0 +1,42 @@ +// 寮曞叆 echarts 鏍稿績妯″潡锛屾牳蹇冩ā鍧楁彁渚涗簡 echarts 浣跨敤蹇呴』瑕佺殑鎺ュ彛銆� +import * as echarts from "echarts/core"; + +/** 寮曞叆浠绘剰鍥捐〃锛岃繖閲屽紩鍏ョ殑鏄煴鐘跺浘and鎶樼嚎鍥惧浘琛紙鍥捐〃鍚庣紑閮戒负 Chart锛� */ +import { BarChart, LineChart,PieChart ,PictorialBarChart} from "echarts/charts"; + +// 寮曞叆鎻愮ず妗嗭紝鏍囬锛岀洿瑙掑潗鏍囩郴锛屾暟鎹泦锛屽唴缃暟鎹浆鎹㈠櫒缁勪欢锛岀粍浠跺悗缂€閮戒负 Component +import { + TitleComponent, + TooltipComponent, + GridComponent, + DatasetComponent, + TransformComponent, + LegendComponent, + +} from "echarts/components"; + +// 鏍囩鑷姩甯冨眬锛屽叏灞€杩囨浮鍔ㄧ敾绛夌壒鎬� +import { LabelLayout, UniversalTransition } from "echarts/features"; + +// 寮曞叆 Canvas 娓叉煋鍣紝娉ㄦ剰寮曞叆 CanvasRenderer 鎴栬€� SVGRenderer 鏄繀椤荤殑涓€姝� +import { CanvasRenderer } from "echarts/renderers"; + +// 娉ㄥ唽蹇呴』鐨勭粍浠� +echarts.use([ + TitleComponent, + TooltipComponent, + GridComponent, + DatasetComponent, + TransformComponent, + LegendComponent, + BarChart, + LabelLayout, + UniversalTransition, + CanvasRenderer, + LineChart, + PieChart, + PictorialBarChart +]); + +// 瀵煎嚭 +export default echarts; \ No newline at end of file diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 0000000000000000000000000000000000000000..4827b8f2d4c3132d2d7baf2e85059e6e1e52e3f0 --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1,42 @@ +import dayjs from "dayjs"; +//灏嗚幏鍙栫殑鏁版嵁鍥炴樉琛ㄥ崟 +const setFormValue = (form, content) => { + let res = {}; + for (const key in form) { + if (Object.hasOwnProperty.call(content, key)) { + res[key] = content[key]; + } else { + res[key] = form[key]; + } + } + return res; +}; +//鏍煎紡鍖栨椂闂� +const formatTimeWithDayjs = (time, formar = "YYYY-MM-DD HH:mm:ss") => { + if (time.indexOf) { + if (time.indexOf("-") < 0 && time.indexOf(":") < 0) { + time = Number(time); + } else { + return dayjs(time).format(formar); + } + } + if (time <= 10000000000) { + time = time * 1000; + } + return dayjs(time).format(formar); +}; +//灏嗕笂浼犵殑鏂囦欢杞负base64 +const file2Base64 = (file) => { + return new Promise((resolve) => { + // console.log(file); + let reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function(e) { + // console.log(e.target.result); + resolve(e.target.result); + // return e.target.result; + }; + }); +}; + +export { setFormValue, formatTimeWithDayjs, file2Base64 }; diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 0000000000000000000000000000000000000000..bd3855255a68b1fd93c3bcd333c65610fcf8e116 --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,97 @@ +import axios from "axios"; +import { MessageBox, Message } from "element-ui"; +import store from "@/store"; +// import { getToken } from "@/utils/auth"; + +const url = [ + // "/api/v1/app/uploadAppLogo", + // "/api/v1/account/changeAvatar", + // "/api/v1/account/importFromExcel", + // "/api/v1/account/downloadExcelModel", + // "/api/v1/basic/logout" +]; //涓婁紶鏂囦欢鎺ュ彛 + +// create an axios instance +const service = axios.create({ + timeout: 30000, + withCredentials: true, + credentials: "include", + baseURL: process.env.VUE_APP_BASE_API +}); + +service.interceptors.request.use( + config => { + if (store.getters.token && url.indexOf(config.url) < 0) { + // let each request carry token + // ['X-Token'] is a custom headers key + // please modify it according to the actual situation + // config.headers["token"] = getToken(); + } else { + if (config.url != "/api/v1/basic/logout") { + config.params = { + ...config.params + // token: getToken() + }; + } + } + return config; + }, + error => { + console.error(error); + return Promise.reject(error); + } +); + +service.interceptors.response.use( + response => { + if (response.config.responseType === "blob") return response; + const res = response.data; + // if the custom code is not 20000, it is judged as an error. + if (res.state !== true) { + const [code, message] = res.message.split(":"); + /* 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired; */ + /* res.code === 50008 || res.code === 50012 || res.code === 50014 */ + if (code === "AUTH-ERROR-01") { + // to re-login + MessageBox.confirm("鎮ㄥ凡娉ㄩ攢锛屽彲浠ョ暀鍦ㄦ椤碉紝鎴栭噸鏂扮櫥褰�", "纭娉ㄩ攢", { + confirmButtonText: "閲嶆柊鐧诲綍", + cancelButtonText: "鐣欏湪姝ら〉", + type: "warning" + }).then(() => { + store.dispatch("logout"); + }); + } else { + Message({ + message: message || "Error", + type: "error", + duration: 5 * 1000, + showClose: true + }); + } + return Promise.reject(new Error(res.message || "Error")); + } else { + return res.body; + } + }, + error => { + console.error(error); + Message({ + message: + error.message === "Request failed with status code 404" + ? "鏆傛棤璁块棶鏉冮檺锛岃鑱旂郴绠$悊鍛�" + : [ + "timeout of 5000ms exceeded", + "Network Error", + "Request failed with status code 404" + ].includes(error.message) + ? "缃戠粶閿欒锛岃绋嶅悗鍐嶈瘯" + : error.message, + type: "error", + duration: 8 * 1000, + showClose: true + }); + return Promise.reject(error); + } +); + +export default service; diff --git a/src/views/feedback/index.vue b/src/views/feedback/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..b07a5b610b59163f1ad81419e56fb6cff588c169 --- /dev/null +++ b/src/views/feedback/index.vue @@ -0,0 +1,20 @@ +<template> + <InnerView> </InnerView> +</template> +<script> +export default { + name: "feedback", + meta: { + sort: 5, + title: "鎰忚鍙嶉", + iconImg: "feedback", + iconImgActive: "feedbackActive", + }, + components: {}, + data() { + return {}; + }, + watch: {}, +}; +</script> +<style lang="scss" scoped></style> diff --git a/src/views/footprint/index.vue b/src/views/footprint/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..1d8e2a90b0436d47427de06613cb3becc62bae89 --- /dev/null +++ b/src/views/footprint/index.vue @@ -0,0 +1,81 @@ +<template> + <InnerView class="InnerView"> + <pub-table + :headers="headers" + :fetcher="fetcher" + :params="params" + ref="table" + > + </pub-table> + </InnerView> +</template> +<script> +export default { + name: "footprint", + meta: { + sort: 3, + title: "鎴戠殑瓒宠抗", + iconImg: "footprint", + iconImgActive: "footprintActive", + }, + components: {}, + data() { + return { + headers: [ + { + field: "index", + fieldName: "搴忓彿", + type: "index", + }, + { + field: "footprint", + fieldName: "瓒宠抗", + }, + { + field: "time", + fieldName: "鏃堕棿", + }, + ], + params: [], + testData: [ + { + footprint: "濂藉樊璇�-鍖哄幙", + time: "2023-07-13 17:14:43", + }, + { + footprint: "绐佸彂鍏叡鍗敓浜嬩欢棰勮淇℃伅鍙戝竷", + time: "2023-04-25 15:28:36", + }, + { + footprint: "缁勭粐瀹炴柦鍔ㄧ墿鐤梾寮哄埗鍏嶇柅", + time: "2023-03-15 14:22:16", + }, + { + footprint: "瀹d紶楗叉枡瀹夊叏鐭ヨ瘑銆佺煡閬撳悎鐞嗕娇鐢ㄩゲ鏂�", + time: "2023-02-18 14:28:15", + }, + { + footprint: "澶变笟淇濋櫓鏈嶅姟涓殑鑱屼笟浠嬬粛琛ヨ创鐢抽", + time: "2023-02-14 12:22:33", + }, + ], + fetcher: async () => { + // console.log(this); + //console.log(params); + // let res = await api.publicEquipment.getBiogasDeviceInfoPage(params); + let res = { + total: this.testData.length, + data: this.testData, + }; + return res; + }, + }; + }, + watch: {}, +}; +</script> +<style lang="scss" scoped> +.InnerView { + padding-top: 24px; +} +</style> diff --git a/src/views/login.vue b/src/views/login.vue new file mode 100644 index 0000000000000000000000000000000000000000..b294627b0a62abb238a329b17f50a8b45739e2cb --- /dev/null +++ b/src/views/login.vue @@ -0,0 +1,144 @@ +<template> + <div class="login" v-loading="loading"> + <div class="login-box"> + <el-form + :model="ruleForm" + :rules="rules" + ref="ruleForm" + label-width="0px" + class="demo-ruleForm" + > + <el-form-item label="" prop="user"> + <el-input placeholder="璇疯緭鍏ョ敤鎴峰悕" v-model="ruleForm.user"> + <i slot="prefix" class="el-input__icon el-icon-user"></i> + </el-input> + </el-form-item> + <el-form-item label="" prop="password"> + <el-input + placeholder="璇疯緭鍏ュ瘑鐮�" + v-model="ruleForm.password" + show-password + @keyup.enter.native="login()" + > + <i slot="prefix" class="el-input__icon el-icon-lock"></i> + </el-input> + </el-form-item> + </el-form> + + <el-button type="primary" style="width: 100%" @click="login" + >鐧诲綍</el-button + > + </div> + </div> +</template> +<script> +// import { CardView } from "@/components/Layout"; +import { appName } from "@/config"; +import { common } from "@/api"; +export default { + name: "login", + meta: { + title: "鐧诲綍", + }, + components: { + // CardView + }, + data() { + return { + loading: false, + appName, + user: "", + password: "", + + ruleForm: { + user: "", + password: "", + }, + rules: { + user: [ + { + required: true, + message: "璇疯緭鍏ョ敤鎴峰悕", + trigger: ["change", "burl"], + }, + ], + password: [ + { + required: true, + message: "璇疯緭鍏ュ瘑鐮�", + trigger: ["change", "burl"], + }, + ], + }, + }; + }, + watch: {}, + methods: { + login() { + this.$refs.ruleForm.validate((valid) => { + if (valid) { + this.loading = true; + common + .login(this.ruleForm) + .then((res) => { + // console.log(res.token); + if (res.token) { + localStorage.setItem("token", res.token); + this.loading = false; + this.$message.success("鐧婚檰鎴愬姛"); + this.$router.replace("/index"); + } + }) + .catch(() => { + this.loading = false; + }); + + // alert('submit!'); + } else { + // console.log('error submit!!'); + return false; + } + }); + }, + }, +}; +</script> +<style lang="scss" scoped> +.login { + // position: fixed; + width: 100vw; + height: 100vh; + background-color: #f5f6fa; + display: flex; + align-items: center; + justify-content: center; +} +.login-box { + width: 500px; + height: 360px; + border-radius: 4px; + background: #fff; + padding: 30px 50px; +} +.title { + display: flex; + align-items: center; + font-size: 20px; + font-weight: bold; + padding-bottom: 10px; + width: 100%; + justify-content: center; + span { + padding-left: 30px; + } + img { + width: 80px; + height: auto; + } +} +// ::v-deep { +// .el-input { +// margin-bottom: 30px; +// } +// } +</style> diff --git a/src/views/photo/edit/index.vue b/src/views/photo/edit/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..b4aaa3a66ba18884f35f1c2c6aa90f7f1345354a --- /dev/null +++ b/src/views/photo/edit/index.vue @@ -0,0 +1,153 @@ +<template> + <div class="pub-form"> + <el-form + ref="form" + :model="form" + label-width="98px" + label-position="right" + :rules="rules" + size="small" + > + <el-form-item prop="name" label="璇佺収鍚嶇О:"> + <el-input v-model="form.name" placeholder="璇疯緭鍏�" clearable></el-input> + </el-form-item> + + <el-form-item prop="pic" label="璇佺収鐓х墖:"> + <div class="tip-text">鍙寮狅紝鏀寔png/jpg</div> + <ImgUploader v-model="form.picList"></ImgUploader> + </el-form-item> + + <el-form-item prop="time" label="鍔炵悊鏃堕棿:"> + <div class="flex-between" style="width:300px"> + <el-date-picker + v-model="form.time" + type="date" + value-format="yyyy-MM-DD" + placeholder="閫夋嫨鏃ユ湡" + > + </el-date-picker> + </div> + </el-form-item> + + <el-form-item> + <el-button + type="primary" + size="small" + @click="submit" + :loading="loading" + >鎻愪氦</el-button + > + <el-button type="primary" plain size="small" @click="close" + >杩斿洖</el-button + > + </el-form-item> + </el-form> + </div> +</template> +<script> +import { mapState } from "vuex"; +import ImgUploader from "@/components/App/ImgUploader"; +export default { + name: "photoEdit", + components: { ImgUploader }, + meta: { + sort: 1, + title: "鎴戠殑璇佺収", + hidden: true, + activeName: "photo", + }, + data: () => { + return { + id: "", + loading: false, + + form: { + id: "", + name: "", + pic: "", + picList: [], + time: "", + }, + rules: { + // name: [ + // { required: true, message: "璇疯緭鍏ヨ鑹插悕绉�", trigger: "change" }, + // ], + }, + }; + }, + computed: { + // import { mapState } from "vuex"; + ...mapState({ + testData: (state) => state.tabledata.photo, + }), + }, + mounted() { + let { id } = this.$route.query; + if (id) { + this.$set(this.form, "id", id); + this.getDetail(id); + } + }, + methods: { + close() { + this.$router.back(-1); + }, + getDetail(id) { + let findItem = this.testData.find((item) => item.id == id); + + if (findItem) { + this.form = this.$utils.setFormValue(this.form, findItem); + } + }, + submit() { + this.$refs.form.validate((valid) => { + if (valid) { + let datas = { ...this.form }; + // datas.picList = [...datas.pic]; + datas.pic = datas.picList[0]; + // console.log(datas); + if (datas.id) { + let resList = this.testData.map((item) => { + if (item.id == datas.id) { + return datas; + } else { + return item; + } + }); + // console.log(resList); + let query = { field: "photo", data: resList }; + this.$store.dispatch("tabledata/changeTableData", query); + } else { + //璁$畻鏂癷d + let newId = this.testData[this.testData.length - 1]?.id + ? this.testData[this.testData.length - 1]?.id + 2 + : 2; + let resList = [...this.testData, { ...datas, id: newId }]; + let query = { field: "photo", data: resList }; + this.$store.dispatch("tabledata/changeTableData", query); + } + // console.log(this.testData); + + this.$message.success("鎿嶄綔鎴愬姛"); + this.$router.back(-1); + } else { + return false; + } + }); + }, + }, +}; +</script> +<style lang="scss" scoped> +::v-deep { + .el-date-editor.el-input, + .el-date-editor.el-input__inner { + width: 132px; + } +} +.tip-text { + padding-bottom: 8px; + font-size: 12px; + color: #a6a6a6; +} +</style> diff --git a/src/views/photo/index.vue b/src/views/photo/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..1e721694e12790555857a0745920e6d973c232d1 --- /dev/null +++ b/src/views/photo/index.vue @@ -0,0 +1,32 @@ +<template> + <!-- <transition :name="transition"> --> + <keep-alive :include="cacheRoutes"> + <router-view class="child-view"></router-view> + </keep-alive> + <!-- </transition> --> +</template> +<script> +import { mapState } from "vuex"; +// import { InnerView, RouteView } from "@/components/Layout"; +export default { + name: "photo", + // components: { InnerView, RouteView }, + meta: { + sort: 2, + title: "鎴戠殑璇佺収", + iconImg: "photo", + iconImgActive: "photoActive", + redirect: "/photo/list", + }, + computed: { + ...mapState({ + cacheRoutes: (state) => state.app.cacheRoutes, + }), + }, + data() { + return {}; + }, + watch: {}, +}; +</script> +<style lang="scss" scoped></style> diff --git a/src/views/photo/list/index.vue b/src/views/photo/list/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..fa9401a677ff91ca3f78e911c383814a950d98f8 --- /dev/null +++ b/src/views/photo/list/index.vue @@ -0,0 +1,178 @@ +<template> + <InnerView> + <pub-table + :headers="headers" + :fetcher="fetcher" + :params="params" + :pagination="false" + showHeader + ref="table" + > + <div slot="btnRight" class="btnRight"> + <el-button type="primary" size="small" @click="openEdit" + >鏂板</el-button + > + </div> + </pub-table> + </InnerView> +</template> + +<script> +// import testCardPhoto from "@/assets/img/test-card-photo.png"; +import { mapState } from "vuex"; +export default { + name: "photoList", + components: {}, + meta: { + sort: 0, + title: "鎴戠殑璇佺収", + hidden: true, + activeName: "photo", + keepAlive: true, + }, + computed: { + // import { mapState } from "vuex"; + ...mapState({ + testData: (state) => state.tabledata.photo, + }), + }, + data() { + return { + EditShow: false, + headers: [ + { + field: "name", + fieldName: "璇佺収鍚嶇О", + }, + { + field: "pic", + fieldName: "璇佺収鍥剧墖", + renderFun: (e) => this.renderPic(e), + }, + { + field: "time", + fieldName: "鍔炵悊鏃堕棿", + width: 100, + }, + { + field: "handle", + fieldName: "鎿嶄綔", + width: 160, + renderFun: (e) => this.renderBtns(e), + }, + ], + params: [ + { + label: "璇佺収鍚嶇О", + key: "name", + placeholder: "璇疯緭鍏�", + }, + ], + // testData: [ + // { + // id: 1, + // name: "鐢靛瓙绀句繚鍗�", + // pic: testCardPhoto, + // time: "2023-01-13", + // }, + // ], + fetcher: async () => { + // console.log(this); + //console.log(params); + // let res = await api.publicEquipment.getBiogasDeviceInfoPage(params); + let res = { + total: this.testData.length, + data: this.testData, + }; + + return res; + }, + }; + }, + activated() { + this.$nextTick(() => { + this.$refs.table.loadData(); + }); + }, + methods: { + renderBtns(e) { + let that = this; + return ( + <div> + <el-button + onClick={() => that.openEdit(e.row)} + size="mini" + plain + type="primary" + > + 缂栬緫 + </el-button> + <el-button + onClick={() => that.delItem(e.row)} + size="mini" + plain + type="warning" + > + 鍒犻櫎 + </el-button> + </div> + ); + }, + renderPic(e) { + return ( + <div> + <el-image + src={e.row.pic} + class="pic-url" + preview-src-list={e.row.picList ? e.row.picList : [e.row.pic]} + ></el-image> + </div> + ); + }, + openEdit(row) { + // console.log(row); + let id = row.id || '' + this.$router.push(`/photo/edit?id=${id}`); + }, + + submitEdit(datas) { + // console.log(datas); + if (datas.id) { + this.testData = this.testData.map((item) => { + if (item.id == datas.id) { + return datas; + } else { + return item; + } + }); + } else { + this.testData = [ + ...this.testData, + { ...datas, id: this.testData.length + 2 }, + ]; + } + + this.$refs.table.loadData(); + }, + delItem(row) { + this.$confirm(`纭鍒犻櫎姝ゆ潯鏁版嵁鍚楋紵`, "鎻愮ず", { + type: "warning", + }) + .then(() => { + this.testData = this.testData.filter((item) => item.id != row.id); + this.$refs.table.loadData(); + }) + .catch(() => {}); + }, + }, +}; +</script> + +<style lang="scss" scoped> +::v-deep { + .pic-url { + width: 116px; + height: 68px; + } +} +</style> diff --git a/src/views/profile/EditEducation.vue b/src/views/profile/EditEducation.vue new file mode 100644 index 0000000000000000000000000000000000000000..2ee46f9998d008d79498ffaafd2ca3970a20abcf --- /dev/null +++ b/src/views/profile/EditEducation.vue @@ -0,0 +1,199 @@ +<template> + <PubDialog + v-model="dialogVisible" + :title="`${id ? '缂栬緫' : '鏂板'}鏁欒偛淇℃伅`" + @beforeClose="beforeClose" + > + <div class="pub-form"> + <el-form + ref="form" + :model="form" + label-width="98px" + label-position="right" + :rules="rules" + size="small" + > + <el-form-item prop="school" label="瀛︽牎:"> + <el-input + v-model="form.school" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + + <el-form-item prop="education" label="瀛﹀巻:"> + <el-input + v-model="form.education" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + + <el-form-item prop="startTime" label="鏃堕棿:"> + <div class="flex-between" style="width:300px"> + <el-date-picker + v-model="form.startTime" + type="date" + value-format="yyyy-MM-DD" + placeholder="閫夋嫨鏃ユ湡" + > + </el-date-picker> + <span>鈥斺€�</span> + <el-date-picker + v-model="form.endTime" + type="date" + value-format="yyyy-MM-DD" + placeholder="閫夋嫨鏃ユ湡" + > + </el-date-picker> + </div> + </el-form-item> + + <el-form-item prop="college" label="瀛﹂櫌:"> + <el-input + v-model="form.college" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + <el-form-item prop="special" label="涓撲笟:"> + <el-input + v-model="form.special" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + <el-form-item prop="studentID" label="瀛﹀彿:"> + <el-input + v-model="form.studentID" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + + <el-form-item> + <el-button + type="primary" + size="small" + @click="submit" + :loading="loading" + >鎻愪氦</el-button + > + <el-button type="primary" plain size="small" @click="close" + >杩斿洖</el-button + > + </el-form-item> + </el-form> + </div> + </PubDialog> +</template> +<script> +import PubDialog from "@/components/App/PubDialog"; +export default { + name: "VideoDialog", + components: { PubDialog }, + data: () => { + return { + id: "", + loading: false, + + form: { + school: "", + education: "", + startTime: "", + endTime: "", + college: "", + special: "", + studentID: "", + }, + rules: { + // name: [ + // { required: true, message: "璇疯緭鍏ヨ鑹插悕绉�", trigger: "change" }, + // ], + }, + }; + }, + props: { + value: { + type: Boolean, + default: false, + }, + }, + computed: { + dialogVisible: { + get: function(that) { + return that.value; + }, + set: function(newValue) { + this.$emit("input", newValue); + }, + }, + }, + methods: { + resetForm() { + this.form = { + id: "", + school: "", + education: "", + startTime: "", + endTime: "", + college: "", + special: "", + studentID: "", + }; + }, + beforeClose() { + // console.log(this.$refs.form?.resetFields); + // this.$refs.form?.resetFields(); + this.resetForm(); + // this.form.endTime = ""; + this.dialogVisible = false; + }, + open(row) { + if (row) { + this.id = row.id; + this.form = this.$utils.setFormValue(this.form, row); + } + this.dialogVisible = true; + }, + close() { + this.beforeClose(); + }, + submit() { + this.$refs.form.validate((valid) => { + if (valid) { + let datas = { ...this.form }; + if (this.id) datas.id = this.id; + this.$message.success("鎿嶄綔鎴愬姛"); + this.beforeClose(); + this.$emit("submit", datas); + // let funName = datas.id ? "editRole" : "addRole"; + // this.loading = true; + // this.$api.system[funName](datas) + // .then((res) => { + // if (res) { + // this.loading = false; + // this.$message.success("鎿嶄綔鎴愬姛"); + // this.beforeClose(); + // this.$emit("success"); + // } + // }) + // .catch(() => { + // this.loading = false; + // }); + } else { + return false; + } + }); + }, + }, +}; +</script> +<style lang="scss" scoped> +::v-deep { + .el-date-editor.el-input, + .el-date-editor.el-input__inner { + width: 132px; + } +} +</style> diff --git a/src/views/profile/EditJob.vue b/src/views/profile/EditJob.vue new file mode 100644 index 0000000000000000000000000000000000000000..660340de19b6ad8a2e01229e920c21b00da22939 --- /dev/null +++ b/src/views/profile/EditJob.vue @@ -0,0 +1,202 @@ +<template> + <PubDialog + v-model="dialogVisible" + :title="`${id ? '缂栬緫' : '鏂板'}鏁欒偛淇℃伅`" + @beforeClose="beforeClose" + > + <div class="pub-form"> + <el-form + ref="form" + :model="form" + label-width="98px" + label-position="right" + :rules="rules" + size="small" + > + <el-form-item prop="company" label="鍏徃:"> + <el-input + v-model="form.company" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + + <el-form-item prop="startTime" label="鏃堕棿:"> + <div class="flex-between" style="width:300px"> + <el-date-picker + v-model="form.startTime" + type="date" + value-format="yyyy-MM-DD" + placeholder="閫夋嫨鏃ユ湡" + > + </el-date-picker> + <span>鈥斺€�</span> + <el-date-picker + v-model="form.endTime" + type="date" + value-format="yyyy-MM-DD" + placeholder="閫夋嫨鏃ユ湡" + > + </el-date-picker> + </div> + </el-form-item> + + <el-form-item prop="jobName" label="鑱屼綅:"> + <el-input + v-model="form.jobName" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + <el-form-item prop="jobStatus" label="鑱屼笟鐘舵€�:"> + <el-input + v-model="form.jobStatus" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + <el-form-item prop="dept" label="閮ㄩ棬:"> + <el-input + v-model="form.dept" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + + <el-form-item prop="content" label="宸ヤ綔鍐呭:"> + <el-input + v-model="form.content" + placeholder="璇疯緭鍏�" + clearable + type="textarea" + ></el-input> + </el-form-item> + <el-form-item> + <el-button + type="primary" + size="small" + @click="submit" + :loading="loading" + >鎻愪氦</el-button + > + <el-button type="primary" plain size="small" @click="close" + >杩斿洖</el-button + > + </el-form-item> + </el-form> + </div> + </PubDialog> +</template> +<script> +import PubDialog from "@/components/App/PubDialog"; +export default { + name: "VideoDialog", + components: { PubDialog }, + data: () => { + return { + id: "", + loading: false, + + form: { + startTime: "", + endTime: "", + company: "", + jobName: "", + jobStatus: "", + dept: "", + content: "", + }, + rules: { + // name: [ + // { required: true, message: "璇疯緭鍏ヨ鑹插悕绉�", trigger: "change" }, + // ], + }, + }; + }, + props: { + value: { + type: Boolean, + default: false, + }, + }, + computed: { + dialogVisible: { + get: function(that) { + return that.value; + }, + set: function(newValue) { + this.$emit("input", newValue); + }, + }, + }, + methods: { + resetForm() { + this.form = { + id: "", + startTime: "", + endTime: "", + company: "", + jobName: "", + jobStatus: "", + dept: "", + content: "", + }; + }, + beforeClose() { + // console.log(this.$refs.form?.resetFields); + // this.$refs.form?.resetFields(); + this.resetForm(); + // this.form.endTime = ""; + this.dialogVisible = false; + }, + open(row) { + if (row) { + this.id = row.id; + this.form = this.$utils.setFormValue(this.form, row); + } + this.dialogVisible = true; + }, + close() { + this.beforeClose(); + }, + submit() { + this.$refs.form.validate((valid) => { + if (valid) { + let datas = { ...this.form }; + if (this.id) datas.id = this.id; + this.$message.success("鎿嶄綔鎴愬姛"); + this.beforeClose(); + this.$emit("submit", datas); + // let funName = datas.id ? "editRole" : "addRole"; + // this.loading = true; + // this.$api.system[funName](datas) + // .then((res) => { + // if (res) { + // this.loading = false; + // this.$message.success("鎿嶄綔鎴愬姛"); + // this.beforeClose(); + // this.$emit("success"); + // } + // }) + // .catch(() => { + // this.loading = false; + // }); + } else { + return false; + } + }); + }, + }, +}; +</script> +<style lang="scss" scoped> +::v-deep { + .el-date-editor.el-input, + .el-date-editor.el-input__inner { + width: 132px; + } + .el-textarea { + width: 325px; + } +} +</style> diff --git a/src/views/profile/PropertyDialog.vue b/src/views/profile/PropertyDialog.vue new file mode 100644 index 0000000000000000000000000000000000000000..5ef420210a8ef863b5cba8765a3c80b9c5100731 --- /dev/null +++ b/src/views/profile/PropertyDialog.vue @@ -0,0 +1,150 @@ +<template> + <PubDialog + v-model="dialogVisible" + :title="`${type == 1 ? '鏂板璧勪骇' : '璧勪骇璇︽儏'}`" + @beforeClose="beforeClose" + > + <div class="pub-form" v-if="type == 1"> + <el-form + ref="form" + :model="form" + label-width="98px" + label-position="right" + :rules="rules" + size="small" + > + <el-form-item prop="name" label="璧勪骇绫诲瀷:"> + <el-input + v-model="form.name" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + + <el-form-item prop="value" label="閲戦:"> + <el-input + v-model="form.value" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + <el-form-item> + <el-button + type="primary" + size="small" + @click="submit" + :loading="loading" + >鎻愪氦</el-button + > + <el-button type="primary" plain size="small" @click="close" + >杩斿洖</el-button + > + </el-form-item> + </el-form> + </div> + </PubDialog> +</template> +<script> +import PubDialog from "@/components/App/PubDialog"; +export default { + name: "PropertyDialog", + components: { PubDialog }, + data: () => { + return { + id: "", + loading: false, + type: 1, + form: { + value: "", + name: "", + }, + rules: { + // name: [ + // { required: true, message: "璇疯緭鍏ヨ鑹插悕绉�", trigger: "change" }, + // ], + }, + }; + }, + props: { + value: { + type: Boolean, + default: false, + }, + }, + computed: { + dialogVisible: { + get: function(that) { + return that.value; + }, + set: function(newValue) { + this.$emit("input", newValue); + }, + }, + }, + methods: { + resetForm() { + this.form = { + value: "", + name: "", + }; + }, + beforeClose() { + // console.log(this.$refs.form?.resetFields); + // this.$refs.form?.resetFields(); + this.resetForm(); + // this.form.endTime = ""; + this.dialogVisible = false; + }, + open(type) { + this.type = type; + // if (row) { + // this.id = row.id; + // this.form = this.$utils.setFormValue(this.form, row); + // } + + this.dialogVisible = true; + }, + close() { + this.beforeClose(); + }, + submit() { + this.$refs.form.validate((valid) => { + if (valid) { + let datas = { ...this.form }; + // if (this.id) datas.id = this.id; + this.$message.success("鎿嶄綔鎴愬姛"); + this.beforeClose(); + this.$emit("submit", datas); + // let funName = datas.id ? "editRole" : "addRole"; + // this.loading = true; + // this.$api.system[funName](datas) + // .then((res) => { + // if (res) { + // this.loading = false; + // this.$message.success("鎿嶄綔鎴愬姛"); + // this.beforeClose(); + // this.$emit("success"); + // } + // }) + // .catch(() => { + // this.loading = false; + // }); + } else { + return false; + } + }); + }, + }, +}; +</script> +<style lang="scss" scoped> +::v-deep { + .el-date-editor.el-input, + .el-date-editor.el-input__inner { + width: 132px; + } + .el-textarea { + width: 325px; + } +} +</style> diff --git a/src/views/profile/education.vue b/src/views/profile/education.vue new file mode 100644 index 0000000000000000000000000000000000000000..271a6429713cb5e90226cb22c392c79d81307e6f --- /dev/null +++ b/src/views/profile/education.vue @@ -0,0 +1,157 @@ +<template> + <InnerView> + <pub-table + :headers="headers" + :fetcher="fetcher" + :params="params" + :pagination="false" + showHeader + ref="table" + > + <div slot="btnRight" class="btnRight"> + <el-button type="primary" size="small" @click="openEdit" + >鏂板</el-button + > + </div> + </pub-table> + <EditEducation + ref="EditEducation" + v-model="EditEducationShow" + @submit="submitEdit" + ></EditEducation> + </InnerView> +</template> + +<script> +import EditEducation from "./EditEducation"; +export default { + name: "Education", + components: { EditEducation }, + meta: {}, + computed: {}, + data() { + return { + EditEducationShow: false, + headers: [ + { + field: "school", + fieldName: "瀛︽牎", + }, + { + field: "education", + fieldName: "瀛﹀巻", + }, + { + field: "time", + fieldName: "鏃堕棿", + width: 180, + formatter: (row) => { + return row.startTime + "~" + row.endTime; + }, + }, + { + field: "college", + fieldName: "瀛﹂櫌", + }, + { + field: "special", + fieldName: "涓撲笟", + }, + { + field: "studentID", + fieldName: "瀛﹀彿", + }, + { + field: "handle", + fieldName: "鎿嶄綔", + width: 160, + renderFun: (e) => this.renderBtns(e), + }, + ], + params: [], + testData: [ + { + id: 1, + school: "閲嶅簡閭數澶у", + education: "鏈", + startTime: "2015-09-01", + endTime: "2019-07-01", + college: "鐢靛瓙淇℃伅瀛﹂櫌", + special: "鐢靛瓙淇℃伅宸ョ▼", + studentID: "******012", + }, + ], + fetcher: async () => { + // console.log(this); + //console.log(params); + // let res = await api.publicEquipment.getBiogasDeviceInfoPage(params); + let res = { + total: this.testData.length, + data: this.testData, + }; + + return res; + }, + }; + }, + methods: { + renderBtns(e) { + let that = this; + return ( + <div> + <el-button + onClick={() => that.openEdit(e.row)} + size="mini" + plain + type="primary" + > + 缂栬緫 + </el-button> + <el-button + onClick={() => that.delItem(e.row)} + size="mini" + plain + type="warning" + > + 鍒犻櫎 + </el-button> + </div> + ); + }, + openEdit(row) { + this.$refs.EditEducation.open(row); + }, + submitEdit(datas) { + // console.log(datas); + if (datas.id) { + this.testData = this.testData.map((item) => { + if (item.id == datas.id) { + return datas; + } else { + return item; + } + }); + } else { + let newId = this.testData[this.testData.length - 1]?.id + ? this.testData[this.testData.length - 1]?.id + 2 + : 2; + this.testData = [...this.testData, { ...datas, id: newId }]; + } + + this.$refs.table.loadData(); + }, + delItem(row) { + this.$confirm(`纭鍒犻櫎姝ゆ潯鏁版嵁鍚楋紵`, "鎻愮ず", { + type: "warning", + }) + .then(() => { + this.testData = this.testData.filter((item) => item.id != row.id); + this.$refs.table.loadData(); + }) + .catch(() => {}); + }, + }, +}; +</script> + +<style></style> diff --git a/src/views/profile/index.vue b/src/views/profile/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..e533e64ec497ad4e46668168bb814e160d43159a --- /dev/null +++ b/src/views/profile/index.vue @@ -0,0 +1,51 @@ +<template> + <InnerView class="flex-col" style="overflow: hidden;"> + <el-menu + :default-active="activeIndex" + class="el-menu-demo" + mode="horizontal" + @select="handleSelect" + > + <el-menu-item index="1">涓汉璧勬枡</el-menu-item> + <el-menu-item index="2">鏁欒偛淇℃伅</el-menu-item> + <el-menu-item index="3">宸ヤ綔缁忓巻</el-menu-item> + <el-menu-item index="4">璧勪骇淇℃伅</el-menu-item> + </el-menu> + <ScrollView> + <Information v-if="activeIndex == '1'"></Information> + <Education v-if="activeIndex == '2'"></Education> + <Job v-if="activeIndex == '3'"></Job> + <Property v-if="activeIndex == '4'"></Property> + </ScrollView> + </InnerView> +</template> +<script> +import Information from "./information.vue"; +import Education from "./education.vue"; +import Job from "./job.vue"; +import Property from "./property.vue"; + +export default { + name: "profile", + components: { Information, Education, Job, Property }, + meta: { + sort: 1, + title: "鎴戠殑妗f", + iconImg: "profile", + iconImgActive: "profileActive", + }, + computed: {}, + data() { + return { + activeIndex: "1", + }; + }, + watch: {}, + methods: { + handleSelect(index) { + this.activeIndex = index; + }, + }, +}; +</script> +<style lang="scss" scoped></style> diff --git a/src/views/profile/information.vue b/src/views/profile/information.vue new file mode 100644 index 0000000000000000000000000000000000000000..85366f4dc3766f9cc0062b8fb4f65083d4423616 --- /dev/null +++ b/src/views/profile/information.vue @@ -0,0 +1,325 @@ +<template> + <InnerView class="flex-col"> + <div class="right-btn"> + <el-button type="primary" plain size="mini" v-if="isEdit" @click="save"> + <i class="el-icon-folder"></i>淇濆瓨 + </el-button> + <el-button + type="primary" + plain + size="mini" + v-else + @click="isEdit = !isEdit" + > + <i class="el-icon-edit-outline"></i>缂栬緫 + </el-button> + </div> + <el-form + ref="form" + :model="form" + label-width="0" + label-position="left" + size="small" + > + <el-descriptions title="" :column="1"> + <el-descriptions-item label="褰撳墠澶村儚"> + <div class="flex-center"> + <div class="avatar"> + <img :src="form.avatar" alt="" /> + </div> + + <el-upload + v-if="isEdit" + class="avatar-uploader" + action="" + :show-file-list="false" + :before-upload=" + (file) => { + beforeUpload(file, 'avatar'); + return false; + } + " + ><el-button type="primary" plain size="mini">鏇存崲澶村儚</el-button> + </el-upload> + </div> + </el-descriptions-item> + <el-descriptions-item label="鐪熷疄濮撳悕"> + <el-form-item prop="name" label="" v-if="isEdit"> + <el-input + v-model="form.name" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + <span v-else>{{ form.name }}</span> + </el-descriptions-item> + + <el-descriptions-item label=""> + <span slot="label">鎬�<span class="hidden-text">鎬у埆</span>鍒�</span> + <el-form-item prop="sex" label="" v-if="isEdit"> + <el-radio-group v-model="form.sex"> + <el-radio :label="'鐢�'">鐢�</el-radio> + <el-radio :label="'濂�'">濂�</el-radio> + </el-radio-group> + </el-form-item> + <span v-else>{{ form.sex }}</span> + </el-descriptions-item> + + <el-descriptions-item label=""> + <span slot="label">姘�<span class="hidden-text">姘戞棌</span>鏃�</span> + <el-form-item prop="nation" label="" v-if="isEdit"> + <el-input + v-model="form.nation" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + <span v-else>{{ form.nation }}</span> + </el-descriptions-item> + + <el-descriptions-item label="鎵嬫満鍙风爜"> + <span>{{ form.phone }}</span> + </el-descriptions-item> + + <el-descriptions-item label=""> + <span slot="label">鍦�<span class="hidden-text">鍦板潃</span>鍧€</span> + <el-form-item prop="address" label="" v-if="isEdit"> + <div class="flex-between" style="width:325px"> + <el-select + v-model="form.address" + placeholder="璇烽€夋嫨" + style="width:155px" + > + <el-option + label="閲嶅簡甯備簯闃冲幙闈掗緳琛楅亾" + value="閲嶅簡甯備簯闃冲幙闈掗緳琛楅亾" + > + </el-option> + </el-select> + <el-input + v-model="form.addressDetail" + style="width:155px" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </div> + </el-form-item> + <span v-else>{{ + hideAddress(form.address, form.addressDetail) + }}</span> + </el-descriptions-item> + + <el-descriptions-item label="鐢靛瓙閭"> + <el-form-item prop="email" label="" v-if="isEdit"> + <el-input + v-model="form.email" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + <span v-else>{{ form.email }}</span> + </el-descriptions-item> + + <el-descriptions-item label="璇佷欢鍙风爜"> + <el-form-item prop="cardID" label="" v-if="isEdit"> + <el-input + v-model="form.cardID" + placeholder="璇疯緭鍏�" + clearable + ></el-input> + </el-form-item> + <span v-else>{{ hideAddress(form.cardID) }}</span> + </el-descriptions-item> + + <el-descriptions-item label="璇佷欢鐓х墖"> + <div class="flex"> + <div class="photo"> + <img :src="form.idcardimg1" alt="" /> + <div class="uploader" v-if="isEdit"> + <el-upload + class="avatar-uploader" + action="" + :show-file-list="false" + :before-upload=" + (file) => { + beforeUpload(file, 'idcardimg1'); + return false; + } + " + > + <i class="el-icon-upload2"></i> + 涓婁紶 + </el-upload> + </div> + </div> + <div class="photo"> + <img :src="form.idcardimg2" alt="" /> + <div class="uploader" v-if="isEdit"> + <el-upload + class="avatar-uploader" + action="" + :show-file-list="false" + :before-upload=" + (file) => { + beforeUpload(file, 'idcardimg2'); + return false; + } + " + > + <i class="el-icon-upload2"></i> + 涓婁紶 + </el-upload> + </div> + </div> + </div> + </el-descriptions-item> + </el-descriptions> + </el-form> + </InnerView> +</template> +<script> +import testAvatar from "@/assets/img/avatar-test.png"; +import idcard1 from "@/assets/img/idcard1.png"; +import idcard2 from "@/assets/img/idcard2.png"; + +export default { + name: "Information", + components: {}, + meta: {}, + computed: {}, + data() { + return { + isEdit: false, + form: { + avatar: testAvatar, + name: "鏉庝簯", + sex: "濂�", + nation: "姹夋棌", + phone: "158****7854", + address: "閲嶅簡甯備簯闃冲幙闈掗緳琛楅亾", + addressDetail: "閲戠涓栫晫鍩�17-12-5", + email: "65874258741@163.com", + cardID: "500235199205274588", + idcardimg1: idcard1, + idcardimg2: idcard2, + }, + }; + }, + watch: {}, + methods: { + hideAddress(address = "", addressDetail = "") { + let add = "" + address + addressDetail; + + let arr = add.split(""); + + let res = arr.map((item, index) => { + if (index < 6) { + return item; + } else { + return "*"; + } + }); + return res.join(""); + }, + uploadFile() {}, + async beforeUpload(file, field) { + let url = await this.$utils.file2Base64(file); + // console.log(url); + this.$set(this.form, field, url); + return false; + }, + save() { + this.$message.success("鎿嶄綔鎴愬姛"); + this.isEdit = false; + }, + }, +}; +</script> +<style lang="scss" scoped> +.avatar { + width: 80px; + height: 80px; + border-radius: 50%; + overflow: hidden; + margin-right: 16px; + + box-shadow: 0px 2px 6px rgba($color: #000000, $alpha: 0.2); + img { + width: 100%; + height: 100%; + } +} +.flex-col { + position: relative; + .right-btn { + position: absolute; + right: 64px; + top: 34px; + ::v-deep { + span { + display: flex; + align-items: center; + + i { + font-size: 17px; + margin-right: 5px; + } + } + } + } +} +::v-deep { + .el-select .el-input { + width: auto; + } + .el-form { + .el-descriptions-item__label:not(.is-bordered-label) { + line-height: 30px; + } + .el-descriptions-item__container .el-descriptions-item__content { + line-height: 30px; + } + } + .el-form-item--small.el-form-item { + margin-bottom: 0; + } + .el-descriptions :not(.is-bordered) .el-descriptions-item__cell { + padding-bottom: 10px; + } +} +.photo { + width: 141px; + height: 93px; + margin-right: 15px; + position: relative; + img { + width: 100%; + height: 100%; + } +} +.uploader { + width: 100%; + height: 100%; + position: absolute; + left: 0; + top: 0; + background-color: rgba($color: #000000, $alpha: 0.5); + color: #fff; + .avatar-uploader { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + ::v-deep { + .el-upload { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; + } + } + } +} +</style> diff --git a/src/views/profile/job.vue b/src/views/profile/job.vue new file mode 100644 index 0000000000000000000000000000000000000000..35e13fd6ed0475c7e54f96507412460f23286eb5 --- /dev/null +++ b/src/views/profile/job.vue @@ -0,0 +1,154 @@ +<template> + <InnerView> + <pub-table + :headers="headers" + :fetcher="fetcher" + :params="params" + :pagination="false" + showHeader + ref="table" + > + <div slot="btnRight" class="btnRight"> + <el-button type="primary" size="small" @click="openEdit" + >鏂板</el-button + > + </div> + </pub-table> + <EditJob ref="EditJob" v-model="EditJobShow" @submit="submitEdit"></EditJob> + </InnerView> +</template> + +<script> +import EditJob from "./EditJob"; +export default { + name: "Job", + components: { EditJob }, + meta: {}, + computed: {}, + data() { + return { + EditJobShow: false, + headers: [ + { + field: "company", + fieldName: "鍏徃", + }, + { + field: "time", + fieldName: "鏃堕棿", + width: 180, + formatter: (row) => { + return row.startTime + "~" + row.endTime; + }, + }, + { + field: "jobName", + fieldName: "鑱屼綅鍚嶇О", + }, + { + field: "jobStatus", + fieldName: "鑱屼笟鐘舵€�", + }, + { + field: "dept", + fieldName: "閮ㄩ棬", + }, + { + field: "content", + fieldName: "宸ヤ綔鍐呭", + width: 140, + }, + { + field: "handle", + fieldName: "鎿嶄綔", + width: 160, + renderFun: (e) => this.renderBtns(e), + }, + ], + params: [], + testData: [ + { + id: 1, + startTime: "2015-09-01", + endTime: "2019-07-01", + company: "涔濆惃绉戞妧", + jobName: "浜у搧缁忕悊", + jobStatus: "绂昏亴", + dept: "浜嬩笟涓€閮�", + content: "浜у搧璋冪爺锛屼骇鍝佸師鍨嬶紝浜у搧璁捐锛岄渶姹傛枃妗c€侀渶姹傝瑙�", + }, + ], + fetcher: async () => { + // console.log(this); + //console.log(params); + // let res = await api.publicEquipment.getBiogasDeviceInfoPage(params); + let res = { + total: this.testData.length, + data: this.testData, + }; + return res; + }, + }; + }, + methods: { + renderBtns(e) { + let that = this; + return ( + <div> + <el-button + onClick={() => that.openEdit(e.row)} + size="mini" + plain + type="primary" + > + 缂栬緫 + </el-button> + <el-button + onClick={() => that.delItem(e.row)} + size="mini" + plain + type="warning" + > + 鍒犻櫎 + </el-button> + </div> + ); + }, + openEdit(row) { + this.$refs.EditJob.open(row); + }, + submitEdit(datas) { + // console.log(datas); + + if (datas.id) { + this.testData = this.testData.map((item) => { + if (item.id == datas.id) { + return datas; + } else { + return item; + } + }); + } else { + let newId = this.testData[this.testData.length - 1]?.id + ? this.testData[this.testData.length - 1]?.id + 2 + : 2; + this.testData = [...this.testData, { ...datas, id: newId }]; + } + + this.$refs.table.loadData(); + }, + delItem(row) { + this.$confirm(`纭鍒犻櫎姝ゆ潯鏁版嵁鍚楋紵`, "鎻愮ず", { + type: "warning", + }) + .then(() => { + this.testData = this.testData.filter((item) => item.id != row.id); + this.$refs.table.loadData(); + }) + .catch(() => {}); + }, + }, +}; +</script> + +<style></style> diff --git a/src/views/profile/property.vue b/src/views/profile/property.vue new file mode 100644 index 0000000000000000000000000000000000000000..7803b29669600f0a2621481b335fe22ef66f9ccb --- /dev/null +++ b/src/views/profile/property.vue @@ -0,0 +1,249 @@ +<template> + <InnerView> + <ScrollView> + <el-button + type="primary" + size="small" + @click="addProperty" + style="margin-top:19px" + >鏂板璧勪骇</el-button + > + <div class="total-property"> + <div class="flex"> + <img src="@/assets/img/property.png" alt="" /> + <span>璧勪骇鎬婚</span> + </div> + <div class="value">{{ allProperty }}</div> + <div class="open-detail" @click="openDetail">鏌ョ湅</div> + </div> + + <div class="content-title">璧勪骇鍒嗗竷</div> + <div class="chart" id="chart"></div> + </ScrollView> + <PropertyDialog + ref="PropertyDialog" + v-model="PropertyDialogShow" + @submit="submitDialog" + ></PropertyDialog> + + <PubDialog + v-model="dialogVisible" + :title="`璧勪骇璇︽儏`" + @beforeClose="dialogVisible = false" + > + <div class="property-box"> + <pub-table + :headers="headers" + :fetcher="fetcher" + :pagination="false" + ref="table" + > + </pub-table> + </div> + </PubDialog> + </InnerView> +</template> +<script> +import PropertyDialog from "./PropertyDialog.vue"; +import PubDialog from "@/components/App/PubDialog"; +export default { + name: "Property", + components: { PropertyDialog, PubDialog }, + meta: {}, + data() { + return { + PropertyDialogShow: false, + dialogVisible: false, + testData: [ + { + name: "瀛樻", + value: "1000", + updateTime: "2023-07-01 12:25:12", + }, + { + name: "鍩洪噾", + value: "253", + updateTime: "2023-06-25 16:15:24", + }, + { + name: "鑲$エ", + value: "800", + updateTime: "2023-06-12 14:21:38", + }, + ], + + headers: [ + { + field: "name", + fieldName: "璧勪骇绫诲瀷", + }, + { + field: "value", + fieldName: "閲戦", + }, + { + field: "updateTime", + fieldName: "涓婁紶鏃堕棿", + }, + ], + params: [], + fetcher: async () => { + console.log("this.testData", this); + // console.log(this); + //console.log(params); + // let res = await api.publicEquipment.getBiogasDeviceInfoPage(params); + let res = { + total: this?.testData?.length, + data: this?.testData, + }; + console.log(res); + return res; + }, + }; + }, + computed: { + allProperty() { + let all = 0; + for (let i = 0; i < this.testData.length; i++) { + const element = this.testData[i]; + all += parseFloat(element.value); + } + return all.toFixed(2); + }, + }, + watch: {}, + mounted() { + this.getCharts(); + }, + methods: { + addProperty() { + this.$refs.PropertyDialog.open(1); + }, + openDetail() { + this.dialogVisible = true; + // this.$refs.PropertyDialog.open(2, this.testData); + }, + submitDialog(datas) { + let time = this.$utils.formatTimeWithDayjs(new Date()); + this.testData = [ + ...this.testData, + { + ...datas, + updateTime: time, + }, + ]; + this.getCharts(); + }, + getCharts() { + const chartBox = this.$echarts.init(document.getElementById("chart")); + const option = { + backgroundColor: "white", + tooltip: { + show: true, + trigger: "item", + //{a}(绯诲垪鍚�)锛寋b}(鏁版嵁椤瑰悕),{c}(鏁板€�),{d}(鐧惧垎姣�) + formatter: "{a} <br/>{b} : {c}", + backgroundColor: "rgba(1, 13, 19, 0.5)", + borderWidth: 0, + textStyle: { + color: "rgba(212, 232, 254, 1)", + // fontSize: fontChart(0.24), + }, + }, + + legend: { + top: 10, + left:'10%', + itemWidth: 25, + itemHeight: 14, + borderRadius: 8, + textStyle: { + color: "#000", + fontFamily: "Alibaba PuHuiTi", + fontSize: 14, + fontWeight: 400, + }, + }, + series: [ + { + name: "璧勪骇鍒嗗竷", + type: "pie", + radius: "70%", + center: ["25%", "54%"], + data: this.testData, + label: { + normal: { + formatter: ["{b|{b}}", "{c|{c}}"].join("\n"), + rich: { + c: { + color: "inherit", + fontSize: 12, + }, + b: { + fontSize: 12, + height: 25, + }, + }, + }, + }, + emphasis: { + itemStyle: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: "rgba(0, 0, 0, 0.5)", + }, + }, + }, + ], + }; + chartBox.setOption(option); + // 鏍规嵁椤甸潰澶у皬鑷姩鍝嶅簲鍥捐〃澶у皬 + window.addEventListener("resize", function() { + chartBox.resize(); + }); + }, + }, +}; +</script> +<style lang="scss" scoped> +.property-box { + height: 400px; + width: 100%; +} +.total-property { + width: 242px; + height: 132px; + border-radius: 16px; + background: #ffa74f; + color: #fff; + font-size: 16px; + padding-left: 21px; + margin-top: 30px; + .flex { + align-items: center; + height: 54px; + } + img { + width: 16px; + height: 16px; + margin-right: 7px; + } + .value { + font-size: 30px; + font-weight: bold; + line-height: 36px; + margin-bottom: 7px; + } + .open-detail { + font-size: 14px; + cursor: pointer; + } +} +.content-title { + margin-top: 37px; +} +.chart { + width: 700px; + height: 300px; +} +</style> diff --git a/src/views/serviceData/index.vue b/src/views/serviceData/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..63e10ead47b7b6e381e9f899dff2ba49479eb08e --- /dev/null +++ b/src/views/serviceData/index.vue @@ -0,0 +1,20 @@ +<template> + <InnerView> </InnerView> +</template> +<script> +export default { + name: "serviceData", + meta: { + sort: 4, + title: "鎴戠殑鍔炰簨鏁版嵁", + iconImg: "serviceData", + iconImgActive: "serviceDataActive", + }, + components: {}, + data() { + return {}; + }, + watch: {}, +}; +</script> +<style lang="scss" scoped></style> diff --git a/src/views/spaceIndex/index.vue b/src/views/spaceIndex/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..a0c3ce8a749a28f051e09edd0e9a6efd54f02b44 --- /dev/null +++ b/src/views/spaceIndex/index.vue @@ -0,0 +1,32 @@ +<template> + <!-- <transition :name="transition"> --> + <keep-alive :include="cacheRoutes"> + <router-view class="child-view"></router-view> + </keep-alive> + <!-- </transition> --> +</template> +<script> +import { mapState } from "vuex"; +// import { InnerView, RouteView } from "@/components/Layout"; +export default { + name: "spaceIndex", + // components: { InnerView, RouteView }, + meta: { + sort: 0, + title: "绌洪棿棣栭〉", + iconImg: "spaceIndex", + iconImgActive: "spaceIndexActive", + redirect: "/spaceIndex/main", + }, + computed: { + ...mapState({ + cacheRoutes: (state) => state.app.cacheRoutes, + }), + }, + data() { + return {}; + }, + watch: {}, +}; +</script> +<style lang="scss" scoped></style> diff --git a/src/views/spaceIndex/main/index.vue b/src/views/spaceIndex/main/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..8b0dd2a651661e006f0ea60b50d8d0367132c9d3 --- /dev/null +++ b/src/views/spaceIndex/main/index.vue @@ -0,0 +1,169 @@ +<template> + <InnerView class="flex-col" style="overflow: hidden;"> + <el-menu + :default-active="activeIndex" + class="el-menu-demo" + mode="horizontal" + @select="handleSelect" + > + <el-menu-item index="1">涓汉淇℃伅</el-menu-item> + <el-menu-item index="2">涓汉鏉愭枡</el-menu-item> + </el-menu> + <ScrollView> + <template v-if="activeIndex == '1'"> + <el-descriptions title="" :column="1"> + <el-descriptions-item label="褰撳墠澶村儚"> + <div class="avatar"> + <img src="@/assets/img/avatar-test.png" alt="" /> + </div> + </el-descriptions-item> + <el-descriptions-item label="鐪熷疄濮撳悕">*浜�</el-descriptions-item> + <el-descriptions-item label="璇佷欢鍙风爜" + >**************74588</el-descriptions-item + > + <el-descriptions-item label="瀹炲悕璁よ瘉">鍥涚骇璁よ瘉</el-descriptions-item> + <el-descriptions-item label="鎵嬫満鍙风爜" + >158****7854</el-descriptions-item + > + <el-descriptions-item label=""> + <span slot="label">鍦�<span class="hidden-text">鍦板潃</span>鍧€</span> + 閲嶅簡甯備簯闃冲幙************ + </el-descriptions-item> + <el-descriptions-item label="鐢靛瓙閭" + >65874******@163.com</el-descriptions-item + > + </el-descriptions> + </template> + + <template v-if="activeIndex == '2'"> + <pub-table + :headers="headers" + :fetcher="fetcher" + :params="params" + :pagination="false" + ref="table" + > + </pub-table> + </template> + </ScrollView> + </InnerView> +</template> + +<script> +// import * as api from "@/api"; +export default { + name: "SpaceIndexMain", + meta: { + sort: 0, + title: "绌洪棿棣栭〉", + activeName: "spaceIndex", + hidden: true, + keepAlive: true, + }, + components: {}, + data() { + return { + activeIndex: "1", + headers: [ + { + field: "index", + fieldName: "搴忓彿", + type: "index", + }, + { + field: "materialName", + fieldName: "鏉愭枡鍚嶇О", + }, + { + field: "opdateTime", + fieldName: "涓婁紶鏃堕棿", + }, + { + field: "handle", + fieldName: "鎿嶄綔", + width: 136, + renderFun: (e) => this.renderBtns(e), + }, + ], + params: [ + { + label: "鏉愭枡鍚嶇О", + key: "materialName", + placeholder: "璇疯緭鍏�", + }, + ], + testData: [ + { + materialName: "鐢宠鍦ㄦ牎姹傝亴鍒涗笟琛ヨ创鐩稿叧璧勬枡", + opdateTime: "2023-01-13 12:25:23", + }, + { + materialName: "楂樼瓑瀛︽牎绛夋瘯涓氱敓鎺ユ敹鎵嬬画鍔炵悊鐩稿叧璧勬枡", + opdateTime: "2023-01-08 09:23:46", + }, + { + materialName: "鍙楃悊鍏垂甯堣寖鐢熻法鐪佷换鏁欑敵璇风浉鍏宠祫鏂�", + opdateTime: "2023-01-07 09:15:42", + }, + { + materialName: "妗f鐨勬帴鏀跺拰杞€掔殑鐩稿叧璧勬枡", + opdateTime: "2023-01-06 14:28:13", + }, + { + materialName: "鑱屼笟鎸囧鐩稿叧璧勬枡", + opdateTime: "2023-01-04 11:18:23", + }, + ], + fetcher: async () => { + // console.log(this); + //console.log(params); + // let res = await api.publicEquipment.getBiogasDeviceInfoPage(params); + let res = { + total: this.testData.length, + data: this.testData, + }; + return res; + }, + }; + }, + watch: {}, + methods: { + renderBtns(e) { + let that = this; + return ( + <div> + <el-button + onClick={() => that.openDetail(e.row)} + size="mini" + plain + type="primary" + > + 璇︽儏 + </el-button> + </div> + ); + }, + openDetail() { + this.$router.push("/spaceIndex/materiaDetail"); + }, + handleSelect(index) { + // console.log(index); + this.activeIndex = index; + }, + }, +}; +</script> +<style lang="scss" scoped> +.avatar { + width: 80px; + height: 80px; + border-radius: 50%; + overflow: hidden; + + box-shadow: 0px 2px 6px rgba($color: #000000, $alpha: 0.2); + img { + width: 100%; + height: 100%; + } +} +</style> diff --git a/src/views/spaceIndex/materiaDetail/index.vue b/src/views/spaceIndex/materiaDetail/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..ff467f8d2c43fc5b1786bf2153f3acbc383c7b0e --- /dev/null +++ b/src/views/spaceIndex/materiaDetail/index.vue @@ -0,0 +1,65 @@ +<template> + <InnerView class="flex-col" style="overflow: hidden;"> + <BackTitle title="鏉愭枡璇︽儏"></BackTitle> + <ScrollView> + <div class="content-title">鍩虹淇℃伅</div> + + <el-descriptions title="" :column="1" style="padding-left:30px"> + <el-descriptions-item label="鏉愭枡鍚嶇О" + >鐢宠鍦ㄦ牎姹傝亴鍒涗笟琛ヨ创鐩稿叧璧勬枡</el-descriptions-item + > + <el-descriptions-item label="涓婁紶鏃堕棿" + >2023-01-13 12:25:23</el-descriptions-item + > + </el-descriptions> + <div class="content-title">鏉愭枡鏂囦欢</div> + <div class="file-box flex-between"> + <span>鐢宠鍦ㄦ牎姹傝亴鍒涗笟琛ヨ创鐩稿叧璧勬枡</span> + <div class="flex download"> + <i class="el-icon-download"></i> + <span>涓嬭浇</span> + </div> + </div> + </ScrollView> + </InnerView> +</template> + +<script> +// import * as api from "@/api"; +export default { + name: "SpaceIndexMateriaDetail", + meta: { + sort: 1, + title: "绌洪棿棣栭〉", + activeName: "spaceIndex", + hidden: true, + }, + components: {}, + data() { + return {}; + }, + watch: {}, + methods: {}, +}; +</script> +<style lang="scss" scoped> +.file-box { + width: 529px; + height: 36px; + border: 1px solid #e5e5e5; + padding: 0 22px 0 18px; + font-size: 12px; + color: #666; + margin-top: 38px; + margin-left: 30px; + .download { + color: #3182ff; + align-items: center; + cursor: pointer; + i { + font-size: 17px; + margin-right: 5px; + } + } +} +</style> diff --git a/vue.config.js b/vue.config.js new file mode 100644 index 0000000000000000000000000000000000000000..9e12205b173a80e052a9119de031d74314301510 --- /dev/null +++ b/vue.config.js @@ -0,0 +1,80 @@ +const path = require("path"); +// const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; + +module.exports = { + lintOnSave: process.env.NODE_ENV === "development", + productionSourceMap: false, + devServer: { + open: false, + // proxy: { + // [process.env.VUE_APP_BASE_API]: { + // target: process.env.VUE_APP_REMOTE_URL, + // changeOrigin: true, + // pathRewrite: { + // ["^" + process.env.VUE_APP_BASE_API]: "" + // } + // } + // }, + // overlay: { + // errors: true, + // warnings: false + // } + }, + configureWebpack: { + // plugins: [new BundleAnalyzerPlugin()], + }, + chainWebpack(config) { + // it can improve the speed of the first screen, it is recommended to turn on preload + // it can improve the speed of the first screen, it is recommended to turn on preload + config.plugin("preload").tap(() => [ + { + rel: "preload", + // to ignore runtime.js + // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171 + fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/], + include: "initial" + } + ]); + + // when there are many pages, it will cause too many meaningless requests + config.plugins.delete("prefetch"); + + config.when(process.env.NODE_ENV !== "development", config => { + config + .plugin("ScriptExtHtmlWebpackPlugin") + .after("html") + .use("script-ext-html-webpack-plugin", [ + { + // `runtime` must same as runtimeChunk name. default is `runtime` + inline: /runtime\..*\.js$/ + } + ]) + .end(); + config.optimization.splitChunks({ + chunks: "all", + cacheGroups: { + libs: { + name: "chunk-libs", + test: /[\\/]node_modules[\\/]/, + priority: 10, + chunks: "initial" // only package third parties that are initially dependent + }, + elementUI: { + name: "chunk-elementUI", // split elementUI into a single package + priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app + test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm + }, + commons: { + name: "chunk-commons", + test: path.join(__dirname, "src/components"), // can customize your rules + minChunks: 3, // minimum common number + priority: 5, + reuseExistingChunk: true + } + } + }); + // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk + config.optimization.runtimeChunk("single"); + }); + } +};