├── .env.development
├── .env.production
├── .gitignore
├── LICENSE
├── README.md
├── config
├── base.conf.js
├── dev.conf.js
├── index.js
└── prod.conf.js
├── index.html
├── package.json
├── pictures
├── 1.png
├── 2.png
├── 3.png
├── 4.png
└── 5.png
├── public
└── favicon.ico
├── server
├── app.js
├── log.js
├── router
│ ├── about.js
│ ├── data.js
│ ├── home.js
│ ├── index.js
│ └── user.js
└── utils
│ └── index.js
├── src
├── App.vue
├── api
│ ├── about.ts
│ ├── data.ts
│ ├── home.ts
│ └── login.ts
├── assets
│ ├── css
│ │ ├── base.css
│ │ ├── global.scss
│ │ └── variables.scss
│ ├── iconfont
│ │ ├── demo.css
│ │ ├── demo_index.html
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.js
│ │ ├── iconfont.json
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ └── iconfont.woff2
│ ├── images
│ │ ├── bg.jpeg
│ │ └── profile.jpg
│ └── logo.png
├── components
│ ├── au-header.vue
│ ├── au-input.vue
│ ├── au-layout-empty.vue
│ ├── au-layout.vue
│ ├── au-nav.vue
│ ├── au-pagination.ts
│ └── au-screen.ts
├── icons
│ └── svg
│ │ ├── g1.svg
│ │ ├── g2.svg
│ │ ├── g3.svg
│ │ ├── g4.svg
│ │ ├── g5.svg
│ │ ├── g6.svg
│ │ ├── g7.svg
│ │ ├── v1.svg
│ │ ├── v2.svg
│ │ ├── v3.svg
│ │ ├── v4.svg
│ │ ├── v5.svg
│ │ ├── v6.svg
│ │ ├── v7.svg
│ │ ├── v8.svg
│ │ └── v9.svg
├── main.ts
├── plugins
│ ├── axios.ts
│ ├── element-ui.ts
│ ├── index.ts
│ ├── router.ts
│ └── store.ts
├── router
│ ├── index.ts
│ └── permision.ts
├── shims-vue.d.ts
├── store
│ ├── actions.ts
│ ├── getters.ts
│ ├── index.ts
│ ├── mutations.ts
│ ├── state.ts
│ └── types.ts
├── utils
│ ├── _ls.ts
│ ├── _sign.ts
│ └── index.ts
└── views
│ ├── about
│ ├── au-message.vue
│ ├── au-produce.vue
│ ├── au-record.vue
│ └── index.vue
│ ├── data
│ ├── au-list.vue
│ ├── au-rank.vue
│ ├── chart-config.js
│ ├── index.vue
│ └── rank.vue
│ ├── error
│ └── 404.vue
│ ├── home
│ ├── index.vue
│ └── notice.vue
│ ├── login
│ └── index.vue
│ └── profile
│ ├── au-profile-mobile.vue
│ ├── au-profile-pc.vue
│ ├── au-upload.ts
│ ├── config.js
│ └── index.vue
└── tsconfig.json
/.env.development:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | VITE_BASE_URL=/au/api
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | NODE_ENV=production
2 | VITE_BASE_URL=http://47.243.59.143:8089/api/
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | dist
4 | dist-ssr
5 | *.local
6 | package-lock.json
7 | /server/log
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 coderly
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vue 3 + Typescript + Vite + Vuex + Vue-Router
2 |
3 | This template should help get you started developing with Vue 3 and Typescript and Vuex and Vue-Router in Vite.
4 |
5 |
6 | # Introduction ⚡
7 |
8 | > all about
9 |
10 | - 💡 Vue 3.x
11 | - ⚡️ Typescript
12 | - 🛠️ Vite 2.x
13 | - 📦 Vuex 4.x
14 | - 🔩 Vue-Router 4.x
15 | - 🔑 Md5 And Sign Provide Transmission For Website Security
16 | - 👍 Mock In Development
17 | - 🔖 Iconfont And Svg
18 | - 🔍 Element-plus UI
19 | - 📌 And More...
20 |
21 | ## Some pages
22 | 
23 | 
24 | 
25 | 
26 | 
27 |
28 | # Start
29 | 1. `npm install`
30 | 2. `npm run dev`
--------------------------------------------------------------------------------
/config/base.conf.js:
--------------------------------------------------------------------------------
1 |
2 | import vue from '@vitejs/plugin-vue'
3 | import svgLoader from 'vite-svg-loader'
4 | import styleImport from 'vite-plugin-style-import'
5 | const path = require('path')
6 |
7 | export default {
8 | root: process.cwd(),
9 | publicDir: 'public',
10 | logLevel: 'error',
11 | envDir: process.cwd(),
12 | resolve: {
13 | alias: {
14 | '@': path.resolve(process.cwd(), 'src'),
15 | 'views': path.resolve(process.cwd(), 'src/views'),
16 | }
17 | },
18 | css: {
19 | postcss: {
20 | plugins: [require('autoprefixer')]
21 | },
22 | // 引入全局 scss
23 | preprocessorOptions: {
24 | scss: {
25 | additionalData: "@import './src/assets/css/global.scss';"
26 | }
27 | }
28 | },
29 | plugins: [
30 | vue(),
31 | styleImport({
32 | libs: [{
33 | libraryName: 'element-plus',
34 | esModule: true,
35 | ensureStyleFile: true,
36 | resolveStyle: (name) => {
37 | return `element-plus/lib/theme-chalk/${name}.css`
38 | },
39 | resolveComponent: (name) => {
40 | return `element-plus/lib/${name}`;
41 | }
42 | }]
43 | }),
44 | svgLoader()
45 | ]
46 | }
--------------------------------------------------------------------------------
/config/dev.conf.js:
--------------------------------------------------------------------------------
1 |
2 | import { merge } from 'lodash'
3 | import baseConfig from './base.conf.js'
4 |
5 | const devConfig = {
6 | mode: 'development',
7 | logLevel: 'error',
8 | clearScreen: false, // 不会清空上一次控制台打印信息
9 | server: {
10 | host: '127.0.0.1',
11 | open: true,
12 | port: 3030,
13 | strictPort: true, // 若端口已被占用则会直接退出,而不是尝试下一个可用端口
14 | force: true, // 强制使依赖预构建
15 | proxy: {
16 | '/au': {
17 | target: 'http://localhost:8089',
18 | changeOrigin: true,
19 | rewrite: (path) => path.replace(/^\/au/, '')
20 | }
21 | }
22 | }
23 | }
24 | export default function devConfigFunc() {
25 | return merge(devConfig, baseConfig)
26 | }
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | import dev from './dev.conf.js'
2 | import prod from './prod.conf.js'
3 | export default (({ mode }) => {
4 | if (mode === 'development') {
5 | return dev()
6 | } else {
7 | console.info('当前模式为:', mode)
8 | return prod()
9 | }
10 | })
--------------------------------------------------------------------------------
/config/prod.conf.js:
--------------------------------------------------------------------------------
1 | import baseConfig from './base.conf.js'
2 | import { merge } from 'lodash'
3 | const packJson = require('../package.json')
4 | const execSync = require('child_process').execSync // 同步子进程
5 | let date = new Date(execSync('git show -s --format=%cd').toString())
6 | let ref = execSync('git show -s --format=%D').toString().trim()
7 | let hash = execSync('git show -s --format=%H').toString().trim()
8 |
9 | /** 格式化 - 日期 */
10 | function formatDate(t) {
11 | let year = t.getFullYear()
12 | let month = t.getMonth()
13 | let day = t.getDate()
14 | let h = t.getHours()
15 | let m = t.getMinutes()
16 | let s = t.getSeconds()
17 | month = month < 10 ? '0' + month : month
18 | day = day < 10 ? '0' + day : day
19 | h = h < 10 ? '0' + h : h
20 | m = m < 10 ? '0' + m : m
21 | s = s < 10 ? '0' + s : s
22 | return `${year}-${month}-${day} ${h}:${m}:${s}`
23 | }
24 | /** 格式化 - 当前分支信息 */
25 | function currentRef(str) {
26 | let fs = str.split(',')
27 | let s = fs.filter((s) => s.indexOf('->') !== -1)[0]
28 | return s.slice(s.indexOf('->') + 2)
29 | }
30 |
31 | let messages = '/*' + Buffer.from(`ref: ${currentRef(ref)}, date: ${formatDate(date)}, hash: ${hash}, project: -name- ${packJson.name} -v- ${packJson.version}`).toString('base64') + '*/'
32 |
33 | const prodConfig = {
34 | mode: 'production',
35 | logLevel: 'info',
36 | build: {
37 | target: 'modules',
38 | polyfillDynamicImport: true, // 自动注入 动态导入 polyfill
39 | outDir: 'dist',
40 | assetsDir: 'assets',
41 | assetsInlineLimit: 8192, // 小于 8kb 的导入或引用资源将内联为 base64 编码
42 | cssCodeSplit: false, // 在异步 chunk 中导入的 CSS 将内联到异步 chunk 本身,并在其被加载时插入
43 | sourcemap: false, // 构建后是否生成 source map 文件
44 | rollupOptions: {
45 | output: {
46 | banner: messages,
47 | manualChunks: {
48 | lodash: ['lodash'],
49 | echarts: ['echarts'],
50 | // axios: ['axios'],
51 | // nprogress: ['nprogress'],
52 | // vue: ['vue'],
53 | 'element-plus': ['element-plus']
54 | }
55 | }
56 | },
57 | minify: 'terser',
58 | chunkSizeWarningLimit: 800, // chunk 大小警告的限制
59 | }
60 | }
61 |
62 | export default function prodConfigFunc() {
63 | return merge(prodConfig, baseConfig)
64 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
13 |
14 |
15 | 后台管理模板
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-frontend-template",
3 | "version": "1.0.0",
4 | "keywords": [
5 | "vue",
6 | "vue3.x",
7 | "vite",
8 | "vite2.x",
9 | "typescript",
10 | "element-plus",
11 | "vuex",
12 | "vuex4.x",
13 | "vue-router",
14 | "vue-router4.x",
15 | "md5",
16 | "axios",
17 | "echarts",
18 | "svg",
19 | "template",
20 | "front-end",
21 | "vue模板",
22 | "admin-template",
23 | "后台管理模板",
24 | "管理"
25 | ],
26 | "description": "a front end template development by vue3.x and typescript and vite2.x and vuex4.x and vue-router 4.x and mock and element-plus",
27 | "main": "./src/main.ts",
28 | "license": "MIT",
29 | "author": {
30 | "name": "刘誉",
31 | "email": "974257574@qq.com"
32 | },
33 | "scripts": {
34 | "dev": "concurrently \"npm run dev:e \" \"npm run dev:f\"",
35 | "dev:f": "vite --mode development --config ./config/index.js",
36 | "dev:e": "node ./server/app.js",
37 | "build": "vite build --mode production --config ./config/index.js",
38 | "serve": "vite preview"
39 | },
40 | "dependencies": {
41 | "axios": "^0.21.1",
42 | "concurrently": "^6.2.0",
43 | "echarts": "^5.0.2",
44 | "element-plus": "^1.0.2-beta.32",
45 | "koa": "^2.13.4",
46 | "koa-body": "^5.0.0",
47 | "koa-router": "^10.1.1",
48 | "koa2-cors": "^2.0.6",
49 | "lodash": "^4.17.21",
50 | "log4js": "^6.4.6",
51 | "mockjs": "^1.1.0",
52 | "nprogress": "^0.2.0",
53 | "qs": "^6.10.1",
54 | "vite-plugin-mockit": "^1.0.1",
55 | "vue": "^3.0.5",
56 | "vue-router": "^4.0.4",
57 | "vuex": "^4.0.0"
58 | },
59 | "devDependencies": {
60 | "@types/js-md5": "^0.4.2",
61 | "@types/node": "^14.14.31",
62 | "@types/nprogress": "^0.2.0",
63 | "@types/qs": "^6.9.5",
64 | "@vitejs/plugin-vue": "^1.1.4",
65 | "@vue/compiler-sfc": "^3.0.5",
66 | "autoprefixer": "^10.2.6",
67 | "js-md5": "^0.7.3",
68 | "less": "^4.1.1",
69 | "nodemon": "^2.0.16",
70 | "postcss": "^8.3.0",
71 | "sass": "^1.32.8",
72 | "typescript": "^4.1.3",
73 | "vite": "^2.0.1",
74 | "vite-plugin-style-import": "^0.7.3",
75 | "vite-svg-loader": "^1.4.2"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/pictures/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/pictures/1.png
--------------------------------------------------------------------------------
/pictures/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/pictures/2.png
--------------------------------------------------------------------------------
/pictures/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/pictures/3.png
--------------------------------------------------------------------------------
/pictures/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/pictures/4.png
--------------------------------------------------------------------------------
/pictures/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/pictures/5.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/public/favicon.ico
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | const Koa = require('koa')
2 | const cors = require('koa2-cors')
3 | const app = new Koa()
4 |
5 | app.use(cors())
6 | require('./router/index.js')(app)
7 |
8 | app.listen(8089, (error) => {
9 | if (!error) {
10 | console.log('server is running at http://localhost:8089')
11 | }
12 | })
--------------------------------------------------------------------------------
/server/log.js:
--------------------------------------------------------------------------------
1 | const log4js = require('log4js')
2 | const path = require('path')
3 |
4 | const config = {
5 | appenders: {
6 | default: {
7 | type: 'dateFile',
8 | keepFileExt: true,
9 | filename: path.resolve(__dirname, './log/default.log')
10 | },
11 | koaRoute: {
12 | type: 'dateFile',
13 | keepFileExt: true,
14 | filename: path.resolve(__dirname, './log/koaRoute.log')
15 | },
16 | success: {
17 | type: 'dateFile',
18 | keepFileExt: true,
19 | filename: path.resolve(__dirname, './log/success.log')
20 | }
21 | },
22 | categories: {
23 | default: { appenders: ['default'], level: 'debug' },
24 | koaRoute: { appenders: ['koaRoute'], level: 'info' },
25 | success: { appenders: ['success'], level: 'all' }
26 | }
27 | }
28 |
29 | log4js.configure(config)
30 | const koaLogger = log4js.getLogger('koaRoute')
31 | const logger = log4js.getLogger()
32 | const successLogger = log4js.getLogger('success')
33 |
34 | module.exports = {
35 | koaLogger,
36 | logger,
37 | successLogger
38 | }
--------------------------------------------------------------------------------
/server/router/about.js:
--------------------------------------------------------------------------------
1 | const mockjs = require('mockjs')
2 | const utils = require('../utils/index.js')
3 |
4 | async function actives(ctx) {
5 | const { limit = 10, page = 1 } = ctx.request.query
6 | const data = mockjs.mock({
7 | [`data|${limit}`]: [
8 | {
9 | "id|+1": 1,
10 | "imgUrl|1": [
11 | "https://pic3.zhimg.com/v2-03371b64a1da395c519938e65965ff61.jpg?source=8c23436a",
12 | "https://pic4.zhimg.com/v2-f93156f6bd568c80d5e2d54833286550.jpg?source=8c23436a",
13 | "https://pic2.zhimg.com/v2-37852e07af93ea1675d8cd50a699f4ff.jpg?source=8c23436a",
14 | "https://pic4.zhimg.com/v2-400ebc21c25b0b7bb0740e6e25a7b1c5.jpg?source=8c23436a",
15 | "https://pic2.zhimg.com/v2-ce896400cea15a93a05bc6b0188b668c.jpg?source=8c23436a",
16 | "https://pic1.zhimg.com/v2-456a0f551ce75a8d5adab52e6413ab1d.jpg?source=8c23436a",
17 | "https://pic4.zhimg.com/v2-a73ecc1ba6adedb07c21b85937560192.jpg?source=8c23436a",
18 | ],
19 | "url": "",
20 | "time": () =>`${mockjs.Random.date('yyyy 年 MM 月 dd 日')} - ${mockjs.Random.date('yyyy 年 MM 月 dd 日')}`
21 | }
22 | ]
23 | })
24 | utils.errorHandle(ctx, 200, '获取公告列表成功', data.data, { total: 88 })
25 | }
26 |
27 | async function messages(ctx) {
28 | const { limit = 10, page = 1 } = ctx.request.query
29 | const data = mockjs.mock({
30 | [`data|${limit}`]: [
31 | {
32 | "id|+1": 1,
33 | "label|1": ["【系统通知】", '', '【自动触发】', '【科技】', '【新闻】'],
34 | "title|1": ["该系统将于今晚凌晨2点到5点进行升级维护", '好友给你发来一条元宵祝福', '你的文章被评为年度优秀作品', 'xx炮轰安卓高抽成,称其对产业生态非常不利', '旧代码获新生!AI 重写的应用程序可用于最新计算平台', '今天你打到车了吗?滴滴突然崩了,司机接不到人、乘客付不了钱', '技术写作技巧分享:我是如何从写作小白成长为多平台优秀作者的?'],
35 | "time": () => mockjs.Random.date('yyyy-MM-dd HH:mm:ss')
36 | }
37 | ]
38 | })
39 | utils.errorHandle(ctx, 200, '获取列表成功', data.data, { total: 120 })
40 | }
41 |
42 | async function records(ctx) {
43 | const { limit = 10, page = 1 } = ctx.request.query
44 | const data = mockjs.mock({
45 | [`data|${limit}`]: [
46 | {
47 | "id|+1": 1,
48 | "date": () => mockjs.Random.date('yyyy/MM/dd'),
49 | "time": () => mockjs.Random.date('HH:mm:ss'),
50 | "author|1": ["coderly", '立方体转移工程师', '空间物质转移监督员', '黑白黄的猫'],
51 | "operation|1": ["修改密码", '添加系统管理员', '发布作品', '删除管理员']
52 | }
53 | ]
54 | })
55 | utils.errorHandle(ctx, 200, '获取列表成功', data.data, { total: 120 })
56 | }
57 |
58 | module.exports = {
59 | actives,
60 | messages,
61 | records
62 | }
--------------------------------------------------------------------------------
/server/router/data.js:
--------------------------------------------------------------------------------
1 | const mockjs = require('mockjs')
2 | const utils = require('../utils/index.js')
3 |
4 | async function list(ctx) {
5 | const { limit = 10, page = 1 } = ctx.request.body
6 |
7 | const data = mockjs.mock({
8 | [`data|${limit}`]: [
9 | {
10 | 'id|+1': 1,
11 | 'name|1': ['品牌任务', '最佳推手', '每日上新', '每日一问'],
12 | 'title|1': ['帖子-流行指南', '帖子-合理熬夜', '热搜-如何写出别人无法维护的代码', '问题-优秀的人自恋程度', '帖子-合格韭菜的自我修养'],
13 | 'imgUrl': 'https://img.alicdn.com/tfs/TB1sbkkXmBYBeNjy0FeXXbnmFXa-280-498.png',
14 | 'content': '分享日常的真人穿搭或专业的教程,对时尚有自己的理解,能够给消费者提供时尚搭配心得',
15 | 'link|1': ['好的长文章应该怎么写?', '怎么能让别人注意到这里?']
16 | }
17 | ]
18 | })
19 | utils.errorHandle(ctx, 200, '登录成功', data.data, { total: 68 })
20 | }
21 |
22 | async function news(ctx) {
23 | const { limit = 10, page = 1 } = ctx.request.body
24 | const data = mockjs.mock({
25 | [`data|${limit}`]: [
26 | {
27 | 'id|+1': 1,
28 | 'title|1': ['秋季外套', '冬季毛衣', '牛仔裤', '今年流行的毛衣短款', '早春人气爆棚卫衣', '春季宝藏新品外套', '学生党开学必备连衣裙', '不沾杯口红拒绝尴尬', '干饭人必学偷懒菜', '驱魔司带你一起梦长安'],
29 | 'num': () => mockjs.Random.natural(1,1000)
30 | }
31 | ]
32 | })
33 | utils.errorHandle(ctx, 200, '登录成功', data.data)
34 | }
35 |
36 | module.exports = {
37 | list,
38 | news
39 | }
--------------------------------------------------------------------------------
/server/router/home.js:
--------------------------------------------------------------------------------
1 | const mockjs = require('mockjs')
2 | const utils = require('../utils/index.js')
3 |
4 | async function levels(ctx) {
5 | utils.errorHandle(ctx, 200, '获取用户等级成功', mockjs.Random.natural(1, 5))
6 | }
7 |
8 | async function counts(ctx) {
9 | const data = mockjs.mock([
10 | {
11 | "id": 1,
12 | "title": "昨日阅读总数",
13 | "icon": "iconyinzhangrenzheng",
14 | "num": mockjs.Random.natural(1,1000)
15 | },
16 | {
17 | "id": 2,
18 | "title": "昨日赞同总数",
19 | "icon": "iconhaxi",
20 | "num": mockjs.Random.natural(1,1000)
21 | },
22 | {
23 | "id": 3,
24 | "title": "昨日粉丝数",
25 | "icon": "iconliuzhuan",
26 | "num": mockjs.Random.natural(1,1000)
27 | },
28 | {
29 | "id": 4,
30 | "title": "昨日活跃粉丝数",
31 | "icon": "iconqukuai",
32 | "num": mockjs.Random.natural(1,1000)
33 | },
34 | {
35 | "id": 5,
36 | "title": "内容健康度",
37 | "icon": "iconsuyuan",
38 | "num": "90分"
39 | },
40 | {
41 | "id": 6,
42 | "title": "昨日收益",
43 | "icon": "iconshujuku",
44 | "num": "92,340.00"
45 | }
46 | ])
47 | utils.errorHandle(ctx, 200, '获取统计信息成功', data)
48 | }
49 |
50 | async function notices(ctx) {
51 | const { limit = 10, page = 1 } = ctx.request.query
52 | const data = mockjs.mock({
53 | [`data|${limit}`]: [
54 | {
55 | "id|+1": 1,
56 | "tags": () => [
57 | {
58 | "value": 1,
59 | "label": "HOT"
60 | },
61 | {
62 | "value": 2,
63 | "label": "TOP"
64 | },
65 | {
66 | "value": 3,
67 | "label": "NEW"
68 | },
69 | {
70 | "value": 4,
71 | "label": "置顶"
72 | },
73 | {
74 | "value": 5,
75 | "label": "HOT"
76 | }
77 | ].splice(mockjs.Random.natural(0,4), mockjs.Random.natural(0,2)),
78 | "content|1": ["【活动入口已开启】元宵猜灯谜、战胜小龙人一系列活动来袭,快来体验下", '【创作大赛】创作大赛欢迎你的加入', '【征文】发表文章即可'],
79 | "time": () => mockjs.Random.date('yyyy/MM/dd')
80 | }
81 | ]
82 | })
83 | utils.errorHandle(ctx, 200, '获取公告列表成功', data.data, { total: 203 })
84 | }
85 |
86 | module.exports = {
87 | levels,
88 | counts,
89 | notices
90 | }
--------------------------------------------------------------------------------
/server/router/index.js:
--------------------------------------------------------------------------------
1 | const KoaRouter = require('koa-router')
2 | const KoaBody = require('koa-body') // post解析参数并支持附件上传
3 |
4 | const user = require('./user.js')
5 | const data = require('./data.js')
6 | const home = require('./home.js')
7 | const about = require('./about.js')
8 | const router = new KoaRouter()
9 |
10 | /** user */
11 | router.get('/api/user/info', user.info)
12 | .post('/api/user/login', user.login)
13 |
14 | /** data */
15 |
16 | router.get('/api/data/list', data.list)
17 | .get('/api/data/news', data.news)
18 |
19 | /** home */
20 |
21 | router.get('/api/home/levels', home.levels)
22 | .get('/api/home/counts', home.counts)
23 | .get('/api/home/notices', home.notices)
24 |
25 | /** about */
26 |
27 | router.get('/api/about/actives', about.actives)
28 | .get('/api/about/messages', about.messages)
29 | .get('/api/about/records', about.records)
30 |
31 | module.exports = function useRoutes(app) {
32 | app.use(KoaBody({
33 | multipart: true, // 支持文件上传
34 | }))
35 | app.use(router.routes())
36 | app.use(router.allowedMethods())
37 | }
--------------------------------------------------------------------------------
/server/router/user.js:
--------------------------------------------------------------------------------
1 | const mockjs = require('mockjs')
2 | const md5 = require('js-md5')
3 | const utils = require('../utils/index.js')
4 |
5 | async function login(ctx) {
6 | const { username = '', password = '', sign = '' } = ctx.request.body
7 | let body = utils.cloneData(ctx.request.body)
8 | delete body.sign
9 | const sign_code = utils.sign(body)
10 | if (username === 'admin' && password === md5('admin') && sign_code === sign) {
11 | utils.errorHandle(ctx, 200, '登录成功', '', { token: md5('au真是个天才,哈哈哈') })
12 | return
13 | }
14 | utils.errorHandle(ctx, 30000, '用户信息有误')
15 | }
16 |
17 | async function info(ctx) {
18 | utils.errorHandle(ctx, 200, '获取用户信息成功', mockjs.mock({ username: mockjs.Random.name(), 'sex|1': ['男', '女', '未知'] }))
19 | }
20 |
21 | module.exports = {
22 | login,
23 | info
24 | }
--------------------------------------------------------------------------------
/server/utils/index.js:
--------------------------------------------------------------------------------
1 | const md5 = require('js-md5')
2 | const querystring = require('querystring')
3 | const loggers = require('../log.js')
4 | const { koaLogger } = loggers
5 | /**
6 | *
7 | * @param {加盐数据} data
8 | * @returns
9 | */
10 | function sign(data) {
11 | var newkey = Object.keys(data).sort()
12 | var newObj = {}
13 | for (var i = 0; i < newkey.length; i++) {
14 | newObj[newkey[i]] = data[newkey[i]]
15 | }
16 | let signature = 'au'
17 | for (var j = 0; j < newkey.length; j++) {
18 | signature += newObj[newkey[j]]
19 | }
20 | var date = new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, '').replace(/\.[\d]{3}Z/, '')
21 | signature += date.substring(0, 10)
22 | signature += 'au'
23 | signature = md5(signature.toUpperCase())
24 | return signature
25 | }
26 |
27 | function errorHandle(ctx, code, message = '', data = '', options = {}) {
28 | if (code === 200) {
29 | ctx.body = {
30 | error_code: code,
31 | data,
32 | message,
33 | ...options
34 | };
35 | } else if (message && message.message) {
36 | ctx.body = {
37 | error_code: code,
38 | data,
39 | message: message.message,
40 | ...options
41 | };
42 | } else {
43 | ctx.body = {
44 | error_code: code,
45 | data,
46 | message,
47 | ...options
48 | }
49 | }
50 | code != 200 && koaLogger.error(`错误码:${code},数据:${JSON.stringify(data)},错误信息:${JSON.stringify(message)}`)
51 | }
52 |
53 | function cloneData(data) {
54 | return JSON.parse(JSON.stringify(data))
55 | }
56 |
57 | module.exports = {
58 | sign,
59 | errorHandle,
60 | cloneData
61 | }
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/api/about.ts:
--------------------------------------------------------------------------------
1 | import request from '../plugins/axios'
2 |
3 | export function getActiveList(params: unknown) {
4 | return request({
5 | url: '/about/actives',
6 | method: 'get',
7 | params
8 | })
9 | }
10 |
11 | export function getMessageList(params: unknown) {
12 | return request({
13 | url: '/about/messages',
14 | method: 'get',
15 | params
16 | })
17 | }
18 |
19 | export function getRecordList(params: unknown) {
20 | return request({
21 | url: '/about/records',
22 | method: 'get',
23 | params
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/src/api/data.ts:
--------------------------------------------------------------------------------
1 | import request from '../plugins/axios'
2 |
3 | export function getList(params: unknown) {
4 | return request({
5 | url: '/data/list',
6 | method: 'get',
7 | params
8 | })
9 | }
10 |
11 | export function getNewList(params: unknown) {
12 | return request({
13 | url: '/data/news',
14 | method: 'get',
15 | params
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/src/api/home.ts:
--------------------------------------------------------------------------------
1 | import request from '../plugins/axios'
2 |
3 | export function getNoticelist(params) {
4 | return request({
5 | url: '/home/notices',
6 | method: 'get',
7 | params
8 | })
9 | }
10 |
11 | export function getCountlist() {
12 | return request({
13 | url: '/home/counts',
14 | method: 'get'
15 | })
16 | }
17 |
18 | export function getCurrentLevel() {
19 | return request({
20 | url: '/home/levels',
21 | method: 'get'
22 | })
23 | }
--------------------------------------------------------------------------------
/src/api/login.ts:
--------------------------------------------------------------------------------
1 | import request, { PromiseLoginName } from '../plugins/axios'
2 | import md5 from 'js-md5'
3 | export function login(data: { password: string, username: string }){
4 | let password = md5(data.password)
5 | return request({
6 | url: '/user/login',
7 | method: 'post',
8 | data: {
9 | ...data,
10 | password
11 | }
12 | })
13 | }
14 |
15 | export function info() {
16 | return request({
17 | url: '/user/info',
18 | method: 'get'
19 | })
20 | }
--------------------------------------------------------------------------------
/src/assets/css/base.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | background: #f9f9f9;
4 | overflow: hidden; /** 不让 html 和 body 滚动,让 #app 滚动,可以添加 element-plus 回到顶部功能 */
5 | }
6 | * {
7 | padding: 0;
8 | margin: 0;
9 | box-sizing: border-box;
10 | }
11 | #app {
12 | height: 100%;
13 | overflow: auto;
14 | }
15 |
16 | ul {
17 | list-style-type: none;
18 | }
--------------------------------------------------------------------------------
/src/assets/css/global.scss:
--------------------------------------------------------------------------------
1 | @import './variables.scss';
2 | @mixin mixinBgColor {
3 | background-color: $--var-background-white-;
4 | }
5 | .au-bg-white {
6 | @include mixinBgColor;
7 | }
8 | .au-bg-grey {
9 | background-color: #f9f9f9 !important;
10 | }
11 |
12 | /** card */
13 | .au-card {
14 | @include mixinBgColor;
15 | border-radius: 4px;
16 | border: 1px solid #ebeef5;
17 | overflow: hidden;
18 | color: #303133;
19 | transition: .3s;
20 | &:hover {
21 | box-shadow: 0 2px 12px 0 rgb(0 0 0 / 20%);
22 | }
23 | }
24 | .au-box-shadow {
25 | box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
26 | }
27 |
28 |
29 | /** 单行省略 */
30 | .au-text-line-one {
31 | overflow: hidden;
32 | text-overflow: ellipsis;
33 | white-space: nowrap;
34 | }
35 | .au-text-line-two {
36 | white-space: pre-wrap;
37 | overflow : hidden;
38 | text-overflow: ellipsis;
39 | display: -webkit-box;
40 | -webkit-line-clamp: 2;
41 | -webkit-box-orient: vertical;
42 | }
43 |
44 |
45 | /** svg style */
46 | .au-icon {
47 | width: 20px;
48 | height: 20px;
49 | }
50 |
51 |
52 | /** elements arrangement */
53 | .au-ml-8 {
54 | margin-left: 8px;
55 | }
56 | .au-mt-8 {
57 | margin-top: 8px;
58 | }
59 | .au-pd-8 {
60 | padding: 8px;
61 | }
62 | .au-mt-16 {
63 | margin-top: 16px;
64 | }
65 | .au-ml-16 {
66 | margin-left: 16px;
67 | }
68 | .au-mr-16 {
69 | margin-right: 16px;
70 | }
71 | .au-pd-16 {
72 | padding: 16px;
73 | }
74 | .au-mt-32 {
75 | margin-top: 32px;
76 | }
77 | .au-mr-32 {
78 | margin-right: 32px;
79 | }
80 | .au-pd-32 {
81 | padding: 32px;
82 | }
83 |
84 | /** text alignment direction */
85 | .au-text-end {
86 | text-align: end;
87 | }
88 | .au-text-center {
89 | text-align: center;
90 | }
91 | .au-text-link {
92 | color: #444;
93 | text-decoration: none;
94 | &:hover {
95 | color: #444;
96 | text-decoration: none;
97 | }
98 | }
99 |
100 | .au-block {
101 | display: block;
102 | }
103 | .au-in-block {
104 | display: inline-block;
105 | }
106 | .au-overflow-hidden {
107 | overflow: hidden;
108 | }
109 | .au-flex {
110 | display: flex;
111 | }
112 | .au-flex-rc-center {
113 | display: flex;
114 | align-items: center;
115 | justify-content: center;
116 | }
117 | .au-flex-row-center {
118 | justify-content: center;
119 | }
120 | .au-flex-column-center {
121 | align-items: center;
122 | }
123 |
--------------------------------------------------------------------------------
/src/assets/css/variables.scss:
--------------------------------------------------------------------------------
1 | // 全局变量
2 | // 颜色
3 | $--white-: #fff;
4 | $--blue-: #409EFF;
5 | // 背景
6 | $--var-background-white-: $--white-;
7 |
--------------------------------------------------------------------------------
/src/assets/iconfont/demo.css:
--------------------------------------------------------------------------------
1 | /* Logo 字体 */
2 | @font-face {
3 | font-family: "iconfont logo";
4 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
5 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
6 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
7 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
8 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
9 | }
10 |
11 | .logo {
12 | font-family: "iconfont logo";
13 | font-size: 160px;
14 | font-style: normal;
15 | -webkit-font-smoothing: antialiased;
16 | -moz-osx-font-smoothing: grayscale;
17 | }
18 |
19 | /* tabs */
20 | .nav-tabs {
21 | position: relative;
22 | }
23 |
24 | .nav-tabs .nav-more {
25 | position: absolute;
26 | right: 0;
27 | bottom: 0;
28 | height: 42px;
29 | line-height: 42px;
30 | color: #666;
31 | }
32 |
33 | #tabs {
34 | border-bottom: 1px solid #eee;
35 | }
36 |
37 | #tabs li {
38 | cursor: pointer;
39 | width: 100px;
40 | height: 40px;
41 | line-height: 40px;
42 | text-align: center;
43 | font-size: 16px;
44 | border-bottom: 2px solid transparent;
45 | position: relative;
46 | z-index: 1;
47 | margin-bottom: -1px;
48 | color: #666;
49 | }
50 |
51 |
52 | #tabs .active {
53 | border-bottom-color: #f00;
54 | color: #222;
55 | }
56 |
57 | .tab-container .content {
58 | display: none;
59 | }
60 |
61 | /* 页面布局 */
62 | .main {
63 | padding: 30px 100px;
64 | width: 960px;
65 | margin: 0 auto;
66 | }
67 |
68 | .main .logo {
69 | color: #333;
70 | text-align: left;
71 | margin-bottom: 30px;
72 | line-height: 1;
73 | height: 110px;
74 | margin-top: -50px;
75 | overflow: hidden;
76 | *zoom: 1;
77 | }
78 |
79 | .main .logo a {
80 | font-size: 160px;
81 | color: #333;
82 | }
83 |
84 | .helps {
85 | margin-top: 40px;
86 | }
87 |
88 | .helps pre {
89 | padding: 20px;
90 | margin: 10px 0;
91 | border: solid 1px #e7e1cd;
92 | background-color: #fffdef;
93 | overflow: auto;
94 | }
95 |
96 | .icon_lists {
97 | width: 100% !important;
98 | overflow: hidden;
99 | *zoom: 1;
100 | }
101 |
102 | .icon_lists li {
103 | width: 100px;
104 | margin-bottom: 10px;
105 | margin-right: 20px;
106 | text-align: center;
107 | list-style: none !important;
108 | cursor: default;
109 | }
110 |
111 | .icon_lists li .code-name {
112 | line-height: 1.2;
113 | }
114 |
115 | .icon_lists .icon {
116 | display: block;
117 | height: 100px;
118 | line-height: 100px;
119 | font-size: 42px;
120 | margin: 10px auto;
121 | color: #333;
122 | -webkit-transition: font-size 0.25s linear, width 0.25s linear;
123 | -moz-transition: font-size 0.25s linear, width 0.25s linear;
124 | transition: font-size 0.25s linear, width 0.25s linear;
125 | }
126 |
127 | .icon_lists .icon:hover {
128 | font-size: 100px;
129 | }
130 |
131 | .icon_lists .svg-icon {
132 | /* 通过设置 font-size 来改变图标大小 */
133 | width: 1em;
134 | /* 图标和文字相邻时,垂直对齐 */
135 | vertical-align: -0.15em;
136 | /* 通过设置 color 来改变 SVG 的颜色/fill */
137 | fill: currentColor;
138 | /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
139 | normalize.css 中也包含这行 */
140 | overflow: hidden;
141 | }
142 |
143 | .icon_lists li .name,
144 | .icon_lists li .code-name {
145 | color: #666;
146 | }
147 |
148 | /* markdown 样式 */
149 | .markdown {
150 | color: #666;
151 | font-size: 14px;
152 | line-height: 1.8;
153 | }
154 |
155 | .highlight {
156 | line-height: 1.5;
157 | }
158 |
159 | .markdown img {
160 | vertical-align: middle;
161 | max-width: 100%;
162 | }
163 |
164 | .markdown h1 {
165 | color: #404040;
166 | font-weight: 500;
167 | line-height: 40px;
168 | margin-bottom: 24px;
169 | }
170 |
171 | .markdown h2,
172 | .markdown h3,
173 | .markdown h4,
174 | .markdown h5,
175 | .markdown h6 {
176 | color: #404040;
177 | margin: 1.6em 0 0.6em 0;
178 | font-weight: 500;
179 | clear: both;
180 | }
181 |
182 | .markdown h1 {
183 | font-size: 28px;
184 | }
185 |
186 | .markdown h2 {
187 | font-size: 22px;
188 | }
189 |
190 | .markdown h3 {
191 | font-size: 16px;
192 | }
193 |
194 | .markdown h4 {
195 | font-size: 14px;
196 | }
197 |
198 | .markdown h5 {
199 | font-size: 12px;
200 | }
201 |
202 | .markdown h6 {
203 | font-size: 12px;
204 | }
205 |
206 | .markdown hr {
207 | height: 1px;
208 | border: 0;
209 | background: #e9e9e9;
210 | margin: 16px 0;
211 | clear: both;
212 | }
213 |
214 | .markdown p {
215 | margin: 1em 0;
216 | }
217 |
218 | .markdown>p,
219 | .markdown>blockquote,
220 | .markdown>.highlight,
221 | .markdown>ol,
222 | .markdown>ul {
223 | width: 80%;
224 | }
225 |
226 | .markdown ul>li {
227 | list-style: circle;
228 | }
229 |
230 | .markdown>ul li,
231 | .markdown blockquote ul>li {
232 | margin-left: 20px;
233 | padding-left: 4px;
234 | }
235 |
236 | .markdown>ul li p,
237 | .markdown>ol li p {
238 | margin: 0.6em 0;
239 | }
240 |
241 | .markdown ol>li {
242 | list-style: decimal;
243 | }
244 |
245 | .markdown>ol li,
246 | .markdown blockquote ol>li {
247 | margin-left: 20px;
248 | padding-left: 4px;
249 | }
250 |
251 | .markdown code {
252 | margin: 0 3px;
253 | padding: 0 5px;
254 | background: #eee;
255 | border-radius: 3px;
256 | }
257 |
258 | .markdown strong,
259 | .markdown b {
260 | font-weight: 600;
261 | }
262 |
263 | .markdown>table {
264 | border-collapse: collapse;
265 | border-spacing: 0px;
266 | empty-cells: show;
267 | border: 1px solid #e9e9e9;
268 | width: 95%;
269 | margin-bottom: 24px;
270 | }
271 |
272 | .markdown>table th {
273 | white-space: nowrap;
274 | color: #333;
275 | font-weight: 600;
276 | }
277 |
278 | .markdown>table th,
279 | .markdown>table td {
280 | border: 1px solid #e9e9e9;
281 | padding: 8px 16px;
282 | text-align: left;
283 | }
284 |
285 | .markdown>table th {
286 | background: #F7F7F7;
287 | }
288 |
289 | .markdown blockquote {
290 | font-size: 90%;
291 | color: #999;
292 | border-left: 4px solid #e9e9e9;
293 | padding-left: 0.8em;
294 | margin: 1em 0;
295 | }
296 |
297 | .markdown blockquote p {
298 | margin: 0;
299 | }
300 |
301 | .markdown .anchor {
302 | opacity: 0;
303 | transition: opacity 0.3s ease;
304 | margin-left: 8px;
305 | }
306 |
307 | .markdown .waiting {
308 | color: #ccc;
309 | }
310 |
311 | .markdown h1:hover .anchor,
312 | .markdown h2:hover .anchor,
313 | .markdown h3:hover .anchor,
314 | .markdown h4:hover .anchor,
315 | .markdown h5:hover .anchor,
316 | .markdown h6:hover .anchor {
317 | opacity: 1;
318 | display: inline-block;
319 | }
320 |
321 | .markdown>br,
322 | .markdown>p>br {
323 | clear: both;
324 | }
325 |
326 |
327 | .hljs {
328 | display: block;
329 | background: white;
330 | padding: 0.5em;
331 | color: #333333;
332 | overflow-x: auto;
333 | }
334 |
335 | .hljs-comment,
336 | .hljs-meta {
337 | color: #969896;
338 | }
339 |
340 | .hljs-string,
341 | .hljs-variable,
342 | .hljs-template-variable,
343 | .hljs-strong,
344 | .hljs-emphasis,
345 | .hljs-quote {
346 | color: #df5000;
347 | }
348 |
349 | .hljs-keyword,
350 | .hljs-selector-tag,
351 | .hljs-type {
352 | color: #a71d5d;
353 | }
354 |
355 | .hljs-literal,
356 | .hljs-symbol,
357 | .hljs-bullet,
358 | .hljs-attribute {
359 | color: #0086b3;
360 | }
361 |
362 | .hljs-section,
363 | .hljs-name {
364 | color: #63a35c;
365 | }
366 |
367 | .hljs-tag {
368 | color: #333333;
369 | }
370 |
371 | .hljs-title,
372 | .hljs-attr,
373 | .hljs-selector-id,
374 | .hljs-selector-class,
375 | .hljs-selector-attr,
376 | .hljs-selector-pseudo {
377 | color: #795da3;
378 | }
379 |
380 | .hljs-addition {
381 | color: #55a532;
382 | background-color: #eaffea;
383 | }
384 |
385 | .hljs-deletion {
386 | color: #bd2c00;
387 | background-color: #ffecec;
388 | }
389 |
390 | .hljs-link {
391 | text-decoration: underline;
392 | }
393 |
394 | /* 代码高亮 */
395 | /* PrismJS 1.15.0
396 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
397 | /**
398 | * prism.js default theme for JavaScript, CSS and HTML
399 | * Based on dabblet (http://dabblet.com)
400 | * @author Lea Verou
401 | */
402 | code[class*="language-"],
403 | pre[class*="language-"] {
404 | color: black;
405 | background: none;
406 | text-shadow: 0 1px white;
407 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
408 | text-align: left;
409 | white-space: pre;
410 | word-spacing: normal;
411 | word-break: normal;
412 | word-wrap: normal;
413 | line-height: 1.5;
414 |
415 | -moz-tab-size: 4;
416 | -o-tab-size: 4;
417 | tab-size: 4;
418 |
419 | -webkit-hyphens: none;
420 | -moz-hyphens: none;
421 | -ms-hyphens: none;
422 | hyphens: none;
423 | }
424 |
425 | pre[class*="language-"]::-moz-selection,
426 | pre[class*="language-"] ::-moz-selection,
427 | code[class*="language-"]::-moz-selection,
428 | code[class*="language-"] ::-moz-selection {
429 | text-shadow: none;
430 | background: #b3d4fc;
431 | }
432 |
433 | pre[class*="language-"]::selection,
434 | pre[class*="language-"] ::selection,
435 | code[class*="language-"]::selection,
436 | code[class*="language-"] ::selection {
437 | text-shadow: none;
438 | background: #b3d4fc;
439 | }
440 |
441 | @media print {
442 |
443 | code[class*="language-"],
444 | pre[class*="language-"] {
445 | text-shadow: none;
446 | }
447 | }
448 |
449 | /* Code blocks */
450 | pre[class*="language-"] {
451 | padding: 1em;
452 | margin: .5em 0;
453 | overflow: auto;
454 | }
455 |
456 | :not(pre)>code[class*="language-"],
457 | pre[class*="language-"] {
458 | background: #f5f2f0;
459 | }
460 |
461 | /* Inline code */
462 | :not(pre)>code[class*="language-"] {
463 | padding: .1em;
464 | border-radius: .3em;
465 | white-space: normal;
466 | }
467 |
468 | .token.comment,
469 | .token.prolog,
470 | .token.doctype,
471 | .token.cdata {
472 | color: slategray;
473 | }
474 |
475 | .token.punctuation {
476 | color: #999;
477 | }
478 |
479 | .namespace {
480 | opacity: .7;
481 | }
482 |
483 | .token.property,
484 | .token.tag,
485 | .token.boolean,
486 | .token.number,
487 | .token.constant,
488 | .token.symbol,
489 | .token.deleted {
490 | color: #905;
491 | }
492 |
493 | .token.selector,
494 | .token.attr-name,
495 | .token.string,
496 | .token.char,
497 | .token.builtin,
498 | .token.inserted {
499 | color: #690;
500 | }
501 |
502 | .token.operator,
503 | .token.entity,
504 | .token.url,
505 | .language-css .token.string,
506 | .style .token.string {
507 | color: #9a6e3a;
508 | background: hsla(0, 0%, 100%, .5);
509 | }
510 |
511 | .token.atrule,
512 | .token.attr-value,
513 | .token.keyword {
514 | color: #07a;
515 | }
516 |
517 | .token.function,
518 | .token.class-name {
519 | color: #DD4A68;
520 | }
521 |
522 | .token.regex,
523 | .token.important,
524 | .token.variable {
525 | color: #e90;
526 | }
527 |
528 | .token.important,
529 | .token.bold {
530 | font-weight: bold;
531 | }
532 |
533 | .token.italic {
534 | font-style: italic;
535 | }
536 |
537 | .token.entity {
538 | cursor: help;
539 | }
540 |
--------------------------------------------------------------------------------
/src/assets/iconfont/demo_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IconFont Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | - Unicode
22 | - Font class
23 | - Symbol
24 |
25 |
26 |
查看项目
27 |
28 |
29 |
30 |
31 |
32 |
33 | -
34 |
35 |
哈希
36 | 
37 |
38 |
39 | -
40 |
41 |
流转
42 | 
43 |
44 |
45 | -
46 |
47 |
区块
48 | 
49 |
50 |
51 | -
52 |
53 |
欧元
54 | 
55 |
56 |
57 | -
58 |
59 |
商业化全球
60 | 
61 |
62 |
63 | -
64 |
65 |
溯源
66 | 
67 |
68 |
69 | -
70 |
71 |
数据库
72 | 
73 |
74 |
75 | -
76 |
77 |
印章认证
78 | 
79 |
80 |
81 | -
82 |
83 |
v6
84 | 
85 |
86 |
87 | -
88 |
89 |
v2
90 | 
91 |
92 |
93 | -
94 |
95 |
v7
96 | 
97 |
98 |
99 | -
100 |
101 |
v5
102 | 
103 |
104 |
105 | -
106 |
107 |
v4
108 | 
109 |
110 |
111 | -
112 |
113 |
v9
114 | 
115 |
116 |
117 | -
118 |
119 |
v8
120 | 
121 |
122 |
123 | -
124 |
125 |
v1
126 | 
127 |
128 |
129 | -
130 |
131 |
v3
132 | 
133 |
134 |
135 | -
136 |
137 |
v
138 | 
139 |
140 |
141 | -
142 |
143 |
user
144 | 
145 |
146 |
147 |
148 |
149 |
Unicode 引用
150 |
151 |
152 |
Unicode 是字体在网页端最原始的应用方式,特点是:
153 |
154 | - 兼容性最好,支持 IE6+,及所有现代浏览器。
155 | - 支持按字体的方式去动态调整图标大小,颜色等等。
156 | - 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
157 |
158 |
159 | 注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式
160 |
161 |
Unicode 使用步骤如下:
162 |
第一步:拷贝项目下面生成的 @font-face
163 |
@font-face {
165 | font-family: 'iconfont';
166 | src: url('iconfont.eot');
167 | src: url('iconfont.eot?#iefix') format('embedded-opentype'),
168 | url('iconfont.woff2') format('woff2'),
169 | url('iconfont.woff') format('woff'),
170 | url('iconfont.ttf') format('truetype'),
171 | url('iconfont.svg#iconfont') format('svg');
172 | }
173 |
174 |
第二步:定义使用 iconfont 的样式
175 |
.iconfont {
177 | font-family: "iconfont" !important;
178 | font-size: 16px;
179 | font-style: normal;
180 | -webkit-font-smoothing: antialiased;
181 | -moz-osx-font-smoothing: grayscale;
182 | }
183 |
184 |
第三步:挑选相应图标并获取字体编码,应用于页面
185 |
186 | <span class="iconfont">3</span>
188 |
189 |
190 | "iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。
191 |
192 |
193 |
194 |
195 |
369 |
370 |
font-class 引用
371 |
372 |
373 |
font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。
374 |
与 Unicode 使用方式相比,具有如下特点:
375 |
376 | - 兼容性良好,支持 IE8+,及所有现代浏览器。
377 | - 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
378 | - 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
379 | - 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
380 |
381 |
使用步骤如下:
382 |
第一步:引入项目下面生成的 fontclass 代码:
383 |
<link rel="stylesheet" href="./iconfont.css">
384 |
385 |
第二步:挑选相应图标并获取类名,应用于页面:
386 |
<span class="iconfont iconxxx"></span>
387 |
388 |
389 | "
390 | iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。
391 |
392 |
393 |
394 |
395 |
396 |
397 | -
398 |
401 |
哈希
402 | #iconhaxi
403 |
404 |
405 | -
406 |
409 |
流转
410 | #iconliuzhuan
411 |
412 |
413 | -
414 |
417 |
区块
418 | #iconqukuai
419 |
420 |
421 | -
422 |
425 |
欧元
426 | #iconouyuan
427 |
428 |
429 | -
430 |
433 |
商业化全球
434 | #iconshangyehuaquanqiu
435 |
436 |
437 | -
438 |
441 |
溯源
442 | #iconsuyuan
443 |
444 |
445 | -
446 |
449 |
数据库
450 | #iconshujuku
451 |
452 |
453 | -
454 |
457 |
印章认证
458 | #iconyinzhangrenzheng
459 |
460 |
461 | -
462 |
465 |
v6
466 | #iconv
467 |
468 |
469 | -
470 |
473 |
v2
474 | #iconv1
475 |
476 |
477 | -
478 |
481 |
v7
482 | #iconv2
483 |
484 |
485 | -
486 |
489 |
v5
490 | #iconv3
491 |
492 |
493 | -
494 |
497 |
v4
498 | #iconv4
499 |
500 |
501 | -
502 |
505 |
v9
506 | #iconv5
507 |
508 |
509 | -
510 |
513 |
v8
514 | #iconv6
515 |
516 |
517 | -
518 |
521 |
v1
522 | #iconv7
523 |
524 |
525 | -
526 |
529 |
v3
530 | #iconv8
531 |
532 |
533 | -
534 |
537 |
v
538 | #iconv9
539 |
540 |
541 | -
542 |
545 |
user
546 | #iconuser
547 |
548 |
549 |
550 |
551 |
Symbol 引用
552 |
553 |
554 |
这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章
555 | 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:
556 |
557 | - 支持多色图标了,不再受单色限制。
558 | - 通过一些技巧,支持像字体那样,通过
font-size
, color
来调整样式。
559 | - 兼容性较差,支持 IE9+,及现代浏览器。
560 | - 浏览器渲染 SVG 的性能一般,还不如 png。
561 |
562 |
使用步骤如下:
563 |
第一步:引入项目下面生成的 symbol 代码:
564 |
<script src="./iconfont.js"></script>
565 |
566 |
第二步:加入通用 CSS 代码(引入一次就行):
567 |
<style>
568 | .icon {
569 | width: 1em;
570 | height: 1em;
571 | vertical-align: -0.15em;
572 | fill: currentColor;
573 | overflow: hidden;
574 | }
575 | </style>
576 |
577 |
第三步:挑选相应图标并获取类名,应用于页面:
578 |
<svg class="icon" aria-hidden="true">
579 | <use xlink:href="#icon-xxx"></use>
580 | </svg>
581 |
582 |
583 |
584 |
585 |
586 |
587 |
606 |
607 |
608 |
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {font-family: "iconfont";
2 | src: url('iconfont.eot?t=1614132660938'); /* IE9 */
3 | src: url('iconfont.eot?t=1614132660938#iefix') format('embedded-opentype'), /* IE6-IE8 */
4 | url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
5 | url('iconfont.woff?t=1614132660938') format('woff'),
6 | url('iconfont.ttf?t=1614132660938') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
7 | url('iconfont.svg?t=1614132660938#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family: "iconfont" !important;
12 | font-size: 16px;
13 | font-style: normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .iconhaxi:before {
19 | content: "\e98f";
20 | }
21 |
22 | .iconliuzhuan:before {
23 | content: "\e992";
24 | }
25 |
26 | .iconqukuai:before {
27 | content: "\e994";
28 | }
29 |
30 | .iconouyuan:before {
31 | content: "\e995";
32 | }
33 |
34 | .iconshangyehuaquanqiu:before {
35 | content: "\e996";
36 | }
37 |
38 | .iconsuyuan:before {
39 | content: "\e997";
40 | }
41 |
42 | .iconshujuku:before {
43 | content: "\e998";
44 | }
45 |
46 | .iconyinzhangrenzheng:before {
47 | content: "\e99b";
48 | }
49 |
50 | .iconv:before {
51 | content: "\e666";
52 | }
53 |
54 | .iconv1:before {
55 | content: "\e665";
56 | }
57 |
58 | .iconv2:before {
59 | content: "\e667";
60 | }
61 |
62 | .iconv3:before {
63 | content: "\e672";
64 | }
65 |
66 | .iconv4:before {
67 | content: "\e673";
68 | }
69 |
70 | .iconv5:before {
71 | content: "\e674";
72 | }
73 |
74 | .iconv6:before {
75 | content: "\e675";
76 | }
77 |
78 | .iconv7:before {
79 | content: "\e676";
80 | }
81 |
82 | .iconv8:before {
83 | content: "\e677";
84 | }
85 |
86 | .iconv9:before {
87 | content: "\e7dd";
88 | }
89 |
90 | .iconuser:before {
91 | content: "\e657";
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/src/assets/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "2382143",
3 | "name": "vite2-bg-template",
4 | "font_family": "iconfont",
5 | "css_prefix_text": "icon",
6 | "description": "",
7 | "glyphs": [
8 | {
9 | "icon_id": "18267923",
10 | "name": "哈希",
11 | "font_class": "haxi",
12 | "unicode": "e98f",
13 | "unicode_decimal": 59791
14 | },
15 | {
16 | "icon_id": "18267934",
17 | "name": "流转",
18 | "font_class": "liuzhuan",
19 | "unicode": "e992",
20 | "unicode_decimal": 59794
21 | },
22 | {
23 | "icon_id": "18267938",
24 | "name": "区块",
25 | "font_class": "qukuai",
26 | "unicode": "e994",
27 | "unicode_decimal": 59796
28 | },
29 | {
30 | "icon_id": "18267942",
31 | "name": "欧元",
32 | "font_class": "ouyuan",
33 | "unicode": "e995",
34 | "unicode_decimal": 59797
35 | },
36 | {
37 | "icon_id": "18267949",
38 | "name": "商业化全球",
39 | "font_class": "shangyehuaquanqiu",
40 | "unicode": "e996",
41 | "unicode_decimal": 59798
42 | },
43 | {
44 | "icon_id": "18267957",
45 | "name": "溯源",
46 | "font_class": "suyuan",
47 | "unicode": "e997",
48 | "unicode_decimal": 59799
49 | },
50 | {
51 | "icon_id": "18267958",
52 | "name": "数据库",
53 | "font_class": "shujuku",
54 | "unicode": "e998",
55 | "unicode_decimal": 59800
56 | },
57 | {
58 | "icon_id": "18267973",
59 | "name": "印章认证",
60 | "font_class": "yinzhangrenzheng",
61 | "unicode": "e99b",
62 | "unicode_decimal": 59803
63 | },
64 | {
65 | "icon_id": "12548806",
66 | "name": "v6",
67 | "font_class": "v",
68 | "unicode": "e666",
69 | "unicode_decimal": 58982
70 | },
71 | {
72 | "icon_id": "12548807",
73 | "name": "v2",
74 | "font_class": "v1",
75 | "unicode": "e665",
76 | "unicode_decimal": 58981
77 | },
78 | {
79 | "icon_id": "12548809",
80 | "name": "v7",
81 | "font_class": "v2",
82 | "unicode": "e667",
83 | "unicode_decimal": 58983
84 | },
85 | {
86 | "icon_id": "12643756",
87 | "name": "v5",
88 | "font_class": "v3",
89 | "unicode": "e672",
90 | "unicode_decimal": 58994
91 | },
92 | {
93 | "icon_id": "12643757",
94 | "name": "v4",
95 | "font_class": "v4",
96 | "unicode": "e673",
97 | "unicode_decimal": 58995
98 | },
99 | {
100 | "icon_id": "12643761",
101 | "name": "v9",
102 | "font_class": "v5",
103 | "unicode": "e674",
104 | "unicode_decimal": 58996
105 | },
106 | {
107 | "icon_id": "12643765",
108 | "name": "v8",
109 | "font_class": "v6",
110 | "unicode": "e675",
111 | "unicode_decimal": 58997
112 | },
113 | {
114 | "icon_id": "12643786",
115 | "name": "v1",
116 | "font_class": "v7",
117 | "unicode": "e676",
118 | "unicode_decimal": 58998
119 | },
120 | {
121 | "icon_id": "12643827",
122 | "name": "v3",
123 | "font_class": "v8",
124 | "unicode": "e677",
125 | "unicode_decimal": 58999
126 | },
127 | {
128 | "icon_id": "16561802",
129 | "name": "v",
130 | "font_class": "v9",
131 | "unicode": "e7dd",
132 | "unicode_decimal": 59357
133 | },
134 | {
135 | "icon_id": "15167625",
136 | "name": "user",
137 | "font_class": "user",
138 | "unicode": "e657",
139 | "unicode_decimal": 58967
140 | }
141 | ]
142 | }
143 |
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
84 |
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/src/assets/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/src/assets/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/src/assets/iconfont/iconfont.woff2
--------------------------------------------------------------------------------
/src/assets/images/bg.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/src/assets/images/bg.jpeg
--------------------------------------------------------------------------------
/src/assets/images/profile.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/src/assets/images/profile.jpg
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/src/assets/logo.png
--------------------------------------------------------------------------------
/src/components/au-header.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
60 |
106 |
--------------------------------------------------------------------------------
/src/components/au-input.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ radio.label }}
6 |
7 |
15 |
16 |
17 |
58 |
--------------------------------------------------------------------------------
/src/components/au-layout-empty.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/components/au-layout.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
80 |
151 |
--------------------------------------------------------------------------------
/src/components/au-nav.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
35 |
36 |
37 |
64 |
96 |
--------------------------------------------------------------------------------
/src/components/au-pagination.ts:
--------------------------------------------------------------------------------
1 | import { AppContext, ref, watch, onMounted } from 'vue'
2 |
3 | export default function pagination(ctx?: AppContext, callback?: (v: unknown) => unknown, autoFetch: boolean = false) {
4 | const limit = ref(10)
5 | const page = ref(1)
6 | const total = ref(100)
7 | const clear = () => {
8 | limit.value = 10
9 | page.value = 1
10 | total.value = 100
11 | if (!autoFetch) return
12 | if (typeof callback === 'function') {
13 | callback({
14 | limit: limit.value,
15 | page: page.value,
16 | total: total.value
17 | })
18 | }
19 | }
20 | const changeLimit = (newLimit: number) => {
21 | limit.value = newLimit
22 | }
23 | const changePage = (newPage: number) => {
24 | page.value = newPage
25 | }
26 | const changeTotal = (newTotal: number) => {
27 | total.value = newTotal
28 | }
29 | const pageSizeChange = (...args: []) => {
30 | console.log('sizeChange', args)
31 | }
32 | const currentPageChange = (currPage: number) => {
33 | page.value = currPage
34 | }
35 | watch([limit, page, total], ([l, p, t], [prevLimit, prevPage, prevTotal]) => {
36 | if (!autoFetch) return
37 | if (t !== prevTotal) {
38 | page.value = 1
39 | return
40 | }
41 | if (typeof callback === 'function') {
42 | callback({
43 | limit: limit.value,
44 | page: page.value,
45 | total: total.value
46 | })
47 | }
48 | })
49 |
50 | onMounted(() => {
51 | if(autoFetch && typeof callback === 'function') {
52 | callback({
53 | limit: limit.value,
54 | page: page.value,
55 | total: total.value
56 | })
57 | }
58 | })
59 |
60 | return {
61 | limit,
62 | page,
63 | total,
64 | clear,
65 | changeLimit,
66 | changePage,
67 | changeTotal,
68 | pageSizeChange,
69 | currentPageChange
70 | }
71 | }
--------------------------------------------------------------------------------
/src/components/au-screen.ts:
--------------------------------------------------------------------------------
1 | import { SetupContext, computed, ComputedRef } from 'vue'
2 | import { getStore } from '../store/index'
3 |
4 | export default function screen(ctx?: SetupContext, callback?: (m: ComputedRef, c: ComputedRef) => string) {
5 | const { store } = getStore()
6 | const isMobile = computed(() => store.getters.isMobile)
7 | const closed = computed(() => store.getters.toggleClosed)
8 | const toggleClick = () => {
9 | store.dispatch('updateToggleType', !closed.value)
10 | }
11 | let toggleClass = computed(() => {
12 | if(typeof callback === 'function') return callback(isMobile, closed)
13 | else if (!isMobile.value) return ''
14 | else return closed.value ? 'el-icon-s-unfold' : 'el-icon-s-fold'
15 | })
16 |
17 | return {
18 | isMobile,
19 | closed,
20 | toggleClick,
21 | toggleClass
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 |
4 | // style
5 | import './assets/css/base.css'
6 | import './assets/iconfont/iconfont.css'
7 | import 'nprogress/nprogress.css'
8 | import 'element-plus/lib/theme-chalk/display.css'
9 | import 'element-plus/lib/theme-chalk/index.css'
10 |
11 | // plugins
12 | import plugins from './plugins'
13 |
14 | createApp(App)
15 | .use(plugins)
16 | .mount('#app')
17 |
--------------------------------------------------------------------------------
/src/plugins/axios.ts:
--------------------------------------------------------------------------------
1 | import axios, { AxiosResponse } from 'axios'
2 | import qs from 'qs'
3 | import _sign from '../utils/_sign'
4 |
5 | const request = axios.create({
6 | baseURL: import.meta.env.VITE_BASE_URL,
7 | timeout: 10000,
8 | transformRequest: [function (data) {
9 | const d = qs.stringify(data)
10 | return d
11 | }]
12 | })
13 |
14 | request.interceptors.request.use(
15 | config => {
16 | if (config.method?.toLowerCase() === 'post') {
17 | _sign(config.data)
18 | }
19 | return config
20 | },
21 | error => {
22 | return Promise.reject(error)
23 | }
24 | )
25 |
26 | request.interceptors.response.use(
27 | (response) => {
28 | const res = response.data
29 | return res
30 | },
31 | error => {
32 | console.log('err' + error)
33 | return Promise.reject(error)
34 | }
35 | )
36 |
37 | export interface PromiseBaseName {
38 | data: string | Array | number | Object | undefined | null,
39 | error_code: number,
40 | message?: string
41 | }
42 |
43 | export interface PromiseLoginName extends PromiseBaseName{
44 | token: string
45 | }
46 | export type ResponseName = AxiosResponse | AxiosResponse
47 |
48 | export default request
49 |
--------------------------------------------------------------------------------
/src/plugins/element-ui.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue'
2 | import {
3 | ElAlert,
4 | ElIcon,
5 | ElBacktop,
6 | ElBadge,
7 | ElButton,
8 | ElButtonGroup,
9 | ElCard,
10 | ElCheckbox,
11 | ElCheckboxButton,
12 | ElCheckboxGroup,
13 | ElCol,
14 | ElContainer,
15 | ElDialog,
16 | ElDropdown,
17 | ElDropdownItem,
18 | ElDropdownMenu,
19 | ElForm,
20 | ElFormItem,
21 | ElHeader,
22 | ElInput,
23 | ElInputNumber,
24 | ElLink,
25 | ElMain,
26 | ElMenu,
27 | ElMenuItem,
28 | ElMenuItemGroup,
29 | ElPageHeader,
30 | ElPagination,
31 | ElPopconfirm,
32 | ElPopover,
33 | ElPopper,
34 | ElProgress,
35 | ElRadio,
36 | ElRadioButton,
37 | ElRadioGroup,
38 | ElRow,
39 | ElSelect,
40 | ElStep,
41 | ElSteps,
42 | ElSubmenu,
43 | ElSwitch,
44 | ElTabPane,
45 | ElTable,
46 | ElTableColumn,
47 | ElTabs,
48 | ElTag,
49 | ElTooltip,
50 | ElUpload,
51 | ElLoading,
52 | ElMessage,
53 | ElMessageBox,
54 | ElNotification,
55 | ElTimeline,
56 | ElTimelineItem,
57 | } from 'element-plus'
58 |
59 | const elements = [
60 | ElAlert,
61 | ElIcon,
62 | ElBacktop,
63 | ElBadge,
64 | ElButton,
65 | ElButtonGroup,
66 | ElCard,
67 | ElCheckbox,
68 | ElCheckboxButton,
69 | ElCheckboxGroup,
70 | ElCol,
71 | ElContainer,
72 | ElDialog,
73 | ElDropdown,
74 | ElDropdownItem,
75 | ElDropdownMenu,
76 | ElForm,
77 | ElFormItem,
78 | ElHeader,
79 | ElInput,
80 | ElInputNumber,
81 | ElLink,
82 | ElMain,
83 | ElMenu,
84 | ElMenuItem,
85 | ElMenuItemGroup,
86 | ElPageHeader,
87 | ElPagination,
88 | ElPopconfirm,
89 | ElPopover,
90 | ElPopper,
91 | ElProgress,
92 | ElRadio,
93 | ElRadioButton,
94 | ElRadioGroup,
95 | ElRow,
96 | ElSelect,
97 | ElStep,
98 | ElSteps,
99 | ElSubmenu,
100 | ElSwitch,
101 | ElTabPane,
102 | ElTable,
103 | ElTableColumn,
104 | ElTabs,
105 | ElTag,
106 | ElTooltip,
107 | ElUpload,
108 | ElTimeline,
109 | ElTimelineItem,
110 | ]
111 |
112 | const plugins = [ElLoading, ElMessage, ElMessageBox, ElNotification]
113 |
114 | export default {
115 | install(app: App) {
116 | elements.forEach((component) => {
117 | app.component(component.name, component)
118 | })
119 |
120 | plugins.forEach((plugin) => {
121 | app.use(plugin)
122 | })
123 | },
124 | }
125 |
--------------------------------------------------------------------------------
/src/plugins/index.ts:
--------------------------------------------------------------------------------
1 | import { router } from './router'
2 | import { store, key } from './store'
3 | import ElementUI from './element-ui'
4 | import { App } from 'vue'
5 | import lang from 'element-plus/lib/locale/lang/zh-cn'
6 | import 'dayjs/locale/zh-cn'
7 | import locale from 'element-plus/lib/locale'
8 |
9 | export default {
10 | install(vue: App) {
11 | vue.use(router)
12 | vue.use(store, key)
13 | vue.use(ElementUI, { locale })
14 | // locale.use(lang) // 设置 element-plus 中文,暂时没法起作用,原因待研究
15 | }
16 | }
--------------------------------------------------------------------------------
/src/plugins/router.ts:
--------------------------------------------------------------------------------
1 | import '../router/permision' // permision
2 |
3 | export { default as router } from '../router/index'
--------------------------------------------------------------------------------
/src/plugins/store.ts:
--------------------------------------------------------------------------------
1 | export { key, store } from './../store/index'
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
2 | import Layout from '../components/au-layout.vue'
3 | import EmptyLaoyout from '../components/au-layout-empty.vue'
4 | const routes: Array = [
5 | {
6 | path: '',
7 | redirect: (_) => {
8 | return { path: '/home' }
9 | },
10 | },
11 | {
12 | path: '/',
13 | component: Layout,
14 | children: [
15 | {
16 | path: 'home',
17 | name: 'Home',
18 | component: () =>
19 | import(/* webpackChunkName: 'Home' */ '../views/home/index.vue'),
20 | meta: {
21 | title: '主页',
22 | },
23 | },
24 | {
25 | path: 'about',
26 | name: 'About',
27 | component: () =>
28 | import(/* webpackChunkName: 'About' */ '../views/about/index.vue'),
29 | meta: {
30 | title: '关于',
31 | },
32 | },
33 | {
34 | path: 'profile',
35 | name: 'Profile',
36 | component: () =>
37 | import(
38 | /* webpackChunkName: 'Profile' */ '../views/profile/index.vue'
39 | ),
40 | meta: {
41 | title: '个人中心',
42 | },
43 | },
44 | {
45 | path: 'data',
46 | name: 'Census',
47 | component: EmptyLaoyout,
48 | meta: {
49 | title: '数据统计',
50 | },
51 | children: [
52 | {
53 | path: 'rank',
54 | name: 'Rank',
55 | component: () =>
56 | import(/* webpackChunkName: 'Rank' */ '../views/data/rank.vue'),
57 | meta: {
58 | title: '最新排名',
59 | },
60 | },
61 | {
62 | path: 'data',
63 | name: 'Data',
64 | component: () =>
65 | import(/* webpackChunkName: 'Data' */ '../views/data/index.vue'),
66 | meta: {
67 | title: '实时信息',
68 | },
69 | },
70 | ],
71 | },
72 | ],
73 | },
74 | {
75 | path: '/login',
76 | name: 'Login',
77 | component: () =>
78 | import(/* webpackChunkName: 'Login' */ '../views/login/index.vue'),
79 | meta: {
80 | title: '登录',
81 | },
82 | },
83 | {
84 | path: '/404',
85 | component: () =>
86 | import(/* webpackChunkName: 'Error' */ '../views/error/404.vue'),
87 | meta: {
88 | title: '404',
89 | },
90 | },
91 | {
92 | path: '/',
93 | redirect: (_) => {
94 | return { path: '/home' }
95 | },
96 | },
97 | {
98 | path: '/:currentPath(.*)*',
99 | redirect: (_) => {
100 | return { path: '/404' }
101 | },
102 | },
103 | ]
104 |
105 | const router = createRouter({
106 | history: createWebHistory(),
107 | routes,
108 | scrollBehavior(to, from, savedPosition) {
109 | return {
110 | el: '#app',
111 | top: 0,
112 | behavior: 'smooth',
113 | }
114 | },
115 | })
116 |
117 | export default router
118 |
--------------------------------------------------------------------------------
/src/router/permision.ts:
--------------------------------------------------------------------------------
1 | import { store } from '../store'
2 | import { getlocalStorageToken } from '../utils/_ls'
3 | import NProgress from 'nprogress'
4 | import router from './index'
5 |
6 | router.beforeEach((to, from, next) => {
7 | NProgress.start()
8 | const hasToken = getlocalStorageToken() || store?.state?.token || ''
9 | if (hasToken) {
10 | if (to.path === '/login') {
11 | next('/home')
12 | } else {
13 | next()
14 | }
15 | } else {
16 | if (to.path === '/login'){
17 | next()
18 | } else {
19 | next('/login')
20 | }
21 | }
22 | })
23 |
24 | router.afterEach((to, from) => {
25 | NProgress.done()
26 | const isMobile = store.state.isMobile
27 | const closed = store.state.toggleClosed
28 | if (isMobile && !closed) {
29 | store.dispatch('updateToggleType', true)
30 | }
31 | document!.title = to?.meta?.title as string + '-后台管理模板' || '后台管理模板'
32 | })
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import { DefineComponent } from 'vue'
3 | const component: DefineComponent<{}, {}, any>
4 | export default component
5 | }
--------------------------------------------------------------------------------
/src/store/actions.ts:
--------------------------------------------------------------------------------
1 | import { State, UserInfo } from './state';
2 | import { ActionContext } from 'vuex'
3 | import { login } from '../api/login'
4 | import { SET_TOKEN, CLEAR_TOKEN, USER_LOGIN, UPDATE_SCREEN_WIDTH, UPDATE_IS_MOBILE, UPDATE_TOGGLE_TYPE } from './types'
5 | import { PromiseLoginName } from '../plugins/axios'
6 | export default {
7 | setToken({ commit }: ActionContext, token: string) {
8 | commit(SET_TOKEN, token)
9 | },
10 | clearToken({ commit }: ActionContext) {
11 | commit(CLEAR_TOKEN)
12 | },
13 | login({ commit }: ActionContext, { username, password }: UserInfo) {
14 | return new Promise((resolve, reject) => {
15 | let _query = {
16 | username: username.trim(), password: password.trim()
17 | }
18 | login(_query).then((res) => {
19 | const { error_code, message, token } = res as unknown as PromiseLoginName
20 | if (error_code === 200) {
21 | commit(USER_LOGIN, _query)
22 | commit(SET_TOKEN, token)
23 | resolve(message)
24 | } else {
25 | reject(message)
26 | }
27 | }).catch((error: unknown) => {
28 | reject(error)
29 | })
30 | })
31 | },
32 | updetaScreenWidth({ commit }: ActionContext, width: number) {
33 | if (width < 769) {
34 | commit(UPDATE_IS_MOBILE, true)
35 | commit(UPDATE_TOGGLE_TYPE, true)
36 | } else {
37 | commit(UPDATE_IS_MOBILE, false)
38 | commit(UPDATE_TOGGLE_TYPE, true)
39 | }
40 | commit(UPDATE_SCREEN_WIDTH, width)
41 | },
42 | updateToggleType({ commit }: ActionContext, closed: number) {
43 | commit(UPDATE_TOGGLE_TYPE, closed)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/store/getters.ts:
--------------------------------------------------------------------------------
1 | import { State } from './state'
2 | export default {
3 | getToken(state: State) {
4 | return state.token
5 | },
6 | getUserInfo(state: State) {
7 | return state.userInfo
8 | },
9 | getScreenWidth(state: State) {
10 | return state.screenWidth
11 | },
12 | isMobile(state: State) {
13 | return state.isMobile
14 | },
15 | toggleClosed(state: State) {
16 | return state.toggleClosed
17 | }
18 | }
--------------------------------------------------------------------------------
/src/store/index.ts:
--------------------------------------------------------------------------------
1 | import { InjectionKey } from 'vue'
2 | import { createStore, Store, useStore } from 'vuex'
3 | import { state, State } from './state'
4 | import mutations from './mutations'
5 | import actions from './actions'
6 | import getters from './getters'
7 | export const key: InjectionKey> = Symbol()
8 |
9 | export const store = createStore({
10 | state,
11 | getters,
12 | actions,
13 | mutations
14 | })
15 |
16 | export function getStore() {
17 | return {
18 | store: useStore(key)
19 | }
20 | }
--------------------------------------------------------------------------------
/src/store/mutations.ts:
--------------------------------------------------------------------------------
1 | import { removelocalStorageToken, setlocalStorageToken } from '../utils/_ls'
2 | import { State, UserInfo } from './state'
3 | import { SET_TOKEN, CLEAR_TOKEN, USER_LOGIN, UPDATE_IS_MOBILE, UPDATE_SCREEN_WIDTH, UPDATE_TOGGLE_TYPE } from './types'
4 | export default {
5 | [SET_TOKEN](state: State, token: string) {
6 | state.token = token
7 | setlocalStorageToken(token)
8 | },
9 | [CLEAR_TOKEN](state: State) {
10 | state.token = ''
11 | removelocalStorageToken()
12 | },
13 | [USER_LOGIN](state: State, user: UserInfo) {
14 | state.userInfo = user
15 | },
16 | [UPDATE_SCREEN_WIDTH](state: State, width: number) {
17 | state.screenWidth = width
18 | },
19 | [UPDATE_IS_MOBILE](state: State, isMobile: boolean) {
20 | state.isMobile = isMobile
21 | },
22 | [UPDATE_TOGGLE_TYPE](state: State, closed: boolean) {
23 | state.toggleClosed = closed
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/store/state.ts:
--------------------------------------------------------------------------------
1 | import { getlocalStorageToken } from "../utils/_ls"
2 | export interface State {
3 | token: string;
4 | userInfo: UserInfo;
5 | screenWidth: number;
6 | isMobile: boolean;
7 | toggleClosed: boolean;
8 | [props: string]: any;
9 | }
10 |
11 | export interface UserInfo {
12 | username: string;
13 | password: string;
14 | [props: string]: any;
15 | }
16 |
17 | export function state() {
18 | return {
19 | token: getlocalStorageToken() || '',
20 | userInfo: {
21 | username: '',
22 | password: ''
23 | },
24 | screenWidth: 1000,
25 | toggleClosed: false,
26 | isMobile: false
27 | }
28 | }
--------------------------------------------------------------------------------
/src/store/types.ts:
--------------------------------------------------------------------------------
1 | export const SET_TOKEN = 'set_token'
2 | export const CLEAR_TOKEN = 'clear_token'
3 | export const USER_LOGIN = 'user_login'
4 | export const UPDATE_SCREEN_WIDTH = 'update_screen_width'
5 | export const UPDATE_IS_MOBILE = 'update_is_mobile'
6 | export const UPDATE_TOGGLE_TYPE = 'update_toggle_type'
--------------------------------------------------------------------------------
/src/utils/_ls.ts:
--------------------------------------------------------------------------------
1 | const key = 'au-user'
2 |
3 | export function setlocalStorageToken(value: string) {
4 | localStorage.setItem(key, value)
5 | }
6 |
7 | export function removelocalStorageToken() {
8 | localStorage.removeItem(key)
9 | }
10 |
11 | export const getlocalStorageToken: () => string = function(): string {
12 | return localStorage.getItem(key) as string
13 | }
--------------------------------------------------------------------------------
/src/utils/_sign.ts:
--------------------------------------------------------------------------------
1 | import md5 from 'js-md5'
2 | interface TransformData {
3 | [prop: string]: string | number | Array | Object | undefined | null
4 | }
5 | export default function objKeySort(data: TransformData): string {
6 | var newkey = Object.keys(data).sort()
7 | var newObj: TransformData = {}
8 | for (var i = 0; i < newkey.length; i++) {
9 | newObj[newkey[i]] = data[newkey[i]]
10 | }
11 | let signature = 'au'
12 | for (var j = 0; j < newkey.length; j++) {
13 | signature += newObj[newkey[j]]
14 | }
15 | var date = new Date(+new Date() + 8 * 3600 * 1000).toISOString().replace(/T/g, '').replace(/\.[\d]{3}Z/, '')
16 | signature += date.substring(0, 10)
17 | signature += 'au'
18 | signature = md5(signature.toUpperCase())
19 |
20 | data.sign = signature
21 |
22 | return signature
23 | }
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderlyu/vite-frontend-template/51ffa5db33be55e973b3d0c50b63438fcb5b5552/src/utils/index.ts
--------------------------------------------------------------------------------
/src/views/about/au-message.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 未读消息(3)
6 |
7 |
8 | 已读消息(2)
9 |
10 |
11 | 回收站(1)
12 |
13 |
14 |
39 |
50 |
51 |
52 |
124 |
213 |
--------------------------------------------------------------------------------
/src/views/about/au-produce.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
18 |
19 | 你当前等级为 Lv 4,还差 200 分即可升级为 Lv 5
20 |
21 |
22 | 124 / 500
23 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
账号勋章
41 |
42 |
43 |
44 |
45 |
46 |
账号信用
47 |
出现违规行为将会扣除信用分,信用分降低到一定分数会触发账号处罚,并降低微淘号达人指数
48 |
49 | 95分
50 |
51 |
52 |
53 |
活动中心
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | {{ item.time }}
62 |
63 |
64 |
65 |
66 |
77 |
78 |
79 |
126 |
--------------------------------------------------------------------------------
/src/views/about/au-record.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ item.author }}
8 | {{ item.operation }}
9 |
10 |
11 | {{ item.author}}
12 | 操作于
13 | {{ item.date }} {{ item.time }}
14 |
15 |
16 |
17 |
18 |
29 |
30 |
31 |
61 |
102 |
--------------------------------------------------------------------------------
/src/views/about/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 | 创作空间
12 |
13 |
14 |
15 |
16 | 消息中心
17 |
18 |
19 |
20 |
21 | 操作记录
22 |
23 |
24 |
25 |
26 |
27 |
66 |
--------------------------------------------------------------------------------
/src/views/data/au-list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
{{ item.title }}
15 |
文章描述:
16 |
{{ item.content }}
17 |
18 | 创作指导:
19 | {{ item.link }}
20 |
21 |
22 |
23 |
24 | 查看详情
25 | 立即创作
26 |
27 |
28 |
29 |
30 |
41 |
42 |
43 |
61 |
--------------------------------------------------------------------------------
/src/views/data/au-rank.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
10 | {{ index + 1 }}
11 |
{{ item.title }}
12 | {{ item.num }}
13 | 解读
14 |
15 |
16 |
17 |
42 |
113 |
--------------------------------------------------------------------------------
/src/views/data/chart-config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | pie: function (data) {
3 | let options = {
4 | tooltip: {
5 | trigger: 'item'
6 | },
7 | legend: {
8 | orient: 'vertical',
9 | left: 'left',
10 | },
11 | series: [
12 | {
13 | name: '人群特征',
14 | type: 'pie',
15 | radius: '50%',
16 | data: [
17 | { value: 1048, name: '12 ~ 16岁' },
18 | { value: 735, name: '16 ~ 18岁' },
19 | { value: 580, name: '18 ~ 30岁' },
20 | { value: 484, name: '30岁 ~' }
21 | ],
22 | emphasis: {
23 | itemStyle: {
24 | shadowBlur: 10,
25 | shadowOffsetX: 0,
26 | shadowColor: 'rgba(0, 0, 0, 0.5)'
27 | }
28 | }
29 | }
30 | ]
31 | }
32 | return options
33 | },
34 | line: function (data) {
35 | let options = {
36 | xAxis: {
37 | type: 'category',
38 | data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月']
39 | },
40 | yAxis: {
41 | type: 'value'
42 | },
43 | series: [{
44 | data: [820, 932, 901, 934, 1290, 1330, 1320],
45 | type: 'line',
46 | smooth: true
47 | },
48 | {
49 | data: [80, 92, 91, 94, 190, 130, 120],
50 | type: 'line',
51 | smooth: true
52 | }]
53 | };
54 | return options
55 | },
56 | bar: function (data) {
57 | let options = {
58 | xAxis: {
59 | type: 'category',
60 | data: ['2015', '2016', '2017', '2018', '2019', '2020', '2021']
61 | },
62 | yAxis: {
63 | type: 'value'
64 | },
65 | series: [{
66 | data: [120, 200, 150, 80, 70, 110, 130],
67 | type: 'bar',
68 | showBackground: true,
69 | backgroundStyle: {
70 | color: 'rgba(180, 180, 180, 0.2)'
71 | }
72 | }]
73 | }
74 | return options
75 | }
76 | }
--------------------------------------------------------------------------------
/src/views/data/index.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 |
36 |
37 |
38 |
39 |
40 |
79 |
--------------------------------------------------------------------------------
/src/views/data/rank.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 | 人群特征
11 |
12 |
13 |
14 | 曝光量
15 |
16 |
17 |
18 | 访问量
19 |
20 |
21 |
22 |
28 |
29 | 粉丝最新关注点
30 |
31 |
32 |
33 | 热门关注
34 |
35 |
36 |
37 | 群聊话题
38 |
39 |
40 |
41 |
42 |
43 |
87 |
94 |
--------------------------------------------------------------------------------
/src/views/error/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 404
5 |
6 | NOT FOUND
7 | 当前路径不存在或你没有权限访问
8 | 如有疑惑请联系系统管理员
9 | 返回主页
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/views/home/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | CODERLY
12 | 官方认证
13 |
14 |
15 | 认证机构:随意点大学
16 | 认证信息:点到为止
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 当前等级
29 |
30 |
31 |
32 |
33 |
34 |
35 |
代办事项(2)
36 |
37 | 新的一年好好干,今年争取再给你盖栋大楼
38 | 你还差1个小时就超过前一位同事的工时了,是否前去处理
39 |
40 |
查看详情
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | {{ item.title }}
50 | {{ item.num }}
51 |
52 |
53 |
54 |
55 |
59 |
60 |
61 |
120 |
254 |
--------------------------------------------------------------------------------
/src/views/home/notice.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
22 |
23 |
70 |
--------------------------------------------------------------------------------
/src/views/login/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 用户登录
7 |
8 |
9 |
16 |
17 |
18 |
25 |
26 |
27 | 登 录
28 | 注 册
29 |
30 | 账号:admin ,密码:admin
31 |
32 |
33 |
34 |
35 |
36 |
37 |
71 |
160 |
--------------------------------------------------------------------------------
/src/views/profile/au-profile-mobile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 | -
12 |
13 | 性别
14 | {{ formData.sex ? formData.sex : '未知' }}
15 |
16 |
17 |
18 | -
19 |
20 | 一句话介绍
21 | {{ formData.intro }}
22 |
23 |
24 |
25 | -
26 |
27 | 所在行业
28 | {{ formData.work }}
29 |
30 |
31 |
32 | -
33 |
34 | 个人简介
35 | {{ formData.mark }}
36 |
37 |
38 |
39 |
40 |
41 |
42 |
72 |
--------------------------------------------------------------------------------
/src/views/profile/au-profile-pc.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
17 |
18 |
19 |
20 |
21 |
22 | -
23 |
24 |
25 | {{ visibles[0] ? '用户名' : formData.nick }}
26 |
31 |
32 | 修改
33 |
34 |
35 |
42 |
43 |
44 | 返回主页
45 |
46 |
47 |
48 | -
49 |
50 | {{ item.label }}
51 | {{ visibles[index + 1] ? '' : (
52 | item.props === 'sex' ? (formData[item.props] ? formData[item.props] : '未知') :
53 | formData[item.props]
54 | ) }}
55 |
56 |
57 | 修改
58 |
59 |
60 |
68 |
69 |
70 |
71 |
72 |
80 | 编辑头像
81 |
82 |
83 |
84 |
85 | 保 存
86 |
87 |
88 |
89 |
90 |
139 |
254 |
--------------------------------------------------------------------------------
/src/views/profile/au-upload.ts:
--------------------------------------------------------------------------------
1 | import { ref, SetupContext } from 'vue'
2 |
3 | export function uploadState(ctx: SetupContext) {
4 | const imageUrl = ref('data:image/jpeg;base64,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')
5 | const tempUrl = ref('')
6 | const confirmAvatarVisible = ref(false)
7 | const handleAvatarSuccess = (...args: any[]) => {
8 | console.log('handleAvatarSuccess', args)
9 | }
10 | const beforeAvatarUpload = (file: File) => {
11 | const reader = new FileReader()
12 | reader.onload = function(ev){
13 | tempUrl.value = ev!.target!.result as string
14 | confirmAvatarVisible.value = true
15 | }
16 | reader.readAsDataURL(file)
17 | }
18 | const handleConfirmClose = () => {
19 | confirmAvatarVisible.value = false
20 | }
21 | const confirmAvatar = () => {
22 | imageUrl.value = tempUrl.value
23 | confirmAvatarVisible.value = false
24 | }
25 | return {
26 | imageUrl,
27 | tempUrl,
28 | confirmAvatarVisible,
29 | handleAvatarSuccess,
30 | beforeAvatarUpload,
31 | handleConfirmClose,
32 | confirmAvatar
33 | }
34 | }
--------------------------------------------------------------------------------
/src/views/profile/config.js:
--------------------------------------------------------------------------------
1 | export default function ({ }) {
2 | return {
3 | columns: [
4 | {
5 | label: '性别',
6 | props: 'sex'
7 | },
8 | {
9 | label: '一句话介绍',
10 | props: 'intro'
11 | },
12 | {
13 | label: '所在行业',
14 | props: 'work'
15 | },
16 | {
17 | label: '个人简介',
18 | props: 'mark'
19 | }
20 | ],
21 | config: {
22 | nick: { props: 'nick', type: 'input', placeholder: '请输入昵称' },
23 | sex: {
24 | props: 'sex',
25 | type: 'radio',
26 | options: [
27 | {
28 | label: '男',
29 | value: '男'
30 | },
31 | {
32 | label: '女',
33 | value: '女'
34 | }
35 | ]
36 | },
37 | intro: {
38 | props: 'intro',
39 | type: 'input',
40 | placeholder: '请输入一句话介绍'
41 | },
42 | work: {
43 | props: 'work',
44 | type: 'input',
45 | placeholder: '请输入所在行业'
46 | },
47 | mark: {
48 | props: 'mark',
49 | type: 'input',
50 | placeholder: '请输入个人简介'
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/src/views/profile/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "module": "esnext",
5 | "moduleResolution": "node",
6 | "strict": true,
7 | "jsx": "preserve",
8 | "sourceMap": true,
9 | "resolveJsonModule": true,
10 | "esModuleInterop": true,
11 | "lib": ["esnext", "dom"],
12 | "types": ["vite/client", "node", "vite-svg-loader"]
13 | },
14 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
15 | }
16 |
--------------------------------------------------------------------------------