├── .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 | 
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 |
13 |
16 |
17 |
21 |
22 |
25 |
26 |
29 |
30 |
33 |
34 |
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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
4 |
5 | {{
6 | item.name
7 | }}
8 |
9 |
10 |
11 |
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 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
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 |
2 |
3 |
4 |
5 |
11 |
12 | {{ item.name }}
13 |
14 | {{ item.description }}
15 |
16 |
17 |
18 |
19 |
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 |
2 |
8 |
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 |
2 |
6 |
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 |
2 |
64 |
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 |
2 |
3 |
13 |
20 |
27 |
33 |
34 |
40 |
41 | {{
42 | scope.row[title.prop]
43 | }}
44 |
45 |
46 |
47 |
48 |
62 |
63 |
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 |
2 |
3 |
13 |
14 | 选取文件
15 |
16 | 上传到服务器
23 |
24 |
25 |
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 |
2 |
38 |
39 |
40 |
113 |
114 |
154 |
--------------------------------------------------------------------------------
/src/components/nav-header/src/cpn/NavDialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | QQ
6 |
7 |
8 |
9 | WeiChat
10 |
11 |
12 |
13 |
14 | 项目详细开发过程文档(请点击下方连接)
16 |
17 | Vue3+TS管理系统开发流程
21 |
22 |
23 | 时间
24 |
30 | 和我一起来学习前端吧
31 |
32 |
33 |
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 |
2 |
39 |
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 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/components/page-echart/src/PageChinaChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/src/components/page-echart/src/PageLineChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/components/page-echart/src/PagePicChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/components/page-echart/src/PagePicLableChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
73 |
74 |
80 |
--------------------------------------------------------------------------------
/src/components/page-echart/src/PageRoseChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
4 |
5 | 检索
6 |
7 |
8 | 提交
14 | 重置
17 |
18 |
19 |
20 |
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 |
2 |
3 |
10 |
11 |
17 | 删除多条
18 |
19 | 新建数据
26 |
27 |
28 | {{ $formatUTC(scope.row.createAt) }}
29 |
30 |
31 | {{ $formatUTC(scope.row.updateAt) }}
32 |
33 |
34 |
41 | 编辑
42 |
43 |
50 | 删除
51 |
52 |
53 |
58 |
59 |
60 |
61 |
62 |
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 |
2 |
3 |
4 |
后台管理系统
5 |
6 |
7 |
8 | 用户名登陆
9 |
10 |
11 |
12 |
13 |
14 | 手机号登陆
15 |
16 |
17 |
18 |
19 |
20 | 记住密码
21 | 忘记密码
22 |
23 |
立即登陆
26 |
27 |
28 |
29 |
30 |
63 |
64 |
96 |
--------------------------------------------------------------------------------
/src/views/login/cpns/LoginPhone.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | 获取验证码
17 |
18 |
19 |
20 |
21 |
22 |
23 |
48 |
49 |
62 |
--------------------------------------------------------------------------------
/src/views/login/cpns/LoginUser.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
112 |
113 |
118 |
--------------------------------------------------------------------------------
/src/views/main/analysis/dashboard/cpn/ShowCount.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{ item.title }}
9 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
72 |
73 |
114 |
--------------------------------------------------------------------------------
/src/views/main/analysis/dashboard/dashboard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
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 |
2 |
3 |
4 |
5 | VueTsCMS 是基于Vue3、Vuex、VueRouter、VueCLI、 ElementPlus 、TypeScript、Echart5 等后台系统解决方案。
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 | {{ TreeOptions }}
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
60 |
61 |
85 |
--------------------------------------------------------------------------------
/src/views/main/product/category/category.vue:
--------------------------------------------------------------------------------
1 |
2 |
24 |
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 |
2 |
10 |
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 |
2 |
3 |
9 |
10 |
15 |
16 |
17 |
18 | {{ scope.row.status === 2 ? "启用" : "停用" }}
24 |
25 |
26 |
32 |
33 |
34 |
35 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/views/main/story/chat/chat.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
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 |
2 |
9 |
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 |
2 |
26 |
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 |
2 |
16 |
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 |
2 |
3 |
8 |
17 |
24 |
34 |
35 |
36 |
37 |
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 |
2 |
3 |
8 |
9 |
16 |
17 | {{ scope.row.enabel === 2 ? "启用" : "停用" }}
23 |
24 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
119 |
120 |
128 |
--------------------------------------------------------------------------------
/src/views/not-found/NotFound.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
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 |
--------------------------------------------------------------------------------