├── .browserslistrc ├── .editorconfig ├── .env.development ├── .env.production ├── .env.test ├── .eslintrc.js ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .prettierignore ├── .prettierrc ├── README.md ├── babel.config.js ├── commitlint.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html └── page │ └── run-time │ ├── index.html │ ├── script.js │ └── style.css ├── src ├── App.vue ├── assets │ ├── css │ │ ├── base.less │ │ └── index.less │ └── images │ │ ├── background_img.jpg │ │ ├── logo.png │ │ ├── qq.png │ │ ├── qq_logo.png │ │ ├── weichat.png │ │ └── weichat_logo.jpg ├── common-ui │ ├── breadcrumb │ │ ├── index.ts │ │ ├── src │ │ │ └── BreadCrumb.vue │ │ └── types │ │ │ └── types.ts │ ├── msi-card │ │ ├── index.ts │ │ └── src │ │ │ └── MsiCard.vue │ ├── msi-descriptions │ │ ├── index.ts │ │ └── src │ │ │ └── MsiDescriptions.vue │ ├── msi-echarts │ │ ├── hooks │ │ │ ├── initECharts.ts │ │ │ └── mapCityToMap.ts │ │ ├── index.ts │ │ ├── map │ │ │ ├── china.json │ │ │ └── city.ts │ │ └── src │ │ │ └── MsiEcharts.vue │ ├── msi-editor │ │ ├── index.ts │ │ └── src │ │ │ └── MsiEditor.vue │ ├── msi-form │ │ ├── index.ts │ │ ├── src │ │ │ └── MsiForm.vue │ │ └── types │ │ │ └── types.ts │ ├── msi-tabel │ │ ├── index.ts │ │ ├── src │ │ │ └── MsiTabel.vue │ │ └── types │ │ │ └── types.ts │ └── msi-upload │ │ ├── index.ts │ │ └── src │ │ └── MsiUpload.vue ├── components │ ├── nav-header │ │ ├── index.ts │ │ └── src │ │ │ ├── NavHeader.vue │ │ │ └── cpn │ │ │ └── NavDialog.vue │ ├── nav-menu │ │ ├── index.ts │ │ └── src │ │ │ └── NavMenu.vue │ ├── page-dialog │ │ ├── index.ts │ │ ├── src │ │ │ └── PageDialog.vue │ │ └── types │ │ │ └── types.ts │ ├── page-echart │ │ ├── index.ts │ │ └── src │ │ │ ├── PageBarChart.vue │ │ │ ├── PageChinaChart.vue │ │ │ ├── PageLineChart.vue │ │ │ ├── PagePicChart.vue │ │ │ ├── PagePicLableChart.vue │ │ │ └── PageRoseChart.vue │ ├── page-search │ │ ├── index.ts │ │ └── src │ │ │ └── PageSearch.vue │ └── page-tabel │ │ ├── index.ts │ │ └── src │ │ └── PageTabel.vue ├── global │ ├── index.ts │ ├── registerElement.ts │ └── registerGlobal.ts ├── hooks │ ├── countAction.ts │ ├── pageLinkage.ts │ └── permission.ts ├── main.ts ├── router │ ├── index.ts │ └── main │ │ ├── analysis │ │ ├── dashboard │ │ │ └── dashboard.ts │ │ └── overview │ │ │ └── overview.ts │ │ ├── product │ │ ├── category │ │ │ └── category.ts │ │ └── goods │ │ │ └── goods.ts │ │ ├── story │ │ ├── chat │ │ │ └── chat.ts │ │ └── list │ │ │ └── list.ts │ │ └── system │ │ ├── department │ │ └── department.ts │ │ ├── menu │ │ └── menu.ts │ │ ├── role │ │ └── role.ts │ │ └── user │ │ └── user.ts ├── service │ ├── index.ts │ ├── login │ │ ├── index.ts │ │ └── types.ts │ ├── main │ │ ├── analysis │ │ │ └── index.ts │ │ ├── story │ │ │ └── index.ts │ │ └── system │ │ │ └── index.ts │ ├── request │ │ ├── index.ts │ │ └── type.ts │ └── types.ts ├── shims-vue.d.ts ├── store │ ├── analysis │ │ ├── index.ts │ │ └── types.ts │ ├── index.ts │ ├── login │ │ ├── index.ts │ │ └── types.ts │ ├── product │ │ ├── index.ts │ │ └── types.ts │ ├── system │ │ ├── index.ts │ │ └── types.ts │ └── types.ts ├── utils │ ├── cache.ts │ ├── formate.ts │ ├── handleString.ts │ └── menuToRoute.ts └── views │ ├── login │ ├── Login.vue │ ├── cpns │ │ ├── LoginPhone.vue │ │ └── LoginUser.vue │ └── hooks │ │ └── rules.ts │ ├── main │ ├── Main.vue │ ├── analysis │ │ ├── dashboard │ │ │ ├── config │ │ │ │ └── showCountConfig.ts │ │ │ ├── cpn │ │ │ │ ├── ShowCharts.vue │ │ │ │ └── ShowCount.vue │ │ │ └── dashboard.vue │ │ └── overview │ │ │ ├── config │ │ │ ├── dependencies.ts │ │ │ ├── devDependencies.ts │ │ │ ├── projectStandard.ts │ │ │ ├── projectTree.ts │ │ │ └── technologyStacks.ts │ │ │ └── overview.vue │ ├── product │ │ ├── category │ │ │ ├── category.vue │ │ │ ├── config │ │ │ │ ├── dialog.config.ts │ │ │ │ ├── form.config.ts │ │ │ │ └── tabel.config.ts │ │ │ └── cpn │ │ │ │ └── CategoryHeader.vue │ │ └── goods │ │ │ ├── configs │ │ │ ├── dialog.config.ts │ │ │ └── tabel.config.ts │ │ │ └── goods.vue │ ├── story │ │ ├── chat │ │ │ └── chat.vue │ │ └── list │ │ │ ├── config │ │ │ └── tabel.config.ts │ │ │ └── list.vue │ └── system │ │ ├── department │ │ ├── config │ │ │ ├── dialog.config.ts │ │ │ ├── from.config.ts │ │ │ └── tabel.config.ts │ │ └── department.vue │ │ ├── menu │ │ ├── configs │ │ │ ├── dialog.config.ts │ │ │ └── tabel.config.ts │ │ └── menu.vue │ │ ├── role │ │ ├── config │ │ │ ├── dialog.config.ts │ │ │ ├── form.config.ts │ │ │ └── tabel.config.ts │ │ └── role.vue │ │ └── user │ │ ├── configs │ │ ├── dialog.config.ts │ │ ├── form.config.ts │ │ └── tabel.config.ts │ │ └── user.vue │ └── not-found │ └── NotFound.vue ├── tsconfig.json └── vue.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] # 表示所有文件适用 6 | charset = utf-8 # 设置文件字符集为 utf-8 7 | indent_style = space # 缩进风格(tab | space) 8 | indent_size = 2 # 缩进大小 9 | end_of_line = lf # 控制换行类型(lf | cr | crlf) 10 | trim_trailing_whitespace = true # 去除行首的任意空白字符 11 | insert_final_newline = true # 始终在文件末尾插入一个新行 12 | 13 | [*.md] # 表示仅 md 文件适用以下规则 14 | max_line_length = off 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | VUE_APP_BASE_URL = /api 2 | VUE_APP_TIME_OUT = 10000 3 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | VUE_APP_BASE_URL = http://152.136.185.210:4000 2 | -------------------------------------------------------------------------------- /.env.test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzhibin/vue3_ts_cms/e0ca05268a6c7f797c05f5ac99af7e457a86b80e/.env.test -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: [ 7 | "plugin:vue/vue3-essential", 8 | "eslint:recommended", 9 | "@vue/typescript/recommended", 10 | "@vue/prettier", 11 | "@vue/prettier/@typescript-eslint", 12 | "plugin:prettier/recommended" 13 | ], 14 | parserOptions: { 15 | ecmaVersion: 2020 16 | }, 17 | rules: { 18 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", 19 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", 20 | "@typescript-eslint/no-var-requires": "off", 21 | "@typescript-eslint/no-explicit-any": "off", 22 | "@typescript-eslint/no-non-null-assertion": "off", 23 | "@typescript-eslint/explicit-module-boundary-types": "off" 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run lint 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | .local 3 | .output.js 4 | /node_modules/** 5 | 6 | **/*.svg 7 | **/*.sh 8 | 9 | /public/* 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "tabWidth": 2, 4 | "printWidth": 80, 5 | "singleQuote": false, 6 | "trailingComma": "none", 7 | "semi": true 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 基于Vue3+TypeScript的后台管理系统 2 | 3 | > ### 1.线上体验 4 | 5 | [Vue3+TS后台管理系统在线体验](http://cms.nanxing.ltd) 6 | 7 | **客官如果觉得还不戳,github上不妨顺手点个 :star:,鼓励一下吧。** 8 | 9 | 10 | 11 | > ### 2.项目运行 12 | 13 | * git clone 到本地 14 | * cd 到 vue3_ts_cms目录下运行: 15 | 16 | ~~~ 17 | npm install 或者 cnpm install 18 | ~~~ 19 | 20 | * 运行 21 | 22 | ~~~ 23 | npm run serve 24 | ~~~ 25 | 26 | * 浏览器打开 http://localost:8080/ 27 | 28 | > ### 3.项目功能(部分展示) 29 | 30 | #### 3.1 登陆页面 (默认用户&密码:nanxing,123456) 31 | 32 | ![image-20210827235245708](https://img-blog.csdnimg.cn/972393c864c74d1cb3f368ab88246dcc.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5b-Y5b-Y56KO5paMYmlu,size_20,color_FFFFFF,t_70,g_se,x_16) 33 | 34 | #### 3.2 页面展示 (侧边菜单 - 技术栈展示) 35 | 36 | 37 | #### 3.3系统管理(搜索联动) 38 | 39 | 40 | #### 3.4 商品数据展示(可视化页面) 41 | 42 | > ### 4.项目提交 43 | 44 | ~~~ 45 | npm run commit 46 | ~~~ 47 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | [ 4 | "import", 5 | { 6 | libraryName: "element-plus", 7 | customStyleName: (name) => { 8 | return `element-plus/lib/theme-chalk/${name}.css`; 9 | } 10 | } 11 | ] 12 | ], 13 | presets: ["@vue/cli-plugin-babel/preset"] 14 | }; 15 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["@commitlint/config-conventional"] 3 | }; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msi_cms", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "prettier": "prettier --write .", 10 | "prepare": "husky install", 11 | "commit": "cz" 12 | }, 13 | "dependencies": { 14 | "axios": "^0.21.1", 15 | "core-js": "^3.6.5", 16 | "countup.js": "^2.0.8", 17 | "dayjs": "^1.10.6", 18 | "echarts": "^5.1.2", 19 | "normalize.css": "^8.0.1", 20 | "vue": "^3.2.4", 21 | "vue-countup-v2": "^4.0.0", 22 | "vue-router": "^4.0.10", 23 | "vuex": "^4.0.2", 24 | "wangeditor": "^4.7.7" 25 | }, 26 | "devDependencies": { 27 | "@commitlint/cli": "^13.1.0", 28 | "@commitlint/config-conventional": "^13.1.0", 29 | "@typescript-eslint/eslint-plugin": "^4.18.0", 30 | "@typescript-eslint/parser": "^4.18.0", 31 | "@vue/cli-plugin-babel": "~4.5.0", 32 | "@vue/cli-plugin-eslint": "~4.5.0", 33 | "@vue/cli-plugin-typescript": "~4.5.0", 34 | "@vue/cli-service": "~4.5.0", 35 | "@vue/compiler-sfc": "^3.2.4", 36 | "@vue/eslint-config-prettier": "^6.0.0", 37 | "@vue/eslint-config-typescript": "^7.0.0", 38 | "babel-plugin-import": "^1.13.3", 39 | "babel-plugin-transform-remove-console": "^6.9.4", 40 | "commitizen": "^4.2.4", 41 | "cz-conventional-changelog": "^3.3.0", 42 | "element-plus": "^1.0.2-beta.65", 43 | "eslint": "^6.7.2", 44 | "eslint-plugin-prettier": "^3.3.1", 45 | "eslint-plugin-vue": "^7.0.0", 46 | "husky": "^7.0.0", 47 | "less": "^3.0.4", 48 | "less-loader": "^5.0.0", 49 | "prettier": "^2.3.2", 50 | "typescript": "~4.1.5" 51 | }, 52 | "config": { 53 | "commitizen": { 54 | "path": "./node_modules/cz-conventional-changelog" 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzhibin/vue3_ts_cms/e0ca05268a6c7f797c05f5ac99af7e457a86b80e/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/page/run-time/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #Clock - JavaScript 6 | 7 | 8 | 9 | 10 |
11 |

时钟已停止。

关闭 12 |
13 |
14 |

时钟现在是实时的。

关闭 15 |
16 |
17 |
18 |

暂停

19 |

开始

20 |
21 |
22 |
23 |

00

24 |
25 |
26 |
27 |

00

28 |
29 |
30 |
31 |

00

32 |
33 |
34 |
35 |
36 |
37 |
38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /public/page/run-time/script.js: -------------------------------------------------------------------------------- 1 | console.clear(); 2 | 3 | const hour = document.getElementById("hour"); 4 | const minute = document.getElementById("minute"); 5 | const second = document.getElementById("second"); 6 | const progress = document.querySelector(".progress-bar"); 7 | const pause = document.getElementById("pause"); 8 | const reset = document.getElementById("reset"); 9 | const toasts = document.getElementsByClassName("toast"); 10 | 11 | var interval; 12 | 13 | [...toasts].forEach((toast) => { 14 | toast.addEventListener("click", hideToast); 15 | }); 16 | 17 | function hideToast(e) { 18 | const target = e.target; 19 | 20 | if (target.tagName.toUpperCase() === "SPAN") { 21 | target.parentNode.classList.remove("show"); 22 | } 23 | } 24 | 25 | function getCurrentTime() { 26 | const d = new Date(); 27 | let h = d.getHours(); 28 | let min = d.getMinutes(); 29 | let sec = d.getSeconds(); 30 | 31 | h = h < 10 ? "0" + h : h; 32 | min = min < 10 ? "0" + min : min; 33 | sec = sec < 10 ? "0" + sec : sec; 34 | 35 | hour.textContent = h; 36 | minute.textContent = min; 37 | second.textContent = sec; 38 | 39 | progress.style.width = (+sec / 60) * 100 + "%"; 40 | } 41 | 42 | function clearClass(className) { 43 | for (let i = 0; i < toasts.length; i++) { 44 | toasts[i].classList.remove(className); 45 | } 46 | } 47 | 48 | pause.addEventListener("click", () => { 49 | clearInterval(interval); 50 | clearClass("show"); 51 | document.querySelector('div[data-type="pause"]').classList.add("show"); 52 | }); 53 | 54 | reset.addEventListener("click", () => { 55 | interval = setInterval(getCurrentTime, 1000); 56 | clearClass("show"); 57 | document.querySelector('div[data-type="live"]').classList.add("show"); 58 | }); 59 | 60 | interval = setInterval(getCurrentTime, 1000); 61 | -------------------------------------------------------------------------------- /public/page/run-time/style.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;900&display=swap"); 2 | *{margin:0;padding:0;list-style-type:none;} 3 | a,img{border:0;} 4 | 5 | :root { 6 | --purple-dark: #5F546E; 7 | --purple-light: #827593; 8 | --gray-light: #E5E3E8; 9 | --gray-dark: #A5A2A9; 10 | --light: #fcf8fb; 11 | --transition: all 150ms cubic-bezier(.46,1.13,.67,.87); 12 | } 13 | 14 | .clock-container { 15 | width: 405px; 16 | height: 150px; 17 | display: flex; 18 | align-items: center; 19 | justify-content: space-between; 20 | padding: 35px 50px; 21 | background-color: var(--purple-dark); 22 | position: absolute; 23 | left: 50%; 24 | top: 50%; 25 | transform: translate(-50%, -50%); 26 | box-shadow: 0 15px 40px -10px rgba(0, 0, 0, 0.825); 27 | } 28 | .clock-container span { 29 | text-transform: uppercase; 30 | font-size: 10px; 31 | text-align: right; 32 | display: block; 33 | } 34 | .clock-container p { 35 | font-size: 60px; 36 | color: var(--light); 37 | font-weight: 100; 38 | } 39 | .clock-container p:first-letter { 40 | letter-spacing: 5px; 41 | } 42 | 43 | .container { 44 | width: 560px; 45 | height: 320px; 46 | display: block; 47 | box-shadow: 10px 10px 40px rgba(0, 0, 0, 0.215), -5px -5px 25px rgba(0, 0, 0, 0.125); 48 | background-color: var(--gray-light); 49 | position: relative; 50 | } 51 | .container .top { 52 | width: 215px; 53 | margin: 0 auto; 54 | display: flex; 55 | justify-content: space-between; 56 | margin-top: 40px; 57 | } 58 | .container .top p { 59 | text-transform: uppercase; 60 | font-size: 12px; 61 | font-weight: 900; 62 | color: var(--purple-dark); 63 | letter-spacing: .5px; 64 | cursor: pointer; 65 | } 66 | .container .bottom { 67 | height: 7px; 68 | width: 100%; 69 | position: absolute; 70 | bottom: 0; 71 | background-color: #aaa4b2; 72 | } 73 | .container .bottom .progress-bar { 74 | width: 240px; 75 | height: 100%; 76 | position: absolute; 77 | left: 0; 78 | bottom: 0; 79 | z-index: 9; 80 | background-color: #615770; 81 | transition: var(--transition); 82 | } 83 | 84 | .colon { 85 | --size: 3px; 86 | width: var(--size); 87 | height: 15px; 88 | position: relative; 89 | margin-left: 10px; 90 | margin-right: 10px; 91 | } 92 | .colon::before { 93 | content: ''; 94 | width: 100%; 95 | height: var(--size); 96 | background-color: #9892a3; 97 | position: absolute; 98 | top: 0; 99 | left: 0; 100 | border-radius: 50%; 101 | } 102 | .colon::after { 103 | content: ''; 104 | width: 100%; 105 | height: var(--size); 106 | background-color: #9892a3; 107 | position: absolute; 108 | bottom: 0; 109 | left: 0; 110 | border-radius: 50%; 111 | } 112 | 113 | .toast { 114 | width: 405px; 115 | color: var(--light); 116 | padding: 15px 24px; 117 | background-color: var(--purple-dark); 118 | position: absolute; 119 | bottom: -50px; 120 | left: 50%; 121 | transform: translateX(-50%); 122 | display: flex; 123 | justify-content: space-between; 124 | transition: var(--transition); 125 | z-index: 99; 126 | } 127 | .toast p { 128 | font-weight: 400; 129 | font-size: 18px; 130 | } 131 | .toast p:first-letter { 132 | text-transform: uppercase; 133 | } 134 | .toast.show { 135 | bottom: 50px; 136 | } 137 | .toast span { 138 | align-self: center; 139 | font-weight: 500; 140 | cursor: pointer; 141 | } 142 | 143 | *, 144 | *::before, 145 | *::after { 146 | box-sizing: border-box; 147 | } 148 | 149 | body { 150 | width: 100%; 151 | height: 100vh; 152 | padding: 0; 153 | margin: 0; 154 | overflow: hidden; 155 | color: var(--purple-light); 156 | background-color: var(--purple-light); 157 | display: flex; 158 | align-items: center; 159 | justify-content: center; 160 | font-family: 'Roboto', sans-serif; 161 | font-size: 16px; 162 | font-weight: 400; 163 | line-height: 1.15; 164 | position: relative; 165 | } -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/assets/css/base.less: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #app { 4 | width: 100%; 5 | height: 100%; 6 | } 7 | body { 8 | zoom: 0.85; 9 | } 10 | i { 11 | font-style: normal; 12 | } 13 | -------------------------------------------------------------------------------- /src/assets/css/index.less: -------------------------------------------------------------------------------- 1 | @import url("./base.less"); 2 | @import url("//at.alicdn.com/t/font_2774454_0rg8locvk8rg.css"); 3 | -------------------------------------------------------------------------------- /src/assets/images/background_img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzhibin/vue3_ts_cms/e0ca05268a6c7f797c05f5ac99af7e457a86b80e/src/assets/images/background_img.jpg -------------------------------------------------------------------------------- /src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzhibin/vue3_ts_cms/e0ca05268a6c7f797c05f5ac99af7e457a86b80e/src/assets/images/logo.png -------------------------------------------------------------------------------- /src/assets/images/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzhibin/vue3_ts_cms/e0ca05268a6c7f797c05f5ac99af7e457a86b80e/src/assets/images/qq.png -------------------------------------------------------------------------------- /src/assets/images/qq_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzhibin/vue3_ts_cms/e0ca05268a6c7f797c05f5ac99af7e457a86b80e/src/assets/images/qq_logo.png -------------------------------------------------------------------------------- /src/assets/images/weichat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzhibin/vue3_ts_cms/e0ca05268a6c7f797c05f5ac99af7e457a86b80e/src/assets/images/weichat.png -------------------------------------------------------------------------------- /src/assets/images/weichat_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fuzhibin/vue3_ts_cms/e0ca05268a6c7f797c05f5ac99af7e457a86b80e/src/assets/images/weichat_logo.jpg -------------------------------------------------------------------------------- /src/common-ui/breadcrumb/index.ts: -------------------------------------------------------------------------------- 1 | import BreadCrumb from "./src/BreadCrumb.vue"; 2 | export * from "./types/types"; 3 | export default BreadCrumb; 4 | -------------------------------------------------------------------------------- /src/common-ui/breadcrumb/src/BreadCrumb.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/common-ui/breadcrumb/types/types.ts: -------------------------------------------------------------------------------- 1 | export interface BreadCrumbItemType { 2 | name: string; 3 | path: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/common-ui/msi-card/index.ts: -------------------------------------------------------------------------------- 1 | import MsiCard from "./src/MsiCard.vue"; 2 | export default MsiCard; 3 | -------------------------------------------------------------------------------- /src/common-ui/msi-card/src/MsiCard.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 30 | 31 | 43 | -------------------------------------------------------------------------------- /src/common-ui/msi-descriptions/index.ts: -------------------------------------------------------------------------------- 1 | import MsiDescriptions from "./src/MsiDescriptions.vue"; 2 | 3 | export default MsiDescriptions; 4 | -------------------------------------------------------------------------------- /src/common-ui/msi-descriptions/src/MsiDescriptions.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 37 | 38 | 44 | -------------------------------------------------------------------------------- /src/common-ui/msi-echarts/hooks/initECharts.ts: -------------------------------------------------------------------------------- 1 | import * as echarts from "echarts"; 2 | import type { EChartsOption } from "echarts"; 3 | import chinaMap from "../map/china.json"; 4 | echarts.registerMap("china", chinaMap); 5 | export default function (el: HTMLElement) { 6 | const echartsInstance = echarts.init(el); 7 | const setChartOption = function (options: EChartsOption) { 8 | echartsInstance.setOption(options); 9 | }; 10 | window.addEventListener("resize", () => { 11 | echartsInstance.resize(); 12 | }); 13 | const updateSize = () => { 14 | echartsInstance.resize(); 15 | }; 16 | return { 17 | echartsInstance, 18 | setChartOption, 19 | updateSize 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/common-ui/msi-echarts/hooks/mapCityToMap.ts: -------------------------------------------------------------------------------- 1 | import geoCoordMap from "../map/city"; 2 | 3 | export default function (data: any) { 4 | const res = []; 5 | for (let i = 0; i < data.length; i++) { 6 | const geoCoord = (geoCoordMap as any)[data[i].name]; 7 | if (geoCoord) { 8 | res.push({ 9 | name: data[i].name, 10 | value: geoCoord.concat(data[i].value) 11 | }); 12 | } 13 | } 14 | return res; 15 | } 16 | -------------------------------------------------------------------------------- /src/common-ui/msi-echarts/index.ts: -------------------------------------------------------------------------------- 1 | import MsiEcharts from "./src/MsiEcharts.vue"; 2 | 3 | export default MsiEcharts; 4 | -------------------------------------------------------------------------------- /src/common-ui/msi-echarts/map/city.ts: -------------------------------------------------------------------------------- 1 | const city = { 2 | 海门: [121.15, 31.89], 3 | 鄂尔多斯: [109.781327, 39.608266], 4 | 招远: [120.38, 37.35], 5 | 舟山: [122.207216, 29.985295], 6 | 齐齐哈尔: [123.97, 47.33], 7 | 盐城: [120.13, 33.38], 8 | 赤峰: [118.87, 42.28], 9 | 青岛: [120.33, 36.07], 10 | 乳山: [121.52, 36.89], 11 | 金昌: [102.188043, 38.520089], 12 | 泉州: [118.58, 24.93], 13 | 莱西: [120.53, 36.86], 14 | 日照: [119.46, 35.42], 15 | 胶南: [119.97, 35.88], 16 | 南通: [121.05, 32.08], 17 | 拉萨: [91.11, 29.97], 18 | 云浮: [112.02, 22.93], 19 | 梅州: [116.1, 24.55], 20 | 文登: [122.05, 37.2], 21 | 上海: [121.48, 31.22], 22 | 攀枝花: [101.718637, 26.582347], 23 | 威海: [122.1, 37.5], 24 | 承德: [117.93, 40.97], 25 | 厦门: [118.1, 24.46], 26 | 汕尾: [115.375279, 22.786211], 27 | 潮州: [116.63, 23.68], 28 | 丹东: [124.37, 40.13], 29 | 太仓: [121.1, 31.45], 30 | 曲靖: [103.79, 25.51], 31 | 烟台: [121.39, 37.52], 32 | 福州: [119.3, 26.08], 33 | 瓦房店: [121.979603, 39.627114], 34 | 即墨: [120.45, 36.38], 35 | 抚顺: [123.97, 41.97], 36 | 玉溪: [102.52, 24.35], 37 | 张家口: [114.87, 40.82], 38 | 阳泉: [113.57, 37.85], 39 | 莱州: [119.942327, 37.177017], 40 | 湖州: [120.1, 30.86], 41 | 汕头: [116.69, 23.39], 42 | 昆山: [120.95, 31.39], 43 | 宁波: [121.56, 29.86], 44 | 湛江: [110.359377, 21.270708], 45 | 揭阳: [116.35, 23.55], 46 | 荣成: [122.41, 37.16], 47 | 连云港: [119.16, 34.59], 48 | 葫芦岛: [120.836932, 40.711052], 49 | 常熟: [120.74, 31.64], 50 | 东莞: [113.75, 23.04], 51 | 河源: [114.68, 23.73], 52 | 淮安: [119.15, 33.5], 53 | 泰州: [119.9, 32.49], 54 | 南宁: [108.33, 22.84], 55 | 营口: [122.18, 40.65], 56 | 惠州: [114.4, 23.09], 57 | 江阴: [120.26, 31.91], 58 | 蓬莱: [120.75, 37.8], 59 | 韶关: [113.62, 24.84], 60 | 嘉峪关: [98.289152, 39.77313], 61 | 广州: [113.23, 23.16], 62 | 延安: [109.47, 36.6], 63 | 太原: [112.53, 37.87], 64 | 清远: [113.01, 23.7], 65 | 中山: [113.38, 22.52], 66 | 昆明: [102.73, 25.04], 67 | 寿光: [118.73, 36.86], 68 | 盘锦: [122.070714, 41.119997], 69 | 长治: [113.08, 36.18], 70 | 深圳: [114.07, 22.62], 71 | 珠海: [113.52, 22.3], 72 | 宿迁: [118.3, 33.96], 73 | 咸阳: [108.72, 34.36], 74 | 铜川: [109.11, 35.09], 75 | 平度: [119.97, 36.77], 76 | 佛山: [113.11, 23.05], 77 | 海口: [110.35, 20.02], 78 | 江门: [113.06, 22.61], 79 | 章丘: [117.53, 36.72], 80 | 肇庆: [112.44, 23.05], 81 | 大连: [121.62, 38.92], 82 | 临汾: [111.5, 36.08], 83 | 吴江: [120.63, 31.16], 84 | 石嘴山: [106.39, 39.04], 85 | 沈阳: [123.38, 41.8], 86 | 苏州: [120.62, 31.32], 87 | 茂名: [110.88, 21.68], 88 | 嘉兴: [120.76, 30.77], 89 | 长春: [125.35, 43.88], 90 | 胶州: [120.03336, 36.264622], 91 | 银川: [106.27, 38.47], 92 | 张家港: [120.555821, 31.875428], 93 | 三门峡: [111.19, 34.76], 94 | 锦州: [121.15, 41.13], 95 | 南昌: [115.89, 28.68], 96 | 柳州: [109.4, 24.33], 97 | 三亚: [109.511909, 18.252847], 98 | 自贡: [104.778442, 29.33903], 99 | 吉林: [126.57, 43.87], 100 | 阳江: [111.95, 21.85], 101 | 泸州: [105.39, 28.91], 102 | 西宁: [101.74, 36.56], 103 | 宜宾: [104.56, 29.77], 104 | 呼和浩特: [111.65, 40.82], 105 | 成都: [104.06, 30.67], 106 | 大同: [113.3, 40.12], 107 | 镇江: [119.44, 32.2], 108 | 桂林: [110.28, 25.29], 109 | 张家界: [110.479191, 29.117096], 110 | 宜兴: [119.82, 31.36], 111 | 北海: [109.12, 21.49], 112 | 西安: [108.95, 34.27], 113 | 金坛: [119.56, 31.74], 114 | 东营: [118.49, 37.46], 115 | 牡丹江: [129.58, 44.6], 116 | 遵义: [106.9, 27.7], 117 | 绍兴: [120.58, 30.01], 118 | 扬州: [119.42, 32.39], 119 | 常州: [119.95, 31.79], 120 | 潍坊: [119.1, 36.62], 121 | 重庆: [106.54, 29.59], 122 | 台州: [121.420757, 28.656386], 123 | 南京: [118.78, 32.04], 124 | 滨州: [118.03, 37.36], 125 | 贵阳: [106.71, 26.57], 126 | 无锡: [120.29, 31.59], 127 | 本溪: [123.73, 41.3], 128 | 克拉玛依: [84.77, 45.59], 129 | 渭南: [109.5, 34.52], 130 | 马鞍山: [118.48, 31.56], 131 | 宝鸡: [107.15, 34.38], 132 | 焦作: [113.21, 35.24], 133 | 句容: [119.16, 31.95], 134 | 北京: [116.46, 39.92], 135 | 徐州: [117.2, 34.26], 136 | 衡水: [115.72, 37.72], 137 | 包头: [110, 40.58], 138 | 绵阳: [104.73, 31.48], 139 | 乌鲁木齐: [87.68, 43.77], 140 | 枣庄: [117.57, 34.86], 141 | 杭州: [120.19, 30.26], 142 | 淄博: [118.05, 36.78], 143 | 鞍山: [122.85, 41.12], 144 | 溧阳: [119.48, 31.43], 145 | 库尔勒: [86.06, 41.68], 146 | 安阳: [114.35, 36.1], 147 | 开封: [114.35, 34.79], 148 | 济南: [117, 36.65], 149 | 德阳: [104.37, 31.13], 150 | 温州: [120.65, 28.01], 151 | 九江: [115.97, 29.71], 152 | 邯郸: [114.47, 36.6], 153 | 临安: [119.72, 30.23], 154 | 兰州: [103.73, 36.03], 155 | 沧州: [116.83, 38.33], 156 | 临沂: [118.35, 35.05], 157 | 南充: [106.110698, 30.837793], 158 | 天津: [117.2, 39.13], 159 | 富阳: [119.95, 30.07], 160 | 泰安: [117.13, 36.18], 161 | 诸暨: [120.23, 29.71], 162 | 郑州: [113.65, 34.76], 163 | 哈尔滨: [126.63, 45.75], 164 | 聊城: [115.97, 36.45], 165 | 芜湖: [118.38, 31.33], 166 | 唐山: [118.02, 39.63], 167 | 平顶山: [113.29, 33.75], 168 | 邢台: [114.48, 37.05], 169 | 德州: [116.29, 37.45], 170 | 济宁: [116.59, 35.38], 171 | 荆州: [112.239741, 30.335165], 172 | 宜昌: [111.3, 30.7], 173 | 义乌: [120.06, 29.32], 174 | 丽水: [119.92, 28.45], 175 | 洛阳: [112.44, 34.7], 176 | 秦皇岛: [119.57, 39.95], 177 | 株洲: [113.16, 27.83], 178 | 石家庄: [114.48, 38.03], 179 | 莱芜: [117.67, 36.19], 180 | 常德: [111.69, 29.05], 181 | 保定: [115.48, 38.85], 182 | 湘潭: [112.91, 27.87], 183 | 金华: [119.64, 29.12], 184 | 岳阳: [113.09, 29.37], 185 | 长沙: [113, 28.21], 186 | 衢州: [118.88, 28.97], 187 | 廊坊: [116.7, 39.53], 188 | 菏泽: [115.480656, 35.23375], 189 | 合肥: [117.27, 31.86], 190 | 武汉: [114.31, 30.52], 191 | 大庆: [125.03, 46.58] 192 | }; 193 | 194 | export default city; 195 | -------------------------------------------------------------------------------- /src/common-ui/msi-echarts/src/MsiEcharts.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/common-ui/msi-editor/index.ts: -------------------------------------------------------------------------------- 1 | import MsiEditor from "./src/MsiEditor.vue"; 2 | export default MsiEditor; 3 | -------------------------------------------------------------------------------- /src/common-ui/msi-editor/src/MsiEditor.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 72 | 73 | 92 | -------------------------------------------------------------------------------- /src/common-ui/msi-form/index.ts: -------------------------------------------------------------------------------- 1 | import MsiForm from "./src/MsiForm.vue"; 2 | 3 | export * from "./types/types"; 4 | export default MsiForm; 5 | -------------------------------------------------------------------------------- /src/common-ui/msi-form/src/MsiForm.vue: -------------------------------------------------------------------------------- 1 | 65 | 66 | 118 | 119 | 144 | -------------------------------------------------------------------------------- /src/common-ui/msi-form/types/types.ts: -------------------------------------------------------------------------------- 1 | type InputType = "input" | "select" | "password" | "datapicker" | "upload"; 2 | 3 | export interface IFormItemType { 4 | field: string; 5 | type: InputType; 6 | label: string; 7 | rules?: any[]; 8 | placeholder?: string; 9 | options?: any[]; 10 | otherOptions?: any; 11 | isHidden?: boolean; 12 | } 13 | 14 | interface colLayoutType { 15 | span?: number; 16 | xs?: number; 17 | sm?: number; 18 | md?: number; 19 | lg?: number; 20 | xl?: number; 21 | } 22 | export interface IForm { 23 | formItem: IFormItemType[]; 24 | labelWidth?: string; 25 | itemStyle?: any; 26 | colLayout?: colLayoutType; 27 | } 28 | -------------------------------------------------------------------------------- /src/common-ui/msi-tabel/index.ts: -------------------------------------------------------------------------------- 1 | import MsiTabel from "./src/MsiTabel.vue"; 2 | export * from "./types/types"; 3 | export default MsiTabel; 4 | -------------------------------------------------------------------------------- /src/common-ui/msi-tabel/src/MsiTabel.vue: -------------------------------------------------------------------------------- 1 | 64 | 65 | 124 | 125 | 139 | -------------------------------------------------------------------------------- /src/common-ui/msi-tabel/types/types.ts: -------------------------------------------------------------------------------- 1 | export interface ITabelTitle { 2 | prop: string; 3 | label: string; 4 | minWidth?: string; 5 | slotName?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/common-ui/msi-upload/index.ts: -------------------------------------------------------------------------------- 1 | import MsiUpload from "./src/MsiUpload.vue"; 2 | 3 | export default MsiUpload; 4 | -------------------------------------------------------------------------------- /src/common-ui/msi-upload/src/MsiUpload.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/components/nav-header/index.ts: -------------------------------------------------------------------------------- 1 | import NavHeader from "./src/NavHeader.vue"; 2 | 3 | export default NavHeader; 4 | -------------------------------------------------------------------------------- /src/components/nav-header/src/NavHeader.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 113 | 114 | 154 | -------------------------------------------------------------------------------- /src/components/nav-header/src/cpn/NavDialog.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 46 | 47 | 68 | -------------------------------------------------------------------------------- /src/components/nav-menu/index.ts: -------------------------------------------------------------------------------- 1 | import NavMenu from "./src/NavMenu.vue"; 2 | export default NavMenu; 3 | -------------------------------------------------------------------------------- /src/components/nav-menu/src/NavMenu.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 75 | 76 | 135 | -------------------------------------------------------------------------------- /src/components/page-dialog/index.ts: -------------------------------------------------------------------------------- 1 | import PageDialog from "./src/PageDialog.vue"; 2 | 3 | export * from "./types/types"; 4 | export default PageDialog; 5 | -------------------------------------------------------------------------------- /src/components/page-dialog/src/PageDialog.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 90 | 91 | 96 | -------------------------------------------------------------------------------- /src/components/page-dialog/types/types.ts: -------------------------------------------------------------------------------- 1 | import { IForm } from "@/common-ui/msi-form"; 2 | 3 | export interface IDialog extends IForm { 4 | title?: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/components/page-echart/index.ts: -------------------------------------------------------------------------------- 1 | import PageBarChart from "./src/PageBarChart.vue"; 2 | import PagePicChart from "./src/PagePicChart.vue"; 3 | import PageRoseChart from "./src/PageRoseChart.vue"; 4 | import PageLineChart from "./src/PageLineChart.vue"; 5 | import PageChinaChart from "./src/PageChinaChart.vue"; 6 | import PagePicLableChart from "./src/PagePicLableChart.vue"; 7 | export { 8 | PageBarChart, 9 | PagePicChart, 10 | PageRoseChart, 11 | PageLineChart, 12 | PageChinaChart, 13 | PagePicLableChart 14 | }; 15 | -------------------------------------------------------------------------------- /src/components/page-echart/src/PageBarChart.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/components/page-echart/src/PageChinaChart.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/components/page-echart/src/PageLineChart.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/components/page-echart/src/PagePicChart.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/components/page-echart/src/PagePicLableChart.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 73 | 74 | 80 | -------------------------------------------------------------------------------- /src/components/page-echart/src/PageRoseChart.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /src/components/page-search/index.ts: -------------------------------------------------------------------------------- 1 | import PageSearch from "./src/PageSearch.vue"; 2 | 3 | export default PageSearch; 4 | -------------------------------------------------------------------------------- /src/components/page-search/src/PageSearch.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/components/page-tabel/index.ts: -------------------------------------------------------------------------------- 1 | import PageTabel from "./src/PageTabel.vue"; 2 | 3 | export default PageTabel; 4 | -------------------------------------------------------------------------------- /src/components/page-tabel/src/PageTabel.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 172 | 173 | 180 | -------------------------------------------------------------------------------- /src/global/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from "vue"; 2 | import registerElement from "./registerElement"; 3 | import registerGlobal from "./registerGlobal"; 4 | export default function (app: App): void { 5 | app.use(registerElement); 6 | app.use(registerGlobal); 7 | } 8 | -------------------------------------------------------------------------------- /src/global/registerElement.ts: -------------------------------------------------------------------------------- 1 | import type { App } from "vue"; 2 | 3 | import { 4 | ElAside, 5 | ElButton, 6 | ElCheckbox, 7 | ElCol, 8 | ElContainer, 9 | ElDropdown, 10 | ElDropdownItem, 11 | ElDropdownMenu, 12 | ElForm, 13 | ElFormItem, 14 | ElHeader, 15 | ElInput, 16 | ElLink, 17 | ElMain, 18 | ElMenu, 19 | ElMenuItem, 20 | ElSubmenu, 21 | ElTabPane, 22 | ElTabs, 23 | ElRow, 24 | ElSelect, 25 | ElDatePicker, 26 | ElOption, 27 | ElBreadcrumbItem, 28 | ElBreadcrumb, 29 | ElTable, 30 | ElTableColumn, 31 | ElPagination, 32 | ElImage, 33 | ElDialog, 34 | ElTree, 35 | ElAvatar, 36 | ElUpload, 37 | ElCard, 38 | ElTooltip, 39 | ElCollapse, 40 | ElCollapseItem, 41 | ElDescriptions, 42 | ElDescriptionsItem, 43 | ElTag 44 | } from "element-plus"; 45 | 46 | import "element-plus/lib/theme-chalk/base.css"; 47 | 48 | const components = [ 49 | ElButton, 50 | ElTabs, 51 | ElTabPane, 52 | ElForm, 53 | ElFormItem, 54 | ElInput, 55 | ElCheckbox, 56 | ElLink, 57 | ElContainer, 58 | ElAside, 59 | ElHeader, 60 | ElMain, 61 | ElMenu, 62 | ElSubmenu, 63 | ElCol, 64 | ElMenuItem, 65 | ElDropdown, 66 | ElDropdownMenu, 67 | ElDropdownItem, 68 | ElRow, 69 | ElSelect, 70 | ElOption, 71 | ElDatePicker, 72 | ElBreadcrumb, 73 | ElBreadcrumbItem, 74 | ElTable, 75 | ElTableColumn, 76 | ElPagination, 77 | ElImage, 78 | ElDialog, 79 | ElTree, 80 | ElAvatar, 81 | ElUpload, 82 | ElCard, 83 | ElTooltip, 84 | ElCollapse, 85 | ElCollapseItem, 86 | ElDescriptions, 87 | ElDescriptionsItem, 88 | ElTag 89 | ]; 90 | 91 | export default function (app: App): void { 92 | for (const cpn of components) { 93 | app.component(cpn.name, cpn); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/global/registerGlobal.ts: -------------------------------------------------------------------------------- 1 | import { App } from "vue"; 2 | 3 | import { formatUtcToData } from "@/utils/formate"; 4 | export default function registerDirectives(app: App): void { 5 | app.config.globalProperties.$formatUTC = function ( 6 | data: string, 7 | formatString = "YYYY-MM-DD HH:mm:ss" 8 | ) { 9 | return formatUtcToData(data, formatString); 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/hooks/countAction.ts: -------------------------------------------------------------------------------- 1 | import { CountUp } from "countup.js"; 2 | const demo = new CountUp("myTargetElement", 6884); 3 | if (!demo.error) { 4 | demo.start(); 5 | } else { 6 | console.error(demo.error); 7 | } 8 | -------------------------------------------------------------------------------- /src/hooks/pageLinkage.ts: -------------------------------------------------------------------------------- 1 | import { ref } from "vue"; 2 | import PageTabel from "@/components/page-tabel"; 3 | import PageDialog from "@/components/page-dialog"; 4 | 5 | type callback = (data?: any) => void; 6 | 7 | export function searchLinkage() { 8 | const pageTabelRef = ref>(); 9 | const resetBtnClic = () => { 10 | pageTabelRef.value?.getDataList(); 11 | }; 12 | const searchBtnClic = (queryInfo: any) => { 13 | console.log(queryInfo); 14 | 15 | pageTabelRef.value?.getDataList(queryInfo); 16 | }; 17 | return [pageTabelRef, resetBtnClic, searchBtnClic]; 18 | } 19 | 20 | export function operationLinkage( 21 | editCallback?: callback, 22 | createCallBack?: callback 23 | ) { 24 | const pageDialogRef = ref>(); 25 | const defaultValue = ref({}); 26 | const handleCreateBtnClic = () => { 27 | defaultValue.value = {}; 28 | if (pageDialogRef.value) { 29 | pageDialogRef.value.centerDialogVisible = true; 30 | } 31 | createCallBack && createCallBack(); 32 | }; 33 | 34 | const handleEditorBtnClic = (payload: any) => { 35 | defaultValue.value = payload; 36 | 37 | if (pageDialogRef.value) { 38 | pageDialogRef.value.centerDialogVisible = true; 39 | } 40 | 41 | editCallback && editCallback({ ...payload }); 42 | }; 43 | return [ 44 | pageDialogRef, 45 | defaultValue, 46 | handleEditorBtnClic, 47 | handleCreateBtnClic 48 | ]; 49 | } 50 | -------------------------------------------------------------------------------- /src/hooks/permission.ts: -------------------------------------------------------------------------------- 1 | import { useStore } from "@/store"; 2 | export function usePermission(pageName: string, actions: string) { 3 | const store = useStore(); 4 | const permissionList = store.state.login.permissionList; 5 | const permission = `system:${pageName}:${actions}`; 6 | return !!permissionList.find((item) => item === permission); 7 | } 8 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | 4 | import router from "./router"; 5 | import store from "./store"; 6 | import { uploadCache } from "@/store"; 7 | import "normalize.css"; 8 | 9 | import "./assets/css/index.less"; 10 | import register from "./global"; 11 | import localCache from "@/utils/cache"; 12 | localCache.setCache("name", "nanxing"); 13 | localCache.setCache("password", "123456"); 14 | const app = createApp(App); 15 | app.use(register); 16 | app.use(store); 17 | uploadCache(); 18 | app.use(router); 19 | 20 | app.mount("#app"); 21 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from "vue-router"; 2 | import type { RouteRecordRaw } from "vue-router"; 3 | import localCache from "@/utils/cache"; 4 | 5 | import { firstMenu } from "@/utils/menuToRoute"; 6 | 7 | const routes: RouteRecordRaw[] = [ 8 | { 9 | path: "/", 10 | redirect: "/login" 11 | }, 12 | { 13 | path: "/main", 14 | name: "main", 15 | component: () => import("@/views/main/Main.vue") 16 | }, 17 | { 18 | path: "/login", 19 | component: () => import("@/views/login/Login.vue") 20 | }, 21 | { 22 | path: "/:pathMatch(.*)*", 23 | component: () => import("@/views/not-found/NotFound.vue") 24 | } 25 | ]; 26 | 27 | const router = createRouter({ 28 | routes, 29 | history: createWebHashHistory() 30 | }); 31 | router.beforeEach((to, from) => { 32 | if (to.path !== "/login") { 33 | if (!localCache.getCache("token")) { 34 | return "/login"; 35 | } 36 | } 37 | if (to.path === "/main") { 38 | return firstMenu.url; 39 | } 40 | }); 41 | export default router; 42 | -------------------------------------------------------------------------------- /src/router/main/analysis/dashboard/dashboard.ts: -------------------------------------------------------------------------------- 1 | const dashboard = () => import("@/views/main/analysis/dashboard/dashboard.vue"); 2 | export default { 3 | path: "/main/analysis/dashboard", 4 | name: "dashboard", 5 | component: dashboard, 6 | children: [] 7 | }; 8 | -------------------------------------------------------------------------------- /src/router/main/analysis/overview/overview.ts: -------------------------------------------------------------------------------- 1 | const overview = () => import("@/views/main/analysis/overview/overview.vue"); 2 | export default { 3 | path: "/main/analysis/overview", 4 | name: "overview", 5 | component: overview, 6 | children: [] 7 | }; 8 | -------------------------------------------------------------------------------- /src/router/main/product/category/category.ts: -------------------------------------------------------------------------------- 1 | const category = () => import("@/views/main/product/category/category.vue"); 2 | export default { 3 | path: "/main/product/category", 4 | name: "category", 5 | component: category, 6 | children: [] 7 | }; 8 | -------------------------------------------------------------------------------- /src/router/main/product/goods/goods.ts: -------------------------------------------------------------------------------- 1 | const goods = () => import("@/views/main/product/goods/goods.vue"); 2 | export default { 3 | path: "/main/product/goods", 4 | name: "goods", 5 | component: goods, 6 | children: [] 7 | }; 8 | -------------------------------------------------------------------------------- /src/router/main/story/chat/chat.ts: -------------------------------------------------------------------------------- 1 | const chat = () => import("@/views/main/story/chat/chat.vue"); 2 | export default { 3 | path: "/main/story/chat", 4 | name: "chat", 5 | component: chat, 6 | children: [] 7 | }; 8 | -------------------------------------------------------------------------------- /src/router/main/story/list/list.ts: -------------------------------------------------------------------------------- 1 | const list = () => import("@/views/main/story/list/list.vue"); 2 | export default { 3 | path: "/main/story/list", 4 | name: "list", 5 | component: list, 6 | children: [] 7 | }; 8 | -------------------------------------------------------------------------------- /src/router/main/system/department/department.ts: -------------------------------------------------------------------------------- 1 | const department = () => 2 | import("@/views/main/system/department/department.vue"); 3 | export default { 4 | path: "/main/system/department", 5 | name: "department", 6 | component: department, 7 | children: [] 8 | }; 9 | -------------------------------------------------------------------------------- /src/router/main/system/menu/menu.ts: -------------------------------------------------------------------------------- 1 | const menu = () => import("@/views/main/system/menu/menu.vue"); 2 | export default { 3 | path: "/main/system/menu", 4 | name: "menu", 5 | component: menu, 6 | children: [] 7 | }; 8 | -------------------------------------------------------------------------------- /src/router/main/system/role/role.ts: -------------------------------------------------------------------------------- 1 | const role = () => import("@/views/main/system/role/role.vue"); 2 | export default { 3 | path: "/main/system/role", 4 | name: "role", 5 | component: role, 6 | children: [] 7 | }; 8 | -------------------------------------------------------------------------------- /src/router/main/system/user/user.ts: -------------------------------------------------------------------------------- 1 | const user = () => import("@/views/main/system/user/user.vue"); 2 | export default { 3 | path: "/main/system/user", 4 | name: "user", 5 | component: user, 6 | children: [] 7 | }; 8 | -------------------------------------------------------------------------------- /src/service/index.ts: -------------------------------------------------------------------------------- 1 | import MsiRequest from "./request"; 2 | 3 | import localCache from "@/utils/cache"; 4 | 5 | const msiRequest = new MsiRequest({ 6 | baseURL: process.env.VUE_APP_BASE_URL, 7 | timeout: Number(process.env.VUE_APP_TIME_OUT), 8 | interceptors: { 9 | requestInterceptor(config) { 10 | const token = localCache.getCache("token"); 11 | if (token) { 12 | config.headers.Authorization = `Bearer ${token}`; 13 | } 14 | return config; 15 | }, 16 | requestInterceptorCatch(error) { 17 | return error; 18 | }, 19 | responseInterceptor(result) { 20 | return result; 21 | }, 22 | responseInterceptorCatch(error) { 23 | return error; 24 | } 25 | } 26 | }); 27 | console.log(process.env.VUE_APP_BASE_URL); 28 | 29 | export { msiRequest }; 30 | -------------------------------------------------------------------------------- /src/service/login/index.ts: -------------------------------------------------------------------------------- 1 | import { msiRequest } from "../index"; 2 | 3 | import { ResultType } from "../types"; 4 | import { AccountLoginType, AccountLoginResultType } from "./types"; 5 | 6 | enum AccountLoginAPI { 7 | ACCOUNT_LOGIN = "/login", 8 | USER_INFO = "/users/", 9 | USER_MENU = "role/" 10 | } 11 | 12 | export function accountLoginRequest(account: AccountLoginType) { 13 | return msiRequest.post>({ 14 | url: AccountLoginAPI.ACCOUNT_LOGIN, 15 | data: { 16 | ...account, 17 | name: "coderwhy" 18 | } 19 | }); 20 | } 21 | 22 | export function userInfoRequest(id: number) { 23 | return msiRequest.get({ 24 | url: AccountLoginAPI.USER_INFO + id 25 | }); 26 | } 27 | 28 | export function userMenuRequest(id: number) { 29 | return msiRequest.get({ 30 | url: AccountLoginAPI.USER_MENU + id + "/menu" 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /src/service/login/types.ts: -------------------------------------------------------------------------------- 1 | export interface AccountLoginType { 2 | name: string; 3 | password: string; 4 | } 5 | 6 | export interface AccountLoginResultType { 7 | id: number; 8 | name: string; 9 | token: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/service/main/analysis/index.ts: -------------------------------------------------------------------------------- 1 | import { msiRequest } from "../../index"; 2 | import { ResultType } from "../../types"; 3 | 4 | enum ChartsUrl { 5 | GOODS_CATEGORY_COUNT = "/goods/category/count", 6 | GOODS_CATEGORY_SALE = "/goods/category/sale", 7 | GOODS_CATEGORY_FAVOR = "/goods/category/favor", 8 | GOODS_ADDRESS_SALE = "/goods/address/sale", 9 | GOODS_AMOUNT_LIST = "/goods/amount/list", 10 | GOODS_SALE_TOP10 = "/goods/sale/top10" 11 | } 12 | 13 | export function getGoodsCategoryCount() { 14 | return msiRequest.get({ 15 | url: ChartsUrl.GOODS_CATEGORY_COUNT 16 | }); 17 | } 18 | export function getGoodsCategorySale() { 19 | return msiRequest.get({ 20 | url: ChartsUrl.GOODS_CATEGORY_SALE 21 | }); 22 | } 23 | export function getGoodsCategoryFavor() { 24 | return msiRequest.get({ 25 | url: ChartsUrl.GOODS_CATEGORY_FAVOR 26 | }); 27 | } 28 | export function getGoodsAddressSale() { 29 | return msiRequest.get({ 30 | url: ChartsUrl.GOODS_ADDRESS_SALE 31 | }); 32 | } 33 | 34 | export function getGoodsAmountList() { 35 | return msiRequest.get({ 36 | url: ChartsUrl.GOODS_AMOUNT_LIST 37 | }); 38 | } 39 | 40 | export function getGoodsSaleTop10() { 41 | return msiRequest.get({ 42 | url: ChartsUrl.GOODS_SALE_TOP10 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /src/service/main/story/index.ts: -------------------------------------------------------------------------------- 1 | import { msiRequest } from "../../index"; 2 | import { ResultType } from "../../types"; 3 | interface IArticlesDataType { 4 | title: string; 5 | cotent: string; 6 | } 7 | export function publishArticlesData(articlesData: IArticlesDataType) { 8 | return msiRequest.post({ 9 | url: "/story", 10 | data: articlesData 11 | }); 12 | } 13 | export function getArticlesData(payload: any) { 14 | return msiRequest.post({ 15 | url: "/story/list", 16 | data: payload 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /src/service/main/system/index.ts: -------------------------------------------------------------------------------- 1 | import { msiRequest } from "../../index"; 2 | import { ResultType } from "../../types"; 3 | export function getDataList(url: string, query: any = {}) { 4 | return msiRequest.post({ 5 | url, 6 | data: query 7 | }); 8 | } 9 | 10 | export function deleteDataList(url: string) { 11 | return msiRequest.delete({ 12 | url 13 | }); 14 | } 15 | 16 | export function editorPageData(url: string, query: any) { 17 | return msiRequest.patch({ 18 | url, 19 | data: query 20 | }); 21 | } 22 | 23 | export function createPageData(url: string, query: any) { 24 | return msiRequest.post({ 25 | url, 26 | data: query 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /src/service/request/index.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import type { AxiosInstance } from "axios"; 3 | 4 | import { ElLoading } from "element-plus"; 5 | 6 | import { MsiRequestConfig } from "./type"; 7 | import { ILoadingInstance } from "element-plus/lib/el-loading/src/loading.type"; 8 | 9 | const SHOW_LOADING = true; 10 | 11 | class MsiRequest { 12 | instance: AxiosInstance; 13 | elLoading?: ILoadingInstance; 14 | isShowLoading: boolean = SHOW_LOADING; 15 | constructor(config: MsiRequestConfig) { 16 | this.instance = axios.create(config); 17 | this.isShowLoading = config.isShowLoading ?? SHOW_LOADING; 18 | // 实例拦截器 19 | this.instance.interceptors.request.use( 20 | config.interceptors?.requestInterceptor, 21 | config.interceptors?.requestInterceptorCatch 22 | ); 23 | this.instance.interceptors.response.use( 24 | config.interceptors?.responseInterceptor, 25 | config.interceptors?.responseInterceptorCatch 26 | ); 27 | // 全局拦截器 28 | this.instance.interceptors.request.use( 29 | (config) => { 30 | if (this.isShowLoading === true) { 31 | this.elLoading = ElLoading.service({ 32 | text: "正在加载中,请稍后....", 33 | background: "rgba(0,0,0,.6)" 34 | }); 35 | } 36 | 37 | return config; 38 | }, 39 | (error) => { 40 | return error; 41 | } 42 | ); 43 | this.instance.interceptors.response.use( 44 | (result) => { 45 | this.elLoading?.close(); 46 | return result.data; 47 | }, 48 | (error) => { 49 | return error; 50 | } 51 | ); 52 | } 53 | 54 | request(config: MsiRequestConfig): Promise { 55 | if (config.interceptors?.requestInterceptor) { 56 | this.isShowLoading = config.isShowLoading ?? SHOW_LOADING; 57 | config = config.interceptors.requestInterceptor(config); 58 | } 59 | 60 | return this.instance 61 | .request(config) 62 | .then((res) => { 63 | if (config.interceptors?.responseInterceptor) { 64 | res = config.interceptors.responseInterceptor(res); 65 | } 66 | this.isShowLoading = SHOW_LOADING; 67 | return res; 68 | }) 69 | .catch((err) => { 70 | this.isShowLoading = SHOW_LOADING; 71 | return err; 72 | }); 73 | } 74 | 75 | get(config: MsiRequestConfig): Promise { 76 | return this.request({ 77 | ...config, 78 | method: "GET" 79 | }); 80 | } 81 | post(config: MsiRequestConfig): Promise { 82 | return this.request({ 83 | ...config, 84 | method: "POST" 85 | }); 86 | } 87 | delete(config: MsiRequestConfig): Promise { 88 | return this.request({ 89 | ...config, 90 | method: "DELETE" 91 | }); 92 | } 93 | patch(config: MsiRequestConfig): Promise { 94 | return this.request({ 95 | ...config, 96 | method: "PATCH" 97 | }); 98 | } 99 | } 100 | 101 | export default MsiRequest; 102 | -------------------------------------------------------------------------------- /src/service/request/type.ts: -------------------------------------------------------------------------------- 1 | import { AxiosRequestConfig, AxiosResponse } from "axios"; 2 | 3 | export interface MsiInterceptors { 4 | requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig; 5 | requestInterceptorCatch?: (error: any) => any; 6 | responseInterceptor?: (result: T) => T; 7 | responseInterceptorCatch?: (error: any) => any; 8 | } 9 | 10 | export interface MsiRequestConfig 11 | extends AxiosRequestConfig { 12 | interceptors?: MsiInterceptors; 13 | isShowLoading?: boolean; 14 | } 15 | -------------------------------------------------------------------------------- /src/service/types.ts: -------------------------------------------------------------------------------- 1 | export interface ResultType { 2 | code: number; 3 | data: T; 4 | } 5 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module "*.vue" { 3 | import type { DefineComponent } from "vue"; 4 | const component: DefineComponent<{}, {}, any>; 5 | export default component; 6 | } 7 | 8 | declare module "kuan-vue-flip-clock"; 9 | declare module "*.json"; 10 | declare module "*.png"; 11 | declare module "*.jpg"; 12 | -------------------------------------------------------------------------------- /src/store/analysis/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "vuex"; 2 | import type { AnalysisStateType } from "./types"; 3 | import type { RootStateType } from "../types"; 4 | 5 | import { 6 | getGoodsAddressSale, 7 | getGoodsCategoryCount, 8 | getGoodsCategoryFavor, 9 | getGoodsCategorySale, 10 | getGoodsAmountList, 11 | getGoodsSaleTop10 12 | } from "@/service/main/analysis"; 13 | const analysisModule: Module = { 14 | namespaced: true, 15 | state() { 16 | return { 17 | goodsAddressSale: [], 18 | goodsCategoryCount: [], 19 | goodsCategoryFavor: [], 20 | goodsCategorySale: [], 21 | goodsAmountList: [], 22 | goodsSaleTop10: [] 23 | }; 24 | }, 25 | getters: {}, 26 | mutations: { 27 | changeGoodsCategoryCount(state, list: any[]) { 28 | state.goodsCategoryCount = list; 29 | }, 30 | changeGoodsCategorySale(state, list: any[]) { 31 | state.goodsCategorySale = list; 32 | }, 33 | changeGoodsCategoryFavor(state, list: any[]) { 34 | state.goodsCategoryFavor = list; 35 | }, 36 | changeGoodsAddressSale(state, list: any[]) { 37 | state.goodsAddressSale = list; 38 | }, 39 | changeGoodsAmountList(state, list: any[]) { 40 | state.goodsAmountList = list; 41 | }, 42 | changeGoodsSaleTop10(state, list: any[]) { 43 | state.goodsSaleTop10 = list; 44 | } 45 | }, 46 | actions: { 47 | async chartDataAction(context) { 48 | const goodsAmountListRes = await getGoodsAmountList(); 49 | context.commit("changeGoodsAmountList", goodsAmountListRes.data); 50 | 51 | const goodsCateCountRes = await getGoodsCategoryCount(); 52 | context.commit("changeGoodsCategoryCount", goodsCateCountRes.data); 53 | 54 | const goodsCateSaleRes = await getGoodsCategorySale(); 55 | context.commit("changeGoodsCategorySale", goodsCateSaleRes.data); 56 | 57 | const goodsCateFavorRes = await getGoodsCategoryFavor(); 58 | context.commit("changeGoodsCategoryFavor", goodsCateFavorRes.data); 59 | 60 | const goodsAddressSaleRes = await getGoodsAddressSale(); 61 | context.commit("changeGoodsAddressSale", goodsAddressSaleRes.data); 62 | }, 63 | async goodsSaleTop10Action(context) { 64 | const goodsSaleTop10Res = await getGoodsSaleTop10(); 65 | context.commit("changeGoodsSaleTop10", goodsSaleTop10Res.data); 66 | } 67 | }, 68 | modules: {} 69 | }; 70 | 71 | export default analysisModule; 72 | -------------------------------------------------------------------------------- /src/store/analysis/types.ts: -------------------------------------------------------------------------------- 1 | export interface AnalysisStateType { 2 | goodsCategoryCount: any[]; 3 | goodsCategorySale: any[]; 4 | goodsCategoryFavor: any[]; 5 | goodsAddressSale: any[]; 6 | goodsAmountList: any[]; 7 | goodsSaleTop10: any[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore, useStore as useVuexStore, Store } from "vuex"; 2 | 3 | import { RootStateType, RootWithModule } from "./types"; 4 | import loginModule from "./login"; 5 | import systemModule from "./system"; 6 | import productModule from "./product"; 7 | import analysisModule from "./analysis"; 8 | 9 | import { getDataList } from "@/service/main/system"; 10 | const store = createStore({ 11 | state() { 12 | return { 13 | departmentList: [], 14 | departmentCount: 0, 15 | roleList: [], 16 | roleCount: 0, 17 | menuList: [] 18 | }; 19 | }, 20 | getters: {}, 21 | mutations: { 22 | changeDepartmentList(state, payload: any[]) { 23 | state.departmentList = payload; 24 | }, 25 | changeDepartmentCount(state, payload: number) { 26 | state.departmentCount = payload; 27 | }, 28 | changeRoleList(state, payload: any[]) { 29 | state.roleList = payload; 30 | }, 31 | changeRoleCount(state, payload: number) { 32 | state.roleCount = payload; 33 | }, 34 | changeMenuList(state, payload: any[]) { 35 | state.menuList = payload; 36 | } 37 | }, 38 | actions: { 39 | async getInitDataAction({ commit }) { 40 | const departmentResult = await getDataList("/department/list", { 41 | offset: 0, 42 | size: 120 43 | }); 44 | const { list: departmentList, totalCount: departmentCount } = 45 | departmentResult.data; 46 | commit("changeDepartmentList", departmentList); 47 | commit("changeDepartmentCount", departmentCount); 48 | 49 | const roleResult = await getDataList("/role/list", { 50 | offset: 0, 51 | size: 120 52 | }); 53 | const { list: roleList, totalCount: roleCount } = roleResult.data; 54 | commit("changeRoleList", roleList); 55 | commit("changeRoleCount", roleCount); 56 | 57 | const menuResult = await getDataList("/menu/list"); 58 | const { list: menuList } = menuResult.data; 59 | commit("changeMenuList", menuList); 60 | } 61 | }, 62 | modules: { 63 | login: loginModule, 64 | system: systemModule, 65 | product: productModule, 66 | analysis: analysisModule 67 | } 68 | }); 69 | 70 | export function uploadCache() { 71 | store.dispatch("login/uploadAction"); 72 | } 73 | export function useStore(): Store { 74 | return useVuexStore(); 75 | } 76 | 77 | export default store; 78 | -------------------------------------------------------------------------------- /src/store/login/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "vuex"; 2 | import router from "@/router"; 3 | 4 | import { 5 | accountLoginRequest, 6 | userInfoRequest, 7 | userMenuRequest 8 | } from "@/service/login"; 9 | import { AccountLoginType } from "@/service/login/types"; 10 | import localCache from "@/utils/cache"; 11 | import menuToRoute, { jurisdictionList } from "@/utils/menuToRoute"; 12 | 13 | import { RootStateType } from "../types"; 14 | import { LoginStateType } from "./types"; 15 | const loginModule: Module = { 16 | namespaced: true, 17 | state() { 18 | return { 19 | token: "", 20 | userInfo: {}, 21 | userMenus: [], 22 | permissionList: [] 23 | }; 24 | }, 25 | getters: {}, 26 | mutations: { 27 | changeToken(state, token: string) { 28 | state.token = token; 29 | }, 30 | changeUserInfo(state, payload: any) { 31 | state.userInfo = payload; 32 | }, 33 | changeUserMenus(state, payload: any) { 34 | state.userMenus = payload; 35 | const menusInfo = menuToRoute(payload); 36 | menusInfo.forEach((item) => { 37 | router.addRoute("main", item); 38 | }); 39 | 40 | const permissionList = jurisdictionList(payload); 41 | state.permissionList = permissionList; 42 | } 43 | }, 44 | actions: { 45 | async accountLoginAction(context, payload: AccountLoginType) { 46 | // 登陆信息 47 | const loginResult = await accountLoginRequest(payload); 48 | const { id, token } = loginResult.data; 49 | context.commit("changeToken", token); 50 | localCache.setCache("token", token); 51 | 52 | context.dispatch("getInitDataAction", null, { root: true }); 53 | // 登陆后用户信息 54 | const userInfoResult = await userInfoRequest(id); 55 | context.commit("changeUserInfo", userInfoResult.data); 56 | localCache.setCache("userInfo", userInfoResult.data); 57 | //请求用户菜单 58 | const userMenuResult = await userMenuRequest(id); 59 | context.commit("changeUserMenus", userMenuResult.data); 60 | localCache.setCache("userMenus", userMenuResult.data); 61 | // 路由跳转 62 | router.push("/main"); 63 | }, 64 | uploadAction(context) { 65 | const token = localCache.getCache("token"); 66 | if (token) { 67 | context.commit("changeToken", token); 68 | context.dispatch("getInitDataAction", null, { root: true }); 69 | } 70 | const userInfo = localCache.getCache("userInfo"); 71 | if (userInfo) { 72 | context.commit("changeUserInfo", userInfo); 73 | } 74 | const userMenus = localCache.getCache("userMenus"); 75 | if (userMenus) { 76 | context.commit("changeUserMenus", userMenus); 77 | } 78 | } 79 | } 80 | }; 81 | 82 | export default loginModule; 83 | -------------------------------------------------------------------------------- /src/store/login/types.ts: -------------------------------------------------------------------------------- 1 | export interface LoginStateType { 2 | token: string; 3 | userInfo: any; 4 | userMenus: any; 5 | permissionList: string[]; 6 | } 7 | -------------------------------------------------------------------------------- /src/store/product/index.ts: -------------------------------------------------------------------------------- 1 | import type { Module } from "vuex"; 2 | import { RootStateType } from "../types"; 3 | import { ProductStateType } from "./types"; 4 | const productModule: Module = { 5 | namespaced: true, 6 | state: () => { 7 | return { 8 | goodsList: [], 9 | goodsCount: 0 10 | }; 11 | }, 12 | getters: {}, 13 | mutations: {}, 14 | actions: {} 15 | }; 16 | 17 | export default productModule; 18 | -------------------------------------------------------------------------------- /src/store/product/types.ts: -------------------------------------------------------------------------------- 1 | export interface ProductStateType { 2 | goodsList: any[]; 3 | goodsCount: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/store/system/index.ts: -------------------------------------------------------------------------------- 1 | import { Module } from "vuex"; 2 | import { RootStateType } from "../types"; 3 | import { SystemStateType, DataListEnum } from "./types"; 4 | 5 | import { 6 | getDataList, 7 | deleteDataList, 8 | editorPageData, 9 | createPageData 10 | } from "@/service/main/system"; 11 | import { firstCapitalLetter } from "@/utils/handleString"; 12 | const systemModule: Module = { 13 | namespaced: true, 14 | state: () => ({ 15 | usersList: [], 16 | usersCount: 0, 17 | roleList: [], 18 | roleCount: 0, 19 | menuList: [], 20 | menuCount: 0, 21 | goodsList: [], 22 | goodsCount: 0, 23 | departmentList: [], 24 | departmentCount: 0, 25 | categoryList: [], 26 | categoryCount: 0, 27 | storyList: [], 28 | storyCount: 0 29 | }), 30 | getters: { 31 | getDataCount(state) { 32 | return function (pageName: string) { 33 | return (state as any)[`${pageName}Count`]; 34 | }; 35 | } 36 | }, 37 | mutations: { 38 | changeUsersList(state, payload) { 39 | state.usersList = payload; 40 | }, 41 | changeUsersCount(state, payload: number) { 42 | state.usersCount = payload; 43 | }, 44 | changeRoleList(state, payload) { 45 | state.roleList = payload; 46 | }, 47 | changeRoleCount(state, payload: number) { 48 | state.roleCount = payload; 49 | }, 50 | changeMenuList(state, payload) { 51 | state.menuList = payload; 52 | }, 53 | changeMenuCount(state, payload: number) { 54 | state.menuCount = payload; 55 | }, 56 | changeGoodsList(state, payload) { 57 | state.goodsList = payload; 58 | }, 59 | changeGoodsCount(state, payload: number) { 60 | state.goodsCount = payload; 61 | }, 62 | changeDepartmentList(state, payload) { 63 | state.departmentList = payload; 64 | }, 65 | changeDepartmentCount(state, payload: number) { 66 | state.departmentCount = payload; 67 | }, 68 | changeCategoryList(state, list: any[]) { 69 | state.categoryList = list; 70 | }, 71 | changeCategoryCount(state, payload: number) { 72 | state.categoryCount = payload; 73 | }, 74 | changeStoryList(state, list: any[]) { 75 | state.storyList = list; 76 | }, 77 | changeStoryCount(state, count: number) { 78 | state.storyCount = count; 79 | } 80 | }, 81 | actions: { 82 | async dataListAction({ commit }, payload) { 83 | let dataUrl = ""; 84 | switch (payload.pageName) { 85 | case "users": 86 | dataUrl = DataListEnum.USER_LIST_URL; 87 | break; 88 | case "role": 89 | dataUrl = DataListEnum.ROLE_LIST_URL; 90 | break; 91 | case "menu": 92 | dataUrl = DataListEnum.MENU_LIST_URL; 93 | break; 94 | case "goods": 95 | dataUrl = DataListEnum.GOODS_LIST_URL; 96 | break; 97 | case "department": 98 | dataUrl = DataListEnum.DEPAERTMENT_LIST_URL; 99 | break; 100 | case "category": 101 | dataUrl = DataListEnum.CATEGORY_LIST_URL; 102 | break; 103 | case "story": 104 | dataUrl = DataListEnum.STORY_LIST_URL; 105 | break; 106 | } 107 | 108 | const result = await getDataList(dataUrl, payload.queryInfo); 109 | 110 | const pageName = firstCapitalLetter(payload.pageName); 111 | 112 | commit(`change${pageName}List`, result.data.list); 113 | commit(`change${pageName}Count`, result.data.totalCount); 114 | }, 115 | async deleteDataAction(context, payload) { 116 | const { pageName, id } = payload; 117 | const url = `/${pageName}/${id}`; 118 | await deleteDataList(url); 119 | context.dispatch("dataListAction", { 120 | pageName, 121 | queryInfo: { 122 | offset: 0, 123 | size: 10 124 | } 125 | }); 126 | }, 127 | async editorPageDataAction(context, payload: any) { 128 | const { pageName, userId, queryInfo } = payload; 129 | const url = `/${pageName}/${userId}`; 130 | console.log(payload); 131 | await editorPageData(url, queryInfo); 132 | context.dispatch("dataListAction", { 133 | pageName, 134 | offset: 0, 135 | size: 10 136 | }); 137 | }, 138 | async createPageDataAction(context, payload: any) { 139 | const { pageName, queryInfo } = payload; 140 | const url = `/${pageName}`; 141 | await createPageData(url, queryInfo); 142 | context.dispatch("dataListAction", { 143 | pageName, 144 | offset: 0, 145 | size: 10 146 | }); 147 | } 148 | } 149 | }; 150 | export default systemModule; 151 | -------------------------------------------------------------------------------- /src/store/system/types.ts: -------------------------------------------------------------------------------- 1 | export interface SystemStateType { 2 | usersList: any[]; 3 | usersCount: number; 4 | roleList: any[]; 5 | roleCount: number; 6 | menuList: any[]; 7 | menuCount: number; 8 | goodsList: any[]; 9 | goodsCount: number; 10 | departmentList: any[]; 11 | departmentCount: number; 12 | categoryList: any[]; 13 | categoryCount: number; 14 | storyList: any[]; 15 | storyCount: number; 16 | } 17 | export enum DataListEnum { 18 | USER_LIST_URL = "/users/list", 19 | ROLE_LIST_URL = "/role/list", 20 | MENU_LIST_URL = "/menu/list", 21 | GOODS_LIST_URL = "/goods/list", 22 | DEPAERTMENT_LIST_URL = "/department/list", 23 | CATEGORY_LIST_URL = "/category/list", 24 | STORY_LIST_URL = "/story/list" 25 | } 26 | -------------------------------------------------------------------------------- /src/store/types.ts: -------------------------------------------------------------------------------- 1 | import type { LoginStateType } from "./login/types"; 2 | import type { SystemStateType } from "./system/types"; 3 | import { ProductStateType } from "./product/types"; 4 | import type { AnalysisStateType } from "./analysis/types"; 5 | export interface RootStateType { 6 | departmentList: any[]; 7 | departmentCount: number; 8 | roleList: any[]; 9 | roleCount: number; 10 | menuList: any[]; 11 | } 12 | 13 | interface ModuleType { 14 | login: LoginStateType; 15 | system: SystemStateType; 16 | product: ProductStateType; 17 | analysis: AnalysisStateType; 18 | } 19 | 20 | export type RootWithModule = RootStateType & ModuleType; 21 | -------------------------------------------------------------------------------- /src/utils/cache.ts: -------------------------------------------------------------------------------- 1 | class LocalCache { 2 | setCache(key: string, value: any) { 3 | window.localStorage.setItem(key, JSON.stringify(value)); 4 | } 5 | getCache(key: string) { 6 | const value = window.localStorage.getItem(key); 7 | if (value) { 8 | return JSON.parse(value); 9 | } 10 | } 11 | deleteCache(key: string) { 12 | window.localStorage.removeItem(key); 13 | } 14 | clearCache() { 15 | window.localStorage.clear(); 16 | } 17 | } 18 | 19 | export default new LocalCache(); 20 | -------------------------------------------------------------------------------- /src/utils/formate.ts: -------------------------------------------------------------------------------- 1 | import dayjs from "dayjs"; 2 | import utc from "dayjs/plugin/utc"; 3 | 4 | dayjs.extend(utc); 5 | export function formatUtcToData(data: string, formatString: string): string { 6 | return dayjs.utc(data).utcOffset(8).format(formatString); 7 | } 8 | -------------------------------------------------------------------------------- /src/utils/handleString.ts: -------------------------------------------------------------------------------- 1 | export function firstCapitalLetter(letter: string): string { 2 | return letter.slice(0, 1).toUpperCase() + letter.slice(1); 3 | } 4 | -------------------------------------------------------------------------------- /src/utils/menuToRoute.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordRaw } from "vue-router"; 2 | import { BreadCrumbItemType } from "@/common-ui/breadcrumb"; 3 | 4 | let firstMenu: any = null; 5 | export default function (useMenus: any[]): RouteRecordRaw[] { 6 | const routes: RouteRecordRaw[] = []; 7 | // 加入全部路由 8 | const allRoutes: RouteRecordRaw[] = []; 9 | const routeFiles = require.context("@/router/main", true, /\.ts$/); 10 | routeFiles.keys().forEach((filePath) => { 11 | const routeModule = require("@/router/main" + filePath.split(".")[1]); 12 | allRoutes.push(routeModule.default); 13 | }); 14 | // 递归函数 获取可点击部分的url,并进行筛选 15 | function findRouteFun(useMenus: any[]): void { 16 | for (const menu of useMenus) { 17 | if (menu.type === 1) { 18 | findRouteFun(menu.children); 19 | } else if (menu.type === 2) { 20 | const route = allRoutes.find((item) => item.path === menu.url); 21 | if (route) { 22 | if (!firstMenu) { 23 | firstMenu = menu; 24 | } 25 | 26 | routes.push(route); 27 | } 28 | } 29 | } 30 | } 31 | findRouteFun(useMenus); 32 | return routes; 33 | } 34 | 35 | export function pathMapToMenu( 36 | useMenus: any[], 37 | path: string, 38 | breadCrumbList?: BreadCrumbItemType[] 39 | ): any { 40 | for (const menu of useMenus) { 41 | if (menu.type === 1) { 42 | const findMenu = pathMapToMenu(menu.children ?? [], path); 43 | if (findMenu) { 44 | breadCrumbList?.push(menu); 45 | breadCrumbList?.push(findMenu); 46 | return findMenu; 47 | } 48 | } else if (menu.type === 2 && menu.url === path) { 49 | return menu; 50 | } 51 | } 52 | } 53 | 54 | export function breadCrumbMapToMenu( 55 | useMenus: any[], 56 | path: string 57 | ): BreadCrumbItemType[] { 58 | const breadCrumbList: BreadCrumbItemType[] = []; 59 | pathMapToMenu(useMenus, path, breadCrumbList); 60 | return breadCrumbList; 61 | } 62 | 63 | export function jurisdictionList(useMenus: any[]): any { 64 | const permissionList = []; 65 | for (const menu of useMenus) { 66 | if (menu.children) { 67 | const permission = jurisdictionList(menu.children); 68 | permissionList.push(...permission); 69 | } else { 70 | if (menu.permission) { 71 | permissionList.push(menu.permission); 72 | } 73 | } 74 | } 75 | return permissionList; 76 | } 77 | 78 | export function mapFirstMenuList(useMenus: any[]): { 79 | value: any; 80 | title: any; 81 | }[] { 82 | const menuList = []; 83 | for (const menu of useMenus) { 84 | if (menu.type === 1) { 85 | menuList.push({ 86 | value: menu.id, 87 | title: menu.name 88 | }); 89 | } 90 | } 91 | menuList.push({ 92 | value: "", 93 | title: "创建一级菜单" 94 | }); 95 | return menuList; 96 | } 97 | 98 | export function mapHalfCheckedKeys(menuList: any[]): number[] { 99 | const keyList: number[] = []; 100 | const _recursionMapKeys = (menuList: any[]) => { 101 | for (const item of menuList) { 102 | if (item.children) { 103 | _recursionMapKeys(item.children); 104 | } else { 105 | keyList.push(item.id); 106 | } 107 | } 108 | }; 109 | _recursionMapKeys(menuList); 110 | return keyList; 111 | } 112 | export { firstMenu }; 113 | -------------------------------------------------------------------------------- /src/views/login/Login.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 63 | 64 | 96 | -------------------------------------------------------------------------------- /src/views/login/cpns/LoginPhone.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 48 | 49 | 62 | -------------------------------------------------------------------------------- /src/views/login/cpns/LoginUser.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 58 | 59 | 64 | -------------------------------------------------------------------------------- /src/views/login/hooks/rules.ts: -------------------------------------------------------------------------------- 1 | export const loginUserRules = { 2 | name: [ 3 | { 4 | required: true, 5 | message: "用户名不能为空~", 6 | trigger: "blur" 7 | }, 8 | { 9 | pattern: /^\w{4,8}$/, 10 | message: "请输入正确的用户名~", 11 | trigger: "blur" 12 | } 13 | ], 14 | password: [ 15 | { 16 | required: true, 17 | message: "密码不能为空~", 18 | trigger: "blur" 19 | }, 20 | { 21 | pattern: /^\w{4,8}$/, 22 | message: "密码错误~", 23 | trigger: "blur" 24 | } 25 | ] 26 | }; 27 | export const loginPhoneRules = { 28 | phonenumber: [ 29 | { 30 | required: true, 31 | message: "手机号不能为空~", 32 | trigger: "blur" 33 | }, 34 | { 35 | pattern: /^\w{0,11}$/, 36 | message: "请输入正确的手机号~", 37 | trigger: "blur" 38 | } 39 | ], 40 | password: [ 41 | { 42 | required: true, 43 | message: "密码不能为空~", 44 | trigger: "blur" 45 | }, 46 | { 47 | pattern: /^\w{4,8}$/, 48 | message: "密码错误~", 49 | trigger: "blur" 50 | } 51 | ] 52 | }; 53 | -------------------------------------------------------------------------------- /src/views/main/Main.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 57 | 58 | 111 | -------------------------------------------------------------------------------- /src/views/main/analysis/dashboard/config/showCountConfig.ts: -------------------------------------------------------------------------------- 1 | interface countupOptionType { 2 | useEasing?: true; 3 | useGrouping?: boolean; 4 | separator?: string; 5 | decimal?: string; 6 | prefix?: string; 7 | suffix?: string; 8 | } 9 | 10 | interface myCountupOptions { 11 | sale: countupOptionType; 12 | favor: countupOptionType; 13 | inventory: countupOptionType; 14 | saleroom: countupOptionType; 15 | } 16 | 17 | const options: myCountupOptions = { 18 | sale: { 19 | useEasing: true, 20 | useGrouping: true, 21 | separator: "," 22 | }, 23 | favor: { useEasing: true, useGrouping: true, separator: "," }, 24 | inventory: { useEasing: true, useGrouping: true, separator: "," }, 25 | saleroom: { 26 | useEasing: true, 27 | useGrouping: true, 28 | separator: ",", 29 | prefix: "¥" 30 | } 31 | }; 32 | 33 | export default options; 34 | -------------------------------------------------------------------------------- /src/views/main/analysis/dashboard/cpn/ShowCharts.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 112 | 113 | 118 | -------------------------------------------------------------------------------- /src/views/main/analysis/dashboard/cpn/ShowCount.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 72 | 73 | 114 | -------------------------------------------------------------------------------- /src/views/main/analysis/dashboard/dashboard.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/views/main/analysis/overview/config/dependencies.ts: -------------------------------------------------------------------------------- 1 | const dependencies = { 2 | itemList: [ 3 | { 4 | name: "vue", 5 | description: "^3.0.5" 6 | }, 7 | { 8 | name: "vue-router", 9 | description: "^4.0.6" 10 | }, 11 | { 12 | name: "vuex", 13 | description: "^4.0.0" 14 | }, 15 | { 16 | name: "axios", 17 | description: "^0.21.1" 18 | }, 19 | { 20 | name: "element-plus", 21 | description: "^1.0.2-beta.41" 22 | }, 23 | 24 | { 25 | name: "mockjs", 26 | description: "^1.1.0" 27 | }, 28 | 29 | { 30 | name: "less", 31 | description: "^4.1.1" 32 | }, 33 | { 34 | name: "scss", 35 | description: "^0.2.4" 36 | }, 37 | { 38 | name: "EChart", 39 | description: "^5.1.1" 40 | }, 41 | 42 | { 43 | name: "@vueuse/core", 44 | description: "^4.9.1" 45 | }, 46 | { 47 | name: "countup.js", 48 | description: "^2.0.7" 49 | }, 50 | { 51 | name: "dayjs", 52 | description: "^1.10.4" 53 | }, 54 | { 55 | name: "pinia", 56 | description: "^2.0.0-alpha.13" 57 | }, 58 | { 59 | name: "wangeditor", 60 | description: "^4.6.17" 61 | } 62 | ], 63 | column: 2, 64 | title: "生产依赖" 65 | }; 66 | 67 | export default dependencies; 68 | -------------------------------------------------------------------------------- /src/views/main/analysis/overview/config/devDependencies.ts: -------------------------------------------------------------------------------- 1 | const devDependencies = { 2 | itemList: [ 3 | { 4 | name: "typescript", 5 | description: "^4.1.3" 6 | }, 7 | { 8 | name: "webpack", 9 | description: "5" 10 | }, 11 | { 12 | name: "vite", 13 | description: "^2.2.3" 14 | }, 15 | 16 | { 17 | name: "eslint", 18 | description: "^7.25.0" 19 | }, 20 | { 21 | name: "prettier", 22 | description: "^2.2.1" 23 | }, 24 | { 25 | name: "stylelint", 26 | description: "^13.13.0" 27 | }, 28 | { 29 | name: "husky", 30 | description: "^6.0.0" 31 | }, 32 | { 33 | name: "lint-staged", 34 | description: "^10.5.4" 35 | }, 36 | { 37 | name: "rimraf", 38 | description: "^3.0.2" 39 | }, 40 | { 41 | name: "@commitlint/cli", 42 | description: "^12.1.1" 43 | }, 44 | { 45 | name: "@commitlint/config-conventional", 46 | description: "^12.1.1" 47 | }, 48 | { 49 | name: "@types/node", 50 | description: "^14.14.41" 51 | }, 52 | { 53 | name: "@typescript-eslint/eslint-plugin", 54 | description: "^4.22.0" 55 | }, 56 | { 57 | name: "@typescript-eslint/parser", 58 | description: "^4.22.0" 59 | }, 60 | { 61 | name: "@vitejs/plugin-vue", 62 | description: "^1.2.2" 63 | }, 64 | { 65 | name: "@vue/compiler-sfc", 66 | description: "^3.0.5" 67 | }, 68 | { 69 | name: "commitizen", 70 | description: "^4.2.3" 71 | }, 72 | { 73 | name: "cz-conventional-changelog", 74 | description: "3.3.0" 75 | }, 76 | { 77 | name: "eslint-config-airbnb-base", 78 | description: "^14.2.1" 79 | }, 80 | { 81 | name: "eslint-config-prettier", 82 | description: "^8.3.0" 83 | }, 84 | { 85 | name: "eslint-plugin-import", 86 | description: "^2.22.1" 87 | }, 88 | { 89 | name: "eslint-plugin-prettier", 90 | description: "^3.4.0" 91 | }, 92 | { 93 | name: "eslint-plugin-vue", 94 | description: "^7.9.0" 95 | }, 96 | { 97 | name: "stylelint-config-prettier", 98 | description: "^8.0.2" 99 | }, 100 | { 101 | name: "stylelint-config-standard", 102 | description: "^22.0.0" 103 | }, 104 | { 105 | name: "stylelint-order", 106 | description: "^4.1.0" 107 | }, 108 | { 109 | name: "vite-plugin-mock", 110 | description: "^2.5.0" 111 | }, 112 | { 113 | name: "vue-tsc", 114 | description: "^0.0.8" 115 | } 116 | ], 117 | column: 2, 118 | title: "开发依赖" 119 | }; 120 | 121 | export default devDependencies; 122 | -------------------------------------------------------------------------------- /src/views/main/analysis/overview/config/projectStandard.ts: -------------------------------------------------------------------------------- 1 | export const filenameStandard = { 2 | itemList: [ 3 | { name: "文件夹", description: "统一小写, 多个单词使用-分割" }, 4 | { 5 | name: "文件(.ts .vue .json .d.ts)", 6 | description: "统一小写, 多个单词使用-分割" 7 | } 8 | ], 9 | column: 1, 10 | 11 | title: "文件名称规范" 12 | }; 13 | 14 | export const componentStandard = { 15 | itemList: [ 16 | { name: "组件的文件", description: "统一小写, 多个单词使用-分割" }, 17 | { 18 | name: "组件的目录结构", 19 | description: 20 | "例如 button 组件:button/src/index.vue, 统一在button/index.ts导出" 21 | }, 22 | { 23 | name: "组件导包顺序", 24 | description: 25 | "导vue技术栈的包 , 导第三方的工具函数 , 导本地的组件, 导本地的工具函数" 26 | }, 27 | { name: "组件的名称", description: "统一大写开头,驼峰命名" }, 28 | { 29 | name: "组件属性顺序", 30 | description: "name, components, props, emits, setup ..." 31 | }, 32 | { name: "template标签", description: "小写加 - ( 例如: )" }, 33 | { 34 | name: "template标签属性顺序", 35 | description: "v-if , v-for , ref, class, style, ... ,事件" 36 | }, 37 | { 38 | name: "组件的props", 39 | description: "小写开头,驼峰命名,必须编写类型默认值" 40 | }, 41 | { 42 | name: "组件的样式", 43 | description: 44 | "作用域:scoped, lang = scss / less ; 类名:统一小写, 多个单词使用-分割" 45 | } 46 | ], 47 | column: 1, 48 | title: "组件编写规范" 49 | }; 50 | 51 | export const commitStandard = { 52 | itemList: [ 53 | { name: "add 操作", description: "git add " }, 54 | { name: "commit 操作", description: "yarn commit " }, 55 | { name: "pull 操作", description: "git pull " }, 56 | { name: "push 操作", description: "git push " } 57 | ], 58 | column: 1, 59 | 60 | title: "Git提交规范" 61 | }; 62 | -------------------------------------------------------------------------------- /src/views/main/analysis/overview/config/projectTree.ts: -------------------------------------------------------------------------------- 1 | const tree = ` 2 | vue3_ts_cms 3 | │ .browserslistrc 4 | │ .editorconfig 5 | │ .env.development 6 | │ .env.production 7 | │ .env.test 8 | │ .eslintrc.js 9 | │ .gitignore 10 | │ .prettierignore 11 | │ .prettierrc 12 | │ babel.config.js 13 | │ commitlint.config.js 14 | │ package-lock.json 15 | │ package.json 16 | │ README.md 17 | │ tsconfig.json 18 | │ vue.config.js 19 | │ 20 | ├─.husky 21 | │ │ commit-msg 22 | │ │ pre-commit 23 | │ │ 24 | │ └─_ 25 | │ .gitignore 26 | │ husky.sh 27 | │ 28 | ├─public 29 | │ favicon.ico 30 | │ index.html 31 | │ 32 | └─src 33 | │ App.vue 34 | │ main.ts 35 | │ shims-vue.d.ts 36 | │ 37 | ├─assets 38 | │ ├─css 39 | │ │ base.less 40 | │ │ index.less 41 | │ │ wangEditor.less 42 | │ │ 43 | │ └─images 44 | │ background_img.jpg 45 | │ logo.png 46 | │ 47 | ├─common-ui 48 | │ ├─breadcrumb 49 | │ │ │ index.ts 50 | │ │ │ 51 | │ │ ├─src 52 | │ │ │ BreadCrumb.vue 53 | │ │ │ 54 | │ │ └─types 55 | │ │ types.ts 56 | │ │ 57 | │ ├─msi-card 58 | │ │ │ index.ts 59 | │ │ │ 60 | │ │ └─src 61 | │ │ MsiCard.vue 62 | │ │ 63 | │ ├─msi-descriptions 64 | │ │ │ index.ts 65 | │ │ │ 66 | │ │ └─src 67 | │ │ MsiDescriptions.vue 68 | │ │ 69 | │ ├─msi-echarts 70 | │ │ │ index.ts 71 | │ │ │ 72 | │ │ ├─hooks 73 | │ │ │ initECharts.ts 74 | │ │ │ mapCityToMap.ts 75 | │ │ │ 76 | │ │ ├─map 77 | │ │ │ china.json 78 | │ │ │ city.ts 79 | │ │ │ 80 | │ │ └─src 81 | │ │ MsiEcharts.vue 82 | │ │ 83 | │ ├─msi-editor 84 | │ │ │ index.ts 85 | │ │ │ 86 | │ │ └─src 87 | │ │ MsiEditor.vue 88 | │ │ 89 | │ ├─msi-form 90 | │ │ │ index.ts 91 | │ │ │ 92 | │ │ ├─src 93 | │ │ │ MsiForm.vue 94 | │ │ │ 95 | │ │ └─types 96 | │ │ types.ts 97 | │ │ 98 | │ ├─msi-tabel 99 | │ │ │ index.ts 100 | │ │ │ 101 | │ │ ├─src 102 | │ │ │ MsiTabel.vue 103 | │ │ │ 104 | │ │ └─types 105 | │ │ types.ts 106 | │ │ 107 | │ └─msi-upload 108 | │ │ index.ts 109 | │ │ 110 | │ └─src 111 | │ MsiUpload.vue 112 | │ 113 | ├─components 114 | │ ├─nav-header 115 | │ │ │ index.ts 116 | │ │ │ 117 | │ │ └─src 118 | │ │ NavHeader.vue 119 | │ │ 120 | │ ├─nav-menu 121 | │ │ │ index.ts 122 | │ │ │ 123 | │ │ └─src 124 | │ │ NavMenu.vue 125 | │ │ 126 | │ ├─page-dialog 127 | │ │ │ index.ts 128 | │ │ │ 129 | │ │ ├─src 130 | │ │ │ PageDialog.vue 131 | │ │ │ 132 | │ │ └─types 133 | │ │ types.ts 134 | │ │ 135 | │ ├─page-echart 136 | │ │ │ index.ts 137 | │ │ │ 138 | │ │ └─src 139 | │ │ PageBarChart.vue 140 | │ │ PageChinaChart.vue 141 | │ │ PageLineChart.vue 142 | │ │ PagePicChart.vue 143 | │ │ PagePicLableChart.vue 144 | │ │ PageRoseChart.vue 145 | │ │ 146 | │ ├─page-search 147 | │ │ │ index.ts 148 | │ │ │ 149 | │ │ └─src 150 | │ │ PageSearch.vue 151 | │ │ 152 | │ └─page-tabel 153 | │ │ index.ts 154 | │ │ 155 | │ └─src 156 | │ PageTabel.vue 157 | │ 158 | ├─global 159 | │ index.ts 160 | │ registerElement.ts 161 | │ registerGlobal.ts 162 | │ 163 | ├─hooks 164 | │ countAction.ts 165 | │ pageLinkage.ts 166 | │ permission.ts 167 | │ 168 | ├─router 169 | │ │ index.ts 170 | │ │ 171 | │ └─main 172 | │ ├─analysis 173 | │ │ ├─dashboard 174 | │ │ │ dashboard.ts 175 | │ │ │ 176 | │ │ └─overview 177 | │ │ overview.ts 178 | │ │ 179 | │ ├─product 180 | │ │ ├─category 181 | │ │ │ category.ts 182 | │ │ │ 183 | │ │ └─goods 184 | │ │ goods.ts 185 | │ │ 186 | │ ├─story 187 | │ │ ├─chat 188 | │ │ │ chat.ts 189 | │ │ │ 190 | │ │ └─list 191 | │ │ list.ts 192 | │ │ 193 | │ └─system 194 | │ ├─department 195 | │ │ department.ts 196 | │ │ 197 | │ ├─menu 198 | │ │ menu.ts 199 | │ │ 200 | │ ├─role 201 | │ │ role.ts 202 | │ │ 203 | │ └─user 204 | │ user.ts 205 | │ 206 | ├─service 207 | │ │ index.ts 208 | │ │ types.ts 209 | │ │ 210 | │ ├─login 211 | │ │ index.ts 212 | │ │ types.ts 213 | │ │ 214 | │ ├─main 215 | │ │ ├─analysis 216 | │ │ │ index.ts 217 | │ │ │ 218 | │ │ ├─story 219 | │ │ │ index.ts 220 | │ │ │ 221 | │ │ └─system 222 | │ │ index.ts 223 | │ │ 224 | │ └─request 225 | │ index.ts 226 | │ type.ts 227 | │ 228 | ├─store 229 | │ │ index.ts 230 | │ │ types.ts 231 | │ │ 232 | │ ├─analysis 233 | │ │ index.ts 234 | │ │ types.ts 235 | │ │ 236 | │ ├─login 237 | │ │ index.ts 238 | │ │ types.ts 239 | │ │ 240 | │ ├─product 241 | │ │ index.ts 242 | │ │ types.ts 243 | │ │ 244 | │ └─system 245 | │ index.ts 246 | │ types.ts 247 | │ 248 | ├─utils 249 | │ cache.ts 250 | │ formate.ts 251 | │ handleString.ts 252 | │ menuToRoute.ts 253 | │ 254 | └─views 255 | ├─login 256 | │ │ Login.vue 257 | │ │ 258 | │ ├─cpns 259 | │ │ LoginPhone.vue 260 | │ │ LoginUser.vue 261 | │ │ 262 | │ └─hooks 263 | │ rules.ts 264 | │ 265 | ├─main 266 | │ │ Main.vue 267 | │ │ 268 | │ ├─analysis 269 | │ │ ├─dashboard 270 | │ │ │ │ dashboard.vue 271 | │ │ │ │ 272 | │ │ │ ├─config 273 | │ │ │ │ showCountConfig.ts 274 | │ │ │ │ 275 | │ │ │ ├─cpn 276 | │ │ │ │ ShowCharts.vue 277 | │ │ │ │ ShowCount.vue 278 | │ │ │ │ 279 | │ │ │ └─hook 280 | │ │ └─overview 281 | │ │ │ overview copy.vue 282 | │ │ │ overview.vue 283 | │ │ │ 284 | │ │ └─config 285 | │ │ dependencies.ts 286 | │ │ devDependencies.ts 287 | │ │ projectStandard.ts 288 | │ │ projectTree.ts 289 | │ │ technologyStacks.ts 290 | │ │ 291 | │ ├─product 292 | │ │ ├─category 293 | │ │ │ │ category.vue 294 | │ │ │ │ 295 | │ │ │ ├─config 296 | │ │ │ │ dialog.config.ts 297 | │ │ │ │ form.config.ts 298 | │ │ │ │ tabel.config.ts 299 | │ │ │ │ 300 | │ │ │ └─cpn 301 | │ │ │ CategoryHeader.vue 302 | │ │ │ 303 | │ │ └─goods 304 | │ │ │ goods.vue 305 | │ │ │ 306 | │ │ └─configs 307 | │ │ dialog.config.ts 308 | │ │ tabel.config.ts 309 | │ │ 310 | │ ├─story 311 | │ │ ├─chat 312 | │ │ │ chat.vue 313 | │ │ │ 314 | │ │ └─list 315 | │ │ │ list.vue 316 | │ │ │ 317 | │ │ └─config 318 | │ │ tabel.config.ts 319 | │ │ 320 | │ └─system 321 | │ ├─department 322 | │ │ │ department.vue 323 | │ │ │ 324 | │ │ └─config 325 | │ │ dialog.config.ts 326 | │ │ from.config.ts 327 | │ │ tabel.config.ts 328 | │ │ 329 | │ ├─menu 330 | │ │ │ menu.vue 331 | │ │ │ 332 | │ │ └─configs 333 | │ │ dialog.config.ts 334 | │ │ tabel.config.ts 335 | │ │ 336 | │ ├─role 337 | │ │ │ role.vue 338 | │ │ │ 339 | │ │ └─config 340 | │ │ dialog.config.ts 341 | │ │ form.config.ts 342 | │ │ tabel.config.ts 343 | │ │ 344 | │ └─user 345 | │ │ user.vue 346 | │ │ 347 | │ └─configs 348 | │ dialog.config.ts 349 | │ form.config.ts 350 | │ tabel.config.ts 351 | │ 352 | └─not-found 353 | │ NotFound.vue 354 | │ 355 | └─src 356 | `; 357 | 358 | export default tree; 359 | -------------------------------------------------------------------------------- /src/views/main/analysis/overview/config/technologyStacks.ts: -------------------------------------------------------------------------------- 1 | const techologyStack = [ 2 | { 3 | title: "开发工具", 4 | desp: "Visual Studio Code" 5 | }, 6 | 7 | { 8 | title: "编程语言", 9 | desp: "TypeScript 4.x + JavaScript" 10 | }, 11 | 12 | { 13 | title: "构建工具", 14 | desp: "Vite 2.x / Webpack5.x" 15 | }, 16 | 17 | { 18 | title: "前端框架", 19 | desp: "Vue 3.x" 20 | }, 21 | 22 | { 23 | title: "路由工具", 24 | desp: "Vue Router 4.x" 25 | }, 26 | 27 | { 28 | title: "状态管理", 29 | desp: "Vuex 4.x" 30 | }, 31 | 32 | { 33 | title: "UI 框架", 34 | desp: "Element Plus" 35 | }, 36 | 37 | { 38 | title: "可视化", 39 | desp: "Echart5.x" 40 | }, 41 | 42 | { 43 | title: "富文本", 44 | desp: "WangEditor" 45 | }, 46 | 47 | { 48 | title: "工具库", 49 | desp: " @vueuse/core + dayjs + countup.js" 50 | }, 51 | 52 | { 53 | title: "CSS 预编译", 54 | desp: "Sass / Less" 55 | }, 56 | 57 | { 58 | title: "HTTP 工具", 59 | desp: "Axios" 60 | }, 61 | 62 | { 63 | title: "Git Hook 工具", 64 | desp: "husky" 65 | }, 66 | 67 | { 68 | title: "代码规范", 69 | desp: "EditorConfig + Prettier + ESLint" 70 | }, 71 | 72 | { 73 | title: "提交规范", 74 | desp: "Commitizen + Commitlint" 75 | }, 76 | 77 | { 78 | title: "自动部署", 79 | desp: "Centos + Jenkins + Nginx" 80 | } 81 | ]; 82 | 83 | export default techologyStack; 84 | -------------------------------------------------------------------------------- /src/views/main/analysis/overview/overview.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 60 | 61 | 85 | -------------------------------------------------------------------------------- /src/views/main/product/category/category.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 76 | 77 | 84 | -------------------------------------------------------------------------------- /src/views/main/product/category/config/dialog.config.ts: -------------------------------------------------------------------------------- 1 | import { IForm } from "@/common-ui/msi-form"; 2 | 3 | const DialogConfig: IForm = { 4 | formItem: [ 5 | { 6 | field: "name", 7 | label: "类别", 8 | type: "input", 9 | placeholder: "请输入类别" 10 | } 11 | ], 12 | colLayout: { 13 | span: 24 14 | } 15 | }; 16 | 17 | export default DialogConfig; 18 | -------------------------------------------------------------------------------- /src/views/main/product/category/config/form.config.ts: -------------------------------------------------------------------------------- 1 | import type { IForm } from "@/common-ui/msi-form"; 2 | 3 | const FormConfig: IForm = { 4 | formItem: [ 5 | { 6 | field: "name", 7 | type: "input", 8 | label: "类别", 9 | placeholder: "请输入商品类别..." 10 | }, 11 | { 12 | field: "createAt", 13 | type: "datapicker", 14 | label: "创建日期", 15 | otherOptions: { 16 | startPlaceholder: "开始时间", 17 | endPlaceholder: "结束时间", 18 | type: "daterange" 19 | } 20 | } 21 | ], 22 | itemStyle: { 23 | padding: "10px 40px" 24 | } 25 | }; 26 | 27 | export default FormConfig; 28 | -------------------------------------------------------------------------------- /src/views/main/product/category/config/tabel.config.ts: -------------------------------------------------------------------------------- 1 | const tableConfig = { 2 | title: "用户列表", 3 | propList: [ 4 | { prop: "id", label: "id", minWidth: "100" }, 5 | { prop: "name", label: "类别", minWidth: "100" }, 6 | { 7 | prop: "createAt", 8 | label: "创建时间", 9 | minWidth: "250", 10 | slotName: "createAt" 11 | }, 12 | { 13 | prop: "updateAt", 14 | label: "更新时间", 15 | minWidth: "250", 16 | slotName: "updateAt" 17 | }, 18 | { 19 | label: "操作", 20 | minWidth: "120", 21 | slotName: "operation" 22 | } 23 | ], 24 | showTabelIndex: true, 25 | showTabelSelect: true 26 | }; 27 | export default tableConfig; 28 | -------------------------------------------------------------------------------- /src/views/main/product/category/cpn/CategoryHeader.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 30 | 31 | 44 | -------------------------------------------------------------------------------- /src/views/main/product/goods/configs/dialog.config.ts: -------------------------------------------------------------------------------- 1 | import { IForm } from "@/common-ui/msi-form"; 2 | const DialogConfig: IForm = { 3 | formItem: [ 4 | { 5 | field: "name", 6 | type: "input", 7 | label: "商品名称", 8 | placeholder: "请输入商品名字" 9 | }, 10 | { 11 | field: "desc", 12 | type: "input", 13 | label: "商品描述", 14 | placeholder: "请输入商品描述" 15 | }, 16 | { 17 | field: "imgUrl", 18 | type: "upload", 19 | label: "商品图片链接", 20 | placeholder: "请加入商品图片链接" 21 | }, 22 | { 23 | field: "oldPrice", 24 | type: "input", 25 | label: "原价", 26 | placeholder: "请输入商品原价" 27 | }, 28 | { 29 | field: "newPrice", 30 | type: "input", 31 | label: "现价", 32 | placeholder: "请输入商品现价" 33 | }, 34 | { 35 | field: "status", 36 | type: "select", 37 | label: "商品状态", 38 | placeholder: "请选择商品状态", 39 | options: [ 40 | { 41 | title: "上架", 42 | value: 1 43 | }, 44 | { 45 | title: "下架", 46 | value: 2 47 | } 48 | ] 49 | }, 50 | { 51 | field: "inventoryCount", 52 | type: "input", 53 | label: "商品库存件数", 54 | placeholder: "请输入库存件数" 55 | }, 56 | { 57 | field: "saleCount", 58 | type: "input", 59 | label: "商品售卖件数", 60 | placeholder: "请输入商品售卖件数" 61 | }, 62 | { 63 | field: "favorCount", 64 | type: "input", 65 | label: "商品优惠件数", 66 | placeholder: "请输入商品优惠件数" 67 | }, 68 | { 69 | field: "address", 70 | type: "input", 71 | label: "商品地址", 72 | placeholder: "请输入商品地址" 73 | } 74 | ], 75 | colLayout: { 76 | span: 24 77 | }, 78 | labelWidth: "130px", 79 | itemStyle: { 80 | padding: "5px 10px" 81 | } 82 | }; 83 | 84 | export default DialogConfig; 85 | -------------------------------------------------------------------------------- /src/views/main/product/goods/configs/tabel.config.ts: -------------------------------------------------------------------------------- 1 | const tableConfigList = { 2 | title: "商品列表", 3 | propList: [ 4 | { prop: "name", label: "商品名", minWidth: "100" }, 5 | { prop: "oldPrice", label: "原价", minWidth: "50" }, 6 | { prop: "newPrice", label: "现价", minWidth: "50" }, 7 | { prop: "imgUrl", label: "商品展示", minWidth: "80", slotName: "imgUrl" }, 8 | { prop: "inventoryCount", label: "剩余库存", minWidth: "80" }, 9 | { prop: "saleCount", label: "已售", minWidth: "60" }, 10 | { prop: "favorCount", label: "优惠件数", minWidth: "60" }, 11 | { prop: "address", label: "地址", minWidth: "60" }, 12 | { prop: "status", label: "状态", minWidth: "70", slotName: "status" }, 13 | { 14 | prop: "createAt", 15 | label: "创建时间", 16 | minWidth: "150", 17 | slotName: "createAt" 18 | }, 19 | { 20 | prop: "updateAt", 21 | label: "更新时间", 22 | minWidth: "150", 23 | slotName: "updateAt" 24 | }, 25 | { 26 | label: "操作", 27 | minWidth: "110", 28 | slotName: "operation" 29 | } 30 | ], 31 | showTabelIndex: true, 32 | showTabelSelect: true 33 | }; 34 | export default tableConfigList; 35 | -------------------------------------------------------------------------------- /src/views/main/product/goods/goods.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/views/main/story/chat/chat.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 45 | 46 | 60 | -------------------------------------------------------------------------------- /src/views/main/story/list/config/tabel.config.ts: -------------------------------------------------------------------------------- 1 | const TabelConfig = { 2 | title: "故事列表", 3 | propList: [ 4 | { prop: "id", label: "文章ID", minWidth: "100" }, 5 | { prop: "title", label: "文章标题", minWidth: "100" }, 6 | { prop: "content", label: "文章内容", minWidth: "500" }, 7 | { 8 | prop: "createAt", 9 | label: "创建时间", 10 | minWidth: "250", 11 | slotName: "createAt" 12 | } 13 | ], 14 | showTabelIndex: true, 15 | showTabelSelect: true 16 | }; 17 | 18 | export default TabelConfig; 19 | -------------------------------------------------------------------------------- /src/views/main/story/list/list.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 29 | 30 | 41 | -------------------------------------------------------------------------------- /src/views/main/system/department/config/dialog.config.ts: -------------------------------------------------------------------------------- 1 | import { IDialog } from "@/components/page-dialog/types/types"; 2 | 3 | const DialogConfig: IDialog = { 4 | formItem: [ 5 | { 6 | field: "name", 7 | type: "input", 8 | label: "部门名称", 9 | placeholder: "请输入部门名称..." 10 | }, 11 | { 12 | field: "leader", 13 | type: "input", 14 | label: "部门领导", 15 | placeholder: "请输入部门领导..." 16 | }, 17 | { 18 | field: "parentId", 19 | type: "select", 20 | label: "隶属部门", 21 | placeholder: "请输入部门领导...", 22 | options: [ 23 | { 24 | title: "1", 25 | value: 1 26 | }, 27 | { 28 | title: "2", 29 | value: 2 30 | } 31 | ] 32 | } 33 | ], 34 | colLayout: { 35 | span: 24 36 | } 37 | }; 38 | 39 | export default DialogConfig; 40 | -------------------------------------------------------------------------------- /src/views/main/system/department/config/from.config.ts: -------------------------------------------------------------------------------- 1 | import { IForm } from "@/common-ui/msi-form/types/types"; 2 | 3 | const FormConfig: IForm = { 4 | formItem: [ 5 | { 6 | field: "name", 7 | label: "部门名称", 8 | type: "input", 9 | placeholder: "请输入部门名称..." 10 | }, 11 | { 12 | field: "createAt", 13 | type: "datapicker", 14 | label: "创建日期", 15 | otherOptions: { 16 | startPlaceholder: "开始时间", 17 | endPlaceholder: "结束时间", 18 | type: "daterange" 19 | } 20 | }, 21 | { 22 | field: "leader", 23 | label: "部门管理", 24 | type: "input", 25 | placeholder: "请输入部门管理人.." 26 | } 27 | ], 28 | labelWidth: "120px", 29 | itemStyle: { 30 | padding: "10px 40px" 31 | } 32 | }; 33 | 34 | export default FormConfig; 35 | -------------------------------------------------------------------------------- /src/views/main/system/department/config/tabel.config.ts: -------------------------------------------------------------------------------- 1 | const TabelConfig = { 2 | propList: [ 3 | { prop: "id", label: "部门id", minWidth: "100" }, 4 | { prop: "name", label: "部门名称", minWidth: "100" }, 5 | { 6 | prop: "createAt", 7 | label: "创建时间", 8 | minWidth: "250", 9 | slotName: "createAt" 10 | }, 11 | { 12 | prop: "updateAt", 13 | label: "更新时间", 14 | minWidth: "250", 15 | slotName: "updateAt" 16 | }, 17 | { 18 | prop: "leader", 19 | label: "部门领导", 20 | minWidth: "120", 21 | slotName: "operation" 22 | } 23 | ], 24 | showTabelIndex: true, 25 | showTabelSelect: true 26 | }; 27 | 28 | export default TabelConfig; 29 | -------------------------------------------------------------------------------- /src/views/main/system/department/department.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 66 | 67 | 74 | -------------------------------------------------------------------------------- /src/views/main/system/menu/configs/dialog.config.ts: -------------------------------------------------------------------------------- 1 | import { IDialog } from "@/components/page-dialog"; 2 | const DialogConfig: IDialog = { 3 | title: "新建菜单", 4 | formItem: [ 5 | { 6 | field: "name", 7 | label: "菜单名字", 8 | type: "input", 9 | placeholder: "请输入菜单名字" 10 | }, 11 | { 12 | field: "type", 13 | label: "菜单类别", 14 | type: "select", 15 | options: [ 16 | { 17 | title: "一级菜单", 18 | value: 1 19 | }, 20 | { 21 | title: "二级菜单", 22 | value: 2 23 | } 24 | ] 25 | }, 26 | { 27 | field: "url", 28 | label: "菜单路径", 29 | type: "input", 30 | placeholder: "请输入菜单路径" 31 | }, 32 | { 33 | field: "parentId", 34 | label: "父菜单", 35 | type: "select", 36 | placeholder: "默认创建一级菜单", 37 | options: [] 38 | } 39 | ], 40 | colLayout: { 41 | span: 24 42 | } 43 | }; 44 | 45 | export default DialogConfig; 46 | -------------------------------------------------------------------------------- /src/views/main/system/menu/configs/tabel.config.ts: -------------------------------------------------------------------------------- 1 | const tableConfigList = { 2 | title: "菜单列表", 3 | propList: [ 4 | { prop: "name", label: "菜单名称", minWidth: "100" }, 5 | { prop: "icon", label: "菜单图标", minWidth: "150" }, 6 | { prop: "url", label: "菜单路径", minWidth: "200" }, 7 | { prop: "type", label: "类型", minWidth: "100", slotName: "status" }, 8 | { 9 | prop: "createAt", 10 | label: "创建时间", 11 | minWidth: "250", 12 | slotName: "createAt" 13 | }, 14 | { 15 | prop: "updateAt", 16 | label: "更新时间", 17 | minWidth: "250", 18 | slotName: "updateAt" 19 | }, 20 | { 21 | label: "操作", 22 | minWidth: "120", 23 | slotName: "operation" 24 | } 25 | ], 26 | childrenProps: { 27 | rowKey: "id", 28 | treeProps: { 29 | children: "children" 30 | } 31 | }, 32 | showTabelIndex: false, 33 | showTabelSelect: false, 34 | showPagination: false 35 | }; 36 | export default tableConfigList; 37 | -------------------------------------------------------------------------------- /src/views/main/system/menu/menu.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/views/main/system/role/config/dialog.config.ts: -------------------------------------------------------------------------------- 1 | import { IForm } from "@/common-ui/msi-form"; 2 | const DialogConfig: IForm = { 3 | formItem: [ 4 | { 5 | field: "name", 6 | type: "input", 7 | label: "角色名", 8 | placeholder: "请输入角色介绍" 9 | }, 10 | { 11 | field: "intro", 12 | type: "input", 13 | label: "角色介绍", 14 | placeholder: "请输入角色介绍" 15 | } 16 | ], 17 | colLayout: { 18 | span: 24 19 | } 20 | }; 21 | 22 | export default DialogConfig; 23 | -------------------------------------------------------------------------------- /src/views/main/system/role/config/form.config.ts: -------------------------------------------------------------------------------- 1 | import type { IForm } from "@/common-ui/msi-form"; 2 | const formInfo: IForm = { 3 | formItem: [ 4 | { 5 | field: "name", 6 | type: "input", 7 | label: "角色名称", 8 | placeholder: "请输入角色名称..." 9 | }, 10 | { 11 | field: "intro", 12 | type: "input", 13 | label: "权限", 14 | placeholder: "请输入权限..." 15 | }, 16 | { 17 | field: "createTime", 18 | type: "datapicker", 19 | label: "创建日期", 20 | otherOptions: { 21 | startPlaceholder: "开始时间", 22 | endPlaceholder: "结束时间", 23 | type: "daterange" 24 | } 25 | } 26 | ], 27 | labelWidth: "120px", 28 | itemStyle: { 29 | padding: "10px 40px" 30 | } 31 | }; 32 | export default formInfo; 33 | -------------------------------------------------------------------------------- /src/views/main/system/role/config/tabel.config.ts: -------------------------------------------------------------------------------- 1 | const tableConfigList = { 2 | title: "角色管理", 3 | propList: [ 4 | { prop: "name", label: "角色名", minWidth: "100" }, 5 | { prop: "intro", label: "权限", minWidth: "100" }, 6 | { 7 | prop: "createAt", 8 | label: "创建时间", 9 | minWidth: "250", 10 | slotName: "createAt" 11 | }, 12 | { 13 | prop: "updateAt", 14 | label: "更新时间", 15 | minWidth: "250", 16 | slotName: "updateAt" 17 | }, 18 | { 19 | label: "操作", 20 | minWidth: "120", 21 | slotName: "operation" 22 | } 23 | ], 24 | showTabelIndex: true, 25 | showTabelSelect: true 26 | }; 27 | export default tableConfigList; 28 | -------------------------------------------------------------------------------- /src/views/main/system/role/role.vue: -------------------------------------------------------------------------------- 1 | 38 | 39 | 107 | 108 | 118 | -------------------------------------------------------------------------------- /src/views/main/system/user/configs/dialog.config.ts: -------------------------------------------------------------------------------- 1 | import { IForm } from "@/common-ui/msi-form"; 2 | 3 | const DialogConfig: IForm = { 4 | formItem: [ 5 | { 6 | field: "name", 7 | label: "用户名", 8 | type: "input", 9 | placeholder: "请输入用户名" 10 | }, 11 | { 12 | field: "realname", 13 | label: "真实姓名", 14 | type: "input", 15 | placeholder: "请输入真实姓名" 16 | }, 17 | { 18 | field: "password", 19 | label: "密码", 20 | type: "password", 21 | placeholder: "请输入密码", 22 | isHidden: true 23 | }, 24 | { 25 | field: "cellphone", 26 | label: "手机号码", 27 | type: "input", 28 | placeholder: "请输入手机号码" 29 | }, 30 | { 31 | field: "roleId", 32 | label: "角色", 33 | type: "select", 34 | placeholder: "请选择角色", 35 | options: [] 36 | }, 37 | { 38 | field: "departmentId", 39 | label: "部门", 40 | type: "select", 41 | placeholder: "请选择部门", 42 | options: [] 43 | } 44 | ], 45 | colLayout: { 46 | span: 24 47 | } 48 | }; 49 | 50 | export default DialogConfig; 51 | -------------------------------------------------------------------------------- /src/views/main/system/user/configs/form.config.ts: -------------------------------------------------------------------------------- 1 | import type { IForm } from "@/common-ui/msi-form"; 2 | const formInfo: IForm = { 3 | formItem: [ 4 | { 5 | field: "id", 6 | type: "input", 7 | label: "id", 8 | placeholder: "请输入id..." 9 | }, 10 | { 11 | field: "name", 12 | type: "input", 13 | label: "用户名", 14 | placeholder: "请输入用户名..." 15 | }, 16 | { 17 | field: "realname", 18 | type: "input", 19 | label: "真实姓名", 20 | placeholder: "请输入真实姓名..." 21 | }, 22 | { 23 | field: "cellphone", 24 | type: "input", 25 | label: "手机号码", 26 | placeholder: "请输入手机号码..." 27 | }, 28 | { 29 | field: "enable", 30 | type: "select", 31 | label: "状态", 32 | placeholder: "请进行选择...", 33 | options: [ 34 | { 35 | title: "停用", 36 | value: 1 37 | }, 38 | { 39 | title: "启用", 40 | value: 0 41 | } 42 | ] 43 | }, 44 | { 45 | field: "createAt", 46 | type: "datapicker", 47 | label: "创建日期", 48 | otherOptions: { 49 | startPlaceholder: "开始时间", 50 | endPlaceholder: "结束时间", 51 | type: "daterange" 52 | } 53 | } 54 | ], 55 | labelWidth: "120px", 56 | itemStyle: { 57 | padding: "10px 40px" 58 | } 59 | }; 60 | export default formInfo; 61 | -------------------------------------------------------------------------------- /src/views/main/system/user/configs/tabel.config.ts: -------------------------------------------------------------------------------- 1 | const tableConfigList = { 2 | title: "用户列表", 3 | propList: [ 4 | { prop: "name", label: "用户名", minWidth: "100" }, 5 | { prop: "realname", label: "真实性名", minWidth: "100" }, 6 | { prop: "cellphone", label: "手机号码", minWidth: "100" }, 7 | { prop: "enable", label: "状态", minWidth: "100", slotName: "status" }, 8 | { 9 | prop: "createAt", 10 | label: "创建时间", 11 | minWidth: "250", 12 | slotName: "createAt" 13 | }, 14 | { 15 | prop: "updateAt", 16 | label: "更新时间", 17 | minWidth: "250", 18 | slotName: "updateAt" 19 | }, 20 | { 21 | label: "操作", 22 | minWidth: "120", 23 | slotName: "operation" 24 | } 25 | ], 26 | showTabelIndex: true, 27 | showTabelSelect: true 28 | }; 29 | export default tableConfigList; 30 | -------------------------------------------------------------------------------- /src/views/main/system/user/user.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 119 | 120 | 128 | -------------------------------------------------------------------------------- /src/views/not-found/NotFound.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "skipLibCheck": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": ["webpack-env"], 15 | "paths": { 16 | "@/*": ["src/*"] 17 | }, 18 | "lib": ["esnext", "dom", "dom.iterable", "scripthost"] 19 | }, 20 | "include": [ 21 | "src/**/*.ts", 22 | "src/**/*.tsx", 23 | "src/**/*.vue", 24 | "tests/**/*.ts", 25 | "tests/**/*.tsx" 26 | ], 27 | "exclude": ["node_modules"] 28 | } 29 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | module.exports = { 3 | configureWebpack: { 4 | resolve: { 5 | alias: { 6 | "@": path.resolve(__dirname, "src"), 7 | view: "@/view", 8 | router: "@/router", 9 | components: "@/components", 10 | assets: "@/assets" 11 | } 12 | } 13 | }, 14 | devServer: { 15 | proxy: { 16 | "/api": { 17 | target: "http://152.136.185.210:4000", 18 | pathRewrite: { 19 | "^/api": "" 20 | }, 21 | changeOrigin: true 22 | } 23 | } 24 | }, 25 | publicPath: "./", // 注意 这里使用 / 如果不行的话 就 ./ 26 | outputDir: "dist", // 包名 27 | assetsDir: "static" 28 | }; 29 | --------------------------------------------------------------------------------