Compare commits

...

3 Commits

Author SHA1 Message Date
luoer 5b8bc70e72 feat: 优化dockerfile配置
自动部署 / build (push) Successful in 16m48s Details
2023-11-03 17:08:22 +08:00
绝弹 2ae413ccb2 feat: 添加文件图标 2023-11-02 22:04:40 +08:00
luoer c84da369cf feat: 添加文件分类功能 2023-11-02 17:37:40 +08:00
42 changed files with 1105 additions and 661 deletions

2
.env
View File

@ -6,7 +6,7 @@ VITE_TITLE = 绝弹项目管理
# 网站副标题
VITE_SUBTITLE = 快速开发web应用的模板工具
# 接口前缀 说明:参见 axios 的 baseURL
VITE_API = /
VITE_API = http://127.0.0.1:3030/
# =====================================================================================
# 开发设置

View File

@ -75,7 +75,6 @@ jobs:
- name: 登陆到部署环境执行更新命令
uses: appleboy/ssh-action@v1.0.0
if: false
with:
host: ${{ env.deploy_host }}
port: ${{ env.deploy_port }}

View File

@ -1,15 +1,23 @@
FROM node:20-alpine as builder
# 指定工作目录方便下一阶段引用
WORKDIR /app
COPY package.json .
COPY pnpm-lock.yaml .
COPY .npmrc .
# 启用pnpm功能(v16+)
RUN corepack enable
RUN pnpm install
# 仅复制依赖相关文件
COPY .npmrc package.json pnpm-lock.yaml .
# 安装依赖利用docker的缓存机制
RUN --mount=type=cache,id=pnpm-store,target=/root/.pnpm-store pnpm install --frozen-lockfile
# 复制其他文件
COPY . .
# 进行打包
RUN pnpm build
FROM nginx:alpine
# 复制产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 复制nginx配置
COPY --from=builder /app/.github/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80

View File

@ -12,7 +12,6 @@
"release": "release-it --config ./scripts/release/index.cjs"
},
"devDependencies": {
"@apidevtools/swagger-parser": "^10.1.0",
"@arco-design/web-vue": "^2.51.1",
"@iconify-json/icon-park-outline": "^1.1.12",
"@release-it/conventional-changelog": "^5.1.1",
@ -34,19 +33,17 @@
"pinia-plugin-persistedstate": "^3.2.0",
"plop": "^3.1.2",
"release-it": "^15.11.0",
"rollup-plugin-visualizer": "^5.9.2",
"swagger-typescript-api": "^12.0.4",
"tsx": "^3.12.9",
"typescript": "^4.9.5",
"unocss": "^0.49.8",
"unplugin-auto-import": "^0.13.0",
"unplugin-vue-components": "^0.23.0",
"unplugin-vue-router": "^0.7.0",
"vite": "^4.4.9",
"vite-plugin-mock": "^3.0.0",
"vite-plugin-pages": "^0.28.0",
"vite-plugin-style-import": "^2.0.0",
"vue": "^3.3.4",
"vue-drag-resize": "^2.0.3",
"vue-router": "^4.2.4",
"vue-tsc": "^1.8.11"
}

View File

@ -1,9 +1,6 @@
lockfileVersion: '6.0'
devDependencies:
'@apidevtools/swagger-parser':
specifier: ^10.1.0
version: 10.1.0
'@arco-design/web-vue':
specifier: ^2.51.1
version: 2.51.1(vue@3.3.4)
@ -67,6 +64,9 @@ devDependencies:
release-it:
specifier: ^15.11.0
version: 15.11.0
rollup-plugin-visualizer:
specifier: ^5.9.2
version: 5.9.2
swagger-typescript-api:
specifier: ^12.0.4
version: 12.0.4
@ -85,15 +85,9 @@ devDependencies:
unplugin-vue-components:
specifier: ^0.23.0
version: 0.23.0(vue@3.3.4)
unplugin-vue-router:
specifier: ^0.7.0
version: 0.7.0(vue-router@4.2.4)(vue@3.3.4)
vite:
specifier: ^4.4.9
version: 4.4.9(less@4.2.0)
vite-plugin-mock:
specifier: ^3.0.0
version: 3.0.0(vite@4.4.9)
vite-plugin-pages:
specifier: ^0.28.0
version: 0.28.0(vite@4.4.9)
@ -103,9 +97,6 @@ devDependencies:
vue:
specifier: ^3.3.4
version: 3.3.4
vue-drag-resize:
specifier: ^2.0.3
version: 2.0.3
vue-router:
specifier: ^4.2.4
version: 4.2.4(vue@3.3.4)
@ -134,37 +125,6 @@ packages:
resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==}
dev: true
/@apidevtools/json-schema-ref-parser@9.0.6:
resolution: {integrity: sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==}
dependencies:
'@jsdevtools/ono': 7.1.3
call-me-maybe: 1.0.2
js-yaml: 3.14.1
dev: true
/@apidevtools/openapi-schemas@2.1.0:
resolution: {integrity: sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==}
engines: {node: '>=10'}
dev: true
/@apidevtools/swagger-methods@3.0.2:
resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==}
dev: true
/@apidevtools/swagger-parser@10.1.0:
resolution: {integrity: sha512-9Kt7EuS/7WbMAUv2gSziqjvxwDbFSg3Xeyfuj5laUODX8o/k/CpsAKiQ8W7/R88eXFTMbJYg6+7uAmOWNKmwnw==}
peerDependencies:
openapi-types: '>=7'
dependencies:
'@apidevtools/json-schema-ref-parser': 9.0.6
'@apidevtools/openapi-schemas': 2.1.0
'@apidevtools/swagger-methods': 3.0.2
'@jsdevtools/ono': 7.1.3
ajv: 8.12.0
ajv-draft-04: 1.0.0(ajv@8.12.0)
call-me-maybe: 1.0.2
dev: true
/@arco-design/color@0.4.0:
resolution: {integrity: sha512-s7p9MSwJgHeL8DwcATaXvWT3m2SigKpxx4JA1BGPHL4gfvaQsmQfrLBDpjOJFJuJ2jG2dMt3R3P8Pm9E65q18g==}
dependencies:
@ -764,10 +724,6 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.15
dev: true
/@jsdevtools/ono@7.1.3:
resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==}
dev: true
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -1023,6 +979,20 @@ packages:
picomatch: 2.3.1
dev: true
/@rollup/pluginutils@5.0.5:
resolution: {integrity: sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@types/estree': 1.0.1
estree-walker: 2.0.2
picomatch: 2.3.1
dev: true
/@sindresorhus/is@5.6.0:
resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==}
engines: {node: '>=14.16'}
@ -1085,10 +1055,6 @@ packages:
resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==}
dev: true
/@types/mockjs@1.0.7:
resolution: {integrity: sha512-OCxXz6hEaJOVpRwuJMiVY5a6LtJcih+br9gwB/Q8ooOBikvk5FpBQ31OlNimXo3EqKha1Z7PFBni+q9m+8NCWg==}
dev: true
/@types/ms@0.7.31:
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
dev: true
@ -1140,7 +1106,7 @@ packages:
hasBin: true
dependencies:
'@ampproject/remapping': 2.2.1
'@rollup/pluginutils': 5.0.4
'@rollup/pluginutils': 5.0.5
'@unocss/config': 0.49.8
'@unocss/core': 0.49.8
'@unocss/preset-uno': 0.49.8
@ -1270,7 +1236,7 @@ packages:
vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0
dependencies:
'@ampproject/remapping': 2.2.1
'@rollup/pluginutils': 5.0.4
'@rollup/pluginutils': 5.0.5
'@unocss/config': 0.49.8
'@unocss/core': 0.49.8
'@unocss/inspector': 0.49.8
@ -1329,26 +1295,6 @@ packages:
'@volar/language-core': 1.10.1
dev: true
/@vue-macros/common@1.8.0(vue@3.3.4):
resolution: {integrity: sha512-auDJJzE0z3uRe3867e0DsqcseKImktNf5ojCZgUKqiVxb2yTlwlgOVAYCgoep9oITqxkXQymSvFeKhedi8PhaA==}
engines: {node: '>=16.14.0'}
peerDependencies:
vue: ^2.7.0 || ^3.2.25
peerDependenciesMeta:
vue:
optional: true
dependencies:
'@babel/types': 7.23.0
'@rollup/pluginutils': 5.0.4
'@vue/compiler-sfc': 3.3.4
ast-kit: 0.11.2
local-pkg: 0.4.3
magic-string-ast: 0.3.0
vue: 3.3.4
transitivePeerDependencies:
- rollup
dev: true
/@vue/babel-helper-vue-transform-on@1.1.5:
resolution: {integrity: sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==}
dev: true
@ -1561,26 +1507,6 @@ packages:
indent-string: 4.0.0
dev: true
/ajv-draft-04@1.0.0(ajv@8.12.0):
resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
peerDependencies:
ajv: ^8.5.0
peerDependenciesMeta:
ajv:
optional: true
dependencies:
ajv: 8.12.0
dev: true
/ajv@8.12.0:
resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==}
dependencies:
fast-deep-equal: 3.1.3
json-schema-traverse: 1.0.0
require-from-string: 2.0.2
uri-js: 4.4.1
dev: true
/ansi-align@3.0.1:
resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
dependencies:
@ -1631,12 +1557,6 @@ packages:
picomatch: 2.3.1
dev: true
/argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
dependencies:
sprintf-js: 1.0.3
dev: true
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
@ -1696,28 +1616,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/ast-kit@0.11.2:
resolution: {integrity: sha512-Q0DjXK4ApbVoIf9GLyCo252tUH44iTnD/hiJ2TQaJeydYWSpKk0sI34+WMel8S9Wt5pbLgG02oJ+gkgX5DV3sQ==}
engines: {node: '>=16.14.0'}
dependencies:
'@babel/parser': 7.22.16
'@rollup/pluginutils': 5.0.4
pathe: 1.1.1
transitivePeerDependencies:
- rollup
dev: true
/ast-kit@0.9.5:
resolution: {integrity: sha512-kbL7ERlqjXubdDd+szuwdlQ1xUxEz9mCz1+m07ftNVStgwRb2RWw+U6oKo08PAvOishMxiqz1mlJyLl8yQx2Qg==}
engines: {node: '>=16.14.0'}
dependencies:
'@babel/parser': 7.22.16
'@rollup/pluginutils': 5.0.4
pathe: 1.1.1
transitivePeerDependencies:
- rollup
dev: true
/ast-types@0.13.4:
resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==}
engines: {node: '>=4'}
@ -1725,16 +1623,6 @@ packages:
tslib: 2.6.2
dev: true
/ast-walker-scope@0.5.0:
resolution: {integrity: sha512-NsyHMxBh4dmdEHjBo1/TBZvCKxffmZxRYhmclfu0PP6Aftre47jOHYaYaNqJcV0bxihxFXhDkzLHUwHc0ocd0Q==}
engines: {node: '>=16.14.0'}
dependencies:
'@babel/parser': 7.22.16
ast-kit: 0.9.5
transitivePeerDependencies:
- rollup
dev: true
/async-retry@1.3.3:
resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==}
dependencies:
@ -1892,15 +1780,6 @@ packages:
run-applescript: 5.0.0
dev: true
/bundle-require@4.0.1:
resolution: {integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
peerDependencies:
esbuild: '>=0.17'
dependencies:
load-tsconfig: 0.2.5
dev: true
/c12@1.4.2:
resolution: {integrity: sha512-3IP/MuamSVRVw8W8+CHWAz9gKN4gd+voF2zm/Ln6D25C2RhytEZ1ABbC8MjKr4BR9rhoV1JQ7jJA158LDiTkLg==}
dependencies:
@ -2224,18 +2103,6 @@ packages:
xdg-basedir: 5.1.0
dev: true
/connect@3.7.0:
resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==}
engines: {node: '>= 0.10.0'}
dependencies:
debug: 2.6.9
finalhandler: 1.1.2
parseurl: 1.3.3
utils-merge: 1.0.1
transitivePeerDependencies:
- supports-color
dev: true
/consola@2.15.3:
resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==}
dev: true
@ -2508,17 +2375,6 @@ packages:
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
dev: true
/debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.0.0
dev: true
/debug@3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
@ -2624,6 +2480,11 @@ packages:
engines: {node: '>=10'}
dev: true
/define-lazy-prop@2.0.0:
resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==}
engines: {node: '>=8'}
dev: true
/define-lazy-prop@3.0.0:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
engines: {node: '>=12'}
@ -2728,10 +2589,6 @@ packages:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: true
/ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
dev: true
/ejs@3.1.9:
resolution: {integrity: sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==}
engines: {node: '>=0.10.0'}
@ -2752,11 +2609,6 @@ packages:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
dev: true
/encodeurl@1.0.2:
resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
engines: {node: '>= 0.8'}
dev: true
/enhanced-resolve@4.5.0:
resolution: {integrity: sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==}
engines: {node: '>=6.9.0'}
@ -2908,10 +2760,6 @@ packages:
engines: {node: '>=12'}
dev: true
/escape-html@1.0.3:
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
dev: true
/escape-string-regexp@1.0.5:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'}
@ -3031,10 +2879,6 @@ packages:
parse-code-context: 1.0.0
dev: true
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-glob@3.3.1:
resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
engines: {node: '>=8.6.0'}
@ -3096,21 +2940,6 @@ packages:
to-regex-range: 5.0.1
dev: true
/finalhandler@1.1.2:
resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==}
engines: {node: '>= 0.8'}
dependencies:
debug: 2.6.9
encodeurl: 1.0.2
escape-html: 1.0.3
on-finished: 2.3.0
parseurl: 1.3.3
statuses: 1.5.0
unpipe: 1.0.0
transitivePeerDependencies:
- supports-color
dev: true
/find-up@2.1.0:
resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==}
engines: {node: '>=4'}
@ -4208,14 +4037,6 @@ packages:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: true
/js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
dependencies:
argparse: 1.0.10
esprima: 4.0.1
dev: true
/js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
@ -4241,10 +4062,6 @@ packages:
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
dev: true
/json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
dev: true
/json-stringify-safe@5.0.1:
resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==}
dev: true
@ -4360,11 +4177,6 @@ packages:
strip-bom: 3.0.0
dev: true
/load-tsconfig@0.2.5:
resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: true
/local-pkg@0.4.3:
resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==}
engines: {node: '>=14'}
@ -4478,13 +4290,6 @@ packages:
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: true
/magic-string-ast@0.3.0:
resolution: {integrity: sha512-0shqecEPgdFpnI3AP90epXyxZy9g6CRZ+SZ7BcqFwYmtFEnZ1jpevcV5HoyVnlDS9gCnc1UIg3Rsvp3Ci7r8OA==}
engines: {node: '>=16.14.0'}
dependencies:
magic-string: 0.30.3
dev: true
/magic-string@0.25.9:
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
dependencies:
@ -4736,10 +4541,6 @@ packages:
engines: {node: '>=10'}
dev: true
/ms@2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
dev: true
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true
@ -5053,13 +4854,6 @@ packages:
resolution: {integrity: sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==}
dev: true
/on-finished@2.3.0:
resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==}
engines: {node: '>= 0.8'}
dependencies:
ee-first: 1.1.1
dev: true
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
@ -5080,6 +4874,15 @@ packages:
mimic-fn: 4.0.0
dev: true
/open@8.4.2:
resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==}
engines: {node: '>=12'}
dependencies:
define-lazy-prop: 2.0.0
is-docker: 2.2.1
is-wsl: 2.2.0
dev: true
/open@9.1.0:
resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==}
engines: {node: '>=14.16'}
@ -5311,11 +5114,6 @@ packages:
parse-path: 7.0.0
dev: true
/parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
dev: true
/pascal-case@3.1.2:
resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
dependencies:
@ -5371,10 +5169,6 @@ packages:
path-root-regex: 0.1.2
dev: true
/path-to-regexp@6.2.1:
resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==}
dev: true
/path-type@3.0.0:
resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==}
engines: {node: '>=4'}
@ -5551,11 +5345,6 @@ packages:
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
dev: true
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
dev: true
/pupa@3.1.0:
resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==}
engines: {node: '>=12.20'}
@ -5755,11 +5544,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
dev: true
/resize-observer-polyfill@1.5.1:
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
dev: true
@ -5834,6 +5618,22 @@ packages:
glob: 7.2.3
dev: true
/rollup-plugin-visualizer@5.9.2:
resolution: {integrity: sha512-waHktD5mlWrYFrhOLbti4YgQCn1uR24nYsNuXxg7LkPH8KdTXVWR9DNY1WU0QqokyMixVXJS4J04HNrVTMP01A==}
engines: {node: '>=14'}
hasBin: true
peerDependencies:
rollup: 2.x || 3.x
peerDependenciesMeta:
rollup:
optional: true
dependencies:
open: 8.4.2
picomatch: 2.3.1
source-map: 0.7.4
yargs: 17.7.2
dev: true
/rollup@3.29.1:
resolution: {integrity: sha512-c+ebvQz0VIH4KhhCpDsI+Bik0eT8ZFEVZEYw0cGMVqIP8zc+gnwl7iXCamTw7vzv2MeuZFZfdx5JJIq+ehzDlg==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
@ -6110,6 +5910,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/source-map@0.7.4:
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
engines: {node: '>= 8'}
dev: true
/sourcemap-codec@1.4.8:
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
deprecated: Please use @jridgewell/sourcemap-codec instead
@ -6149,15 +5954,6 @@ packages:
through: 2.3.8
dev: true
/sprintf-js@1.0.3:
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
dev: true
/statuses@1.5.0:
resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
engines: {node: '>= 0.6'}
dev: true
/std-env@3.4.3:
resolution: {integrity: sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==}
dev: true
@ -6588,7 +6384,7 @@ packages:
/unimport@2.2.4:
resolution: {integrity: sha512-qMgmeEGqqrrmEtm0dqxMG37J6xBtrriqxq9hILvDb+e6l2F0yTnJomLoCCp0eghLR7bYGeBsUU5Y0oyiUYhViw==}
dependencies:
'@rollup/pluginutils': 5.0.4
'@rollup/pluginutils': 5.0.5
escape-string-regexp: 5.0.0
fast-glob: 3.3.1
local-pkg: 0.4.3
@ -6606,7 +6402,7 @@ packages:
/unimport@3.3.0:
resolution: {integrity: sha512-3jhq3ZG5hFZzrWGDCpx83kjPzefP/EeuKkIO1T0MA4Zwj+dO/Og1mFvZ4aZ5WSDm0FVbbdVIRH1zKBG7c4wOpg==}
dependencies:
'@rollup/pluginutils': 5.0.4
'@rollup/pluginutils': 5.0.5
escape-string-regexp: 5.0.0
fast-glob: 3.3.1
local-pkg: 0.4.3
@ -6674,11 +6470,6 @@ packages:
- vite
dev: true
/unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
dev: true
/unplugin-auto-import@0.13.0(@vueuse/core@9.13.0):
resolution: {integrity: sha512-nKMxDbkjM4FRPInFfm7sWrJOKgxfKKwb5yLPP+DEGl/SG0/FtBoW1LnZL4PQfx0FXjertoHO1P/5nDf+RSip2Q==}
engines: {node: '>=14'}
@ -6726,33 +6517,6 @@ packages:
- supports-color
dev: true
/unplugin-vue-router@0.7.0(vue-router@4.2.4)(vue@3.3.4):
resolution: {integrity: sha512-ddRreGq0t5vlSB7OMy4e4cfU1w2AwBQCwmvW3oP/0IHQiokzbx4hd3TpwBu3eIAFVuhX2cwNQwp1U32UybTVCw==}
peerDependencies:
vue-router: ^4.1.0
peerDependenciesMeta:
vue-router:
optional: true
dependencies:
'@babel/types': 7.23.0
'@rollup/pluginutils': 5.0.4
'@vue-macros/common': 1.8.0(vue@3.3.4)
ast-walker-scope: 0.5.0
chokidar: 3.5.3
fast-glob: 3.3.1
json5: 2.2.3
local-pkg: 0.4.3
mlly: 1.4.2
pathe: 1.1.1
scule: 1.0.0
unplugin: 1.5.0
vue-router: 4.2.4(vue@3.3.4)
yaml: 2.3.2
transitivePeerDependencies:
- rollup
- vue
dev: true
/unplugin@1.4.0:
resolution: {integrity: sha512-5x4eIEL6WgbzqGtF9UV8VEC/ehKptPXDS6L2b0mv4FRMkJxRtjaJfOWDd6a8+kYbqsjklix7yWP0N3SUepjXcg==}
dependencies:
@ -6834,12 +6598,6 @@ packages:
tslib: 2.6.2
dev: true
/uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies:
punycode: 2.3.0
dev: true
/url-join@5.0.0:
resolution: {integrity: sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@ -6849,11 +6607,6 @@ packages:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: true
/utils-merge@1.0.1:
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
engines: {node: '>= 0.4.0'}
dev: true
/v8flags@4.0.1:
resolution: {integrity: sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==}
engines: {node: '>= 10.13.0'}
@ -6866,27 +6619,6 @@ packages:
spdx-expression-parse: 3.0.1
dev: true
/vite-plugin-mock@3.0.0(vite@4.4.9):
resolution: {integrity: sha512-Ibwlga2CSgkoFHFtPW3T/l0fwsGVz9Ss5i7HauBQDyDFfMKgbQXh9wKDLksLZHyai9rkDanxJtIcxbD0bUHCfw==}
engines: {node: '>=16.0.0'}
peerDependencies:
mockjs: '>=1.1.0'
vite: '>=4.0.0'
dependencies:
'@types/mockjs': 1.0.7
bundle-require: 4.0.1
chokidar: 3.5.3
connect: 3.7.0
debug: 4.3.4
fast-glob: 3.3.1
path-to-regexp: 6.2.1
picocolors: 1.0.0
vite: 4.4.9(less@4.2.0)
transitivePeerDependencies:
- esbuild
- supports-color
dev: true
/vite-plugin-pages@0.28.0(vite@4.4.9):
resolution: {integrity: sha512-yncDncFVnjUzhqJnwCgGDZoZ/wO6MEOMe93f2MQjplKXm1MpmHCrTkFCPnQyYGZTVKPAN+y7BQcIpNWPFLQ4+w==}
peerDependencies:
@ -6986,10 +6718,6 @@ packages:
vue: 3.3.4
dev: true
/vue-drag-resize@2.0.3:
resolution: {integrity: sha512-5q03tZ/LyvQsg1iHRcqs+wI2OKNbNIWl9+7V8rVL6MxJhZLCIYSSgbAUaDE38LhD6dFd5aJhdgNmES61AxjXuw==}
dev: true
/vue-router@4.2.4(vue@3.3.4):
resolution: {integrity: sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==}
peerDependencies:

View File

@ -10,7 +10,7 @@ const run = async () => {
const output = await generateApi({
url: "http://localhost:3030/openapi.json",
templates: path.resolve(__dirname, "./template"),
output: path.resolve(process.cwd(), "src/api/service"),
output: path.resolve(process.cwd(), "src/api/generated"),
name: "Api.ts",
singleHttpClient: false,
httpClientType: "axios",

1
scripts/vite/fmt.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -152,7 +152,7 @@ export interface CreateRoleDto {
*
* @example "admin"
*/
slug: string;
code: string;
/**
*
* @example "一段很长的描述"
@ -175,7 +175,7 @@ export interface UpdateRoleDto {
*
* @example "admin"
*/
slug?: string;
code?: string;
/**
*
* @example "一段很长的描述"
@ -310,7 +310,7 @@ export interface File {
mimetype: string;
/**
*
* @example "/upload/2021/10/01/xxx.jpg"
* @example "/upload/2021-10-01/xxx.jpg"
*/
path: string;
/**
@ -323,6 +323,11 @@ export interface File {
* @example ".jpg"
*/
extension: string;
/**
* ID
* @example 0
*/
categoryId: number;
/**
* ID
* @example 1
@ -357,12 +362,110 @@ export interface UpdateFileDto {
*
* @example "头像.jpg"
*/
name: string;
name?: string;
/**
*
* @example "一段很长的描述"
*/
description?: string;
/**
* ID
* @example 1
*/
categoryId?: number;
}
export interface CreateFileCategoryDto {
/**
*
* @example "风景"
*/
name: string;
/**
*
* @example "view"
*/
code: string;
/**
*
* @example "这是一段很长的描述"
*/
description?: string;
/**
* ID
* @example 0
*/
parentId?: number;
}
export interface FileCategory {
/**
*
* @example "风景"
*/
name: string;
/**
*
* @example "view"
*/
code: string;
/**
*
* @example "这是一段很长的描述"
*/
description?: string;
/** 父级ID */
parentId?: number;
/**
* ID
* @example 1
*/
id: number;
/**
*
* @format date-time
* @example "2022-01-01 10:10:10"
*/
createdAt: string;
/**
*
* @example "绝弹"
*/
createdBy: string;
/**
*
* @format date-time
* @example "2022-01-02 11:11:11"
*/
updatedAt: string;
/**
*
* @example "绝弹"
*/
updatedBy: string;
}
export interface UpdateFileCategoryDto {
/**
*
* @example "风景"
*/
name?: string;
/**
*
* @example "view"
*/
code?: string;
/**
*
* @example "这是一段很长的描述"
*/
description?: string;
/**
* ID
* @example 0
*/
parentId?: number;
}
export interface CreatePostDto {
@ -985,6 +1088,75 @@ export interface GetLoginLogsParams {
createdFrom?: string;
}
export interface GetFilesParams {
/**
*
* @example "风景"
*/
name?: string;
/**
* ID
* @example 1
*/
categoryId?: number;
/**
*
* @default "id:desc"
* @pattern /^(\w+:\w+,)*\w+:\w+$/
* @example "id:desc"
*/
sort?: string;
/**
*
* @min 1
* @example 1
*/
page?: number;
/**
*
* @min 0
* @example 10
*/
size?: number;
/**
*
* @example "2020-02-02 02:02:02"
*/
createdFrom?: string;
}
export interface GetFileCategorysParams {
/**
*
* @example "风景"
*/
name?: string;
/**
*
* @default "id:desc"
* @pattern /^(\w+:\w+,)*\w+:\w+$/
* @example "id:desc"
*/
sort?: string;
/**
*
* @min 1
* @example 1
*/
page?: number;
/**
*
* @min 0
* @example 10
*/
size?: number;
/**
*
* @example "2020-02-02 02:02:02"
*/
createdFrom?: string;
}
export interface GetPostsParams {
/**
*
@ -1685,10 +1857,84 @@ export namespace File {
*/
export namespace GetFiles {
export type RequestParams = {};
export type RequestQuery = {};
export type RequestQuery = {
/**
*
* @example "风景"
*/
name?: string;
/**
* ID
* @example 1
*/
categoryId?: number;
/**
*
* @default "id:desc"
* @pattern /^(\w+:\w+,)*\w+:\w+$/
* @example "id:desc"
*/
sort?: string;
/**
*
* @min 1
* @example 1
*/
page?: number;
/**
*
* @min 0
* @example 10
*/
size?: number;
/**
*
* @example "2020-02-02 02:02:02"
*/
createdFrom?: string;
};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = Response;
export type ResponseBody = {
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: object;
};
}
/**
* @description
* @tags file
* @name DelFiles
* @request DELETE:/api/v1/file
*/
export namespace DelFiles {
export type RequestParams = {};
export type RequestQuery = {};
export type RequestBody = string[];
export type RequestHeaders = {};
export type ResponseBody = {
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: object;
};
}
/**
* @description
@ -1731,20 +1977,7 @@ export namespace File {
export type RequestQuery = {};
export type RequestBody = UpdateFileDto;
export type RequestHeaders = {};
export type ResponseBody = {
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: string;
};
export type ResponseBody = Response;
}
/**
* @description
@ -1791,6 +2024,149 @@ export namespace File {
}
}
export namespace FileCategory {
/**
* @description
* @tags fileCategory
* @name AddFileCategory
* @request POST:/api/v1/fileCategorys
*/
export namespace AddFileCategory {
export type RequestParams = {};
export type RequestQuery = {};
export type RequestBody = CreateFileCategoryDto;
export type RequestHeaders = {};
export type ResponseBody = {
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: number;
};
}
/**
* @description
* @tags fileCategory
* @name GetFileCategorys
* @request GET:/api/v1/fileCategorys
*/
export namespace GetFileCategorys {
export type RequestParams = {};
export type RequestQuery = {
/**
*
* @example "风景"
*/
name?: string;
/**
*
* @default "id:desc"
* @pattern /^(\w+:\w+,)*\w+:\w+$/
* @example "id:desc"
*/
sort?: string;
/**
*
* @min 1
* @example 1
*/
page?: number;
/**
*
* @min 0
* @example 10
*/
size?: number;
/**
*
* @example "2020-02-02 02:02:02"
*/
createdFrom?: string;
};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = {
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: FileCategory[];
};
}
/**
* @description
* @tags fileCategory
* @name GetFileCategory
* @request GET:/api/v1/fileCategorys/{id}
*/
export namespace GetFileCategory {
export type RequestParams = {
id: number;
};
export type RequestQuery = {};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = {
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: FileCategory;
};
}
/**
* @description
* @tags fileCategory
* @name SetFileCategory
* @request PATCH:/api/v1/fileCategorys/{id}
*/
export namespace SetFileCategory {
export type RequestParams = {
id: number;
};
export type RequestQuery = {};
export type RequestBody = UpdateFileCategoryDto;
export type RequestHeaders = {};
export type ResponseBody = Response;
}
/**
* @description
* @tags fileCategory
* @name DelFileCategory
* @request DELETE:/api/v1/fileCategorys/{id}
*/
export namespace DelFileCategory {
export type RequestParams = {
id: number;
};
export type RequestQuery = {};
export type RequestBody = never;
export type RequestHeaders = {};
export type ResponseBody = Response;
}
}
export namespace Post {
/**
* @description
@ -3183,10 +3559,61 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
* @name GetFiles
* @request GET:/api/v1/file
*/
getFiles: (params: RequestParams = {}) => {
return this.request<Response, any>({
getFiles: (query: GetFilesParams, params: RequestParams = {}) => {
return this.request<
{
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: object;
},
any
>({
path: `/api/v1/file`,
method: "GET",
query: query,
format: "json",
...params,
});
},
/**
*
*
* @tags file
* @name DelFiles
* @request DELETE:/api/v1/file
*/
delFiles: (data: string[], params: RequestParams = {}) => {
return this.request<
{
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: object;
},
any
>({
path: `/api/v1/file`,
method: "DELETE",
body: data,
type: ContentType.Json,
format: "json",
...params,
});
@ -3232,23 +3659,7 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
* @request PATCH:/api/v1/file/{id}
*/
setFile: (id: number, data: UpdateFileDto, params: RequestParams = {}) => {
return this.request<
{
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: string;
},
any
>({
return this.request<Response, any>({
path: `/api/v1/file/${id}`,
method: "PATCH",
body: data,
@ -3306,6 +3717,140 @@ export class Api<SecurityDataType extends unknown> extends HttpClient<SecurityDa
});
},
};
fileCategory = {
/**
*
*
* @tags fileCategory
* @name AddFileCategory
* @request POST:/api/v1/fileCategorys
*/
addFileCategory: (data: CreateFileCategoryDto, params: RequestParams = {}) => {
return this.request<
{
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: number;
},
any
>({
path: `/api/v1/fileCategorys`,
method: "POST",
body: data,
type: ContentType.Json,
format: "json",
...params,
});
},
/**
*
*
* @tags fileCategory
* @name GetFileCategorys
* @request GET:/api/v1/fileCategorys
*/
getFileCategorys: (query: GetFileCategorysParams, params: RequestParams = {}) => {
return this.request<
{
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: FileCategory[];
},
any
>({
path: `/api/v1/fileCategorys`,
method: "GET",
query: query,
format: "json",
...params,
});
},
/**
*
*
* @tags fileCategory
* @name GetFileCategory
* @request GET:/api/v1/fileCategorys/{id}
*/
getFileCategory: (id: number, params: RequestParams = {}) => {
return this.request<
{
/**
*
* @format int32
* @example 2000
*/
code: number;
/**
*
* @example "请求成功"
*/
message: string;
data?: FileCategory;
},
any
>({
path: `/api/v1/fileCategorys/${id}`,
method: "GET",
format: "json",
...params,
});
},
/**
*
*
* @tags fileCategory
* @name SetFileCategory
* @request PATCH:/api/v1/fileCategorys/{id}
*/
setFileCategory: (id: number, data: UpdateFileCategoryDto, params: RequestParams = {}) => {
return this.request<Response, any>({
path: `/api/v1/fileCategorys/${id}`,
method: "PATCH",
body: data,
type: ContentType.Json,
format: "json",
...params,
});
},
/**
*
*
* @tags fileCategory
* @name DelFileCategory
* @request DELETE:/api/v1/fileCategorys/{id}
*/
delFileCategory: (id: number, params: RequestParams = {}) => {
return this.request<Response, any>({
path: `/api/v1/fileCategorys/${id}`,
method: "DELETE",
format: "json",
...params,
});
},
};
post = {
/**
*

View File

@ -1,3 +1,3 @@
export * from "./instance/api";
export * from "./service/Api";
export * from "./helper/useRequest";
export * from "./generated/Api";
export * from "./instance/useRequest";

View File

@ -1,21 +1,7 @@
import { IToastOptions, toast } from "@/components";
import { store, useUserStore } from "@/store";
import { Message } from "@arco-design/web-vue";
import { Api } from "../service/Api";
class Service extends Api<unknown> {
/**
*
*/
tokenExpiredHandler: () => void = () => {};
/**
*
* @param handler
*/
setTokenExpiredHandler(handler: () => void) {
this.tokenExpiredHandler = handler;
}
}
import { Service } from "./service";
import { addToastInterceptor } from "../interceptors/toast";
import { addAuthInterceptor } from "../interceptors/auth";
import { addExceptionInterceptor } from "../interceptors/exception";
/**
* API
@ -26,59 +12,18 @@ const api = new Service({
});
/**
*
*
*/
api.instance.interceptors.request.use(
(config) => {
const userStore = useUserStore(store);
if (userStore.accessToken) {
config.headers.Authorization = `Bearer ${userStore.accessToken}`;
}
if (config.toast) {
let options: IToastOptions = {};
if (typeof config.toast === "string") {
options = { message: config.toast };
}
if (typeof config.toast === "object") {
options = config.toast;
}
config.closeToast = toast(options);
}
return config;
},
(error) => {
error.config?.closeToast?.();
return Promise.reject(error);
}
);
addToastInterceptor(api.instance);
/**
*
*
*/
api.instance.interceptors.response.use(
(res) => {
res.config.closeToast?.();
if (res.data?.code && res.data.code !== 2000) {
return Promise.reject(res);
}
return res;
},
(error) => {
error.config.closeToast?.();
const userStore = useUserStore(store);
if (error.response) {
const code = error.response.data?.code;
if (code === 4050 || code === 4051) {
Message.warning('提示:登陆过期,请重新登陆!')
userStore.clearUser();
api.tokenExpiredHandler?.();
}
} else if (error.request) {
console.log("request error", error.request);
Message.error(`提示:网络异常,请检查网络是否正常或稍后重试!`);
}
return Promise.reject(error);
}
);
addAuthInterceptor(api.instance);
/**
*
*/
addExceptionInterceptor(api.instance, () => api.expireHandler?.());
export { api };

View File

@ -0,0 +1,12 @@
import { Api } from "../generated/Api";
/**
* API
*/
export class Service extends Api<unknown> {
/**
*
* @description
*/
expireHandler: () => void = () => {};
}

View File

@ -0,0 +1,16 @@
import { store, useUserStore } from "@/store";
import { AxiosInstance } from "axios";
/**
*
* @param axios Axios
*/
export function addAuthInterceptor(axios: AxiosInstance) {
axios.interceptors.request.use((config) => {
const userStore = useUserStore(store);
if (userStore.accessToken) {
config.headers.Authorization = `Bearer ${userStore.accessToken}`;
}
return config;
});
}

View File

@ -0,0 +1,51 @@
import { Notification } from "@arco-design/web-vue";
import { AxiosInstance } from "axios";
const successCodes = [2000];
const expiredCodes = [4050, 4051];
let tipShowing = false;
/**
*
* @param axios Axios
*/
export function addExceptionInterceptor(axios: AxiosInstance, exipreHandler?: (...args: any[]) => any) {
axios.interceptors.response.use(
(res) => {
const code = res.data?.code;
if (code && !successCodes.includes(code)) {
return Promise.reject(res);
}
return res;
},
(error) => {
// 服务端响应错误
if (error.response) {
const code = error.response.data?.code;
if (expiredCodes.includes(code)) {
Notification.warning({
title: "登陆提示",
content: "当前登陆已过期,请重新登陆!",
});
exipreHandler?.(error);
}
return Promise.reject(error);
}
// 客户端请求错误
if (error.request) {
if (!tipShowing) {
tipShowing = true;
Notification.error({
title: "请求提示",
content: `请求服务器失败,请检查网络或稍后重试!`,
onClose: () => (tipShowing = false),
});
}
return Promise.reject(error);
}
return Promise.reject(error);
}
);
}

View File

@ -0,0 +1,39 @@
import { IToastOptions, toast } from "@/components";
import { AxiosInstance } from "axios";
/**
*
* @param axios Axios
*/
export function addToastInterceptor(axios: AxiosInstance) {
axios.interceptors.request.use(
(config) => {
if (config.toast) {
let options: IToastOptions = {};
if (typeof config.toast === "string") {
options = { message: config.toast };
}
if (typeof config.toast === "object") {
options = config.toast;
}
config.closeToast = toast(options);
}
return config;
},
(error) => {
error.config.closeToast?.();
return Promise.reject(error);
}
);
axios.interceptors.response.use(
(response) => {
response.config.closeToast?.();
return response;
},
(error) => {
error.config.closeToast?.();
return Promise.reject(error);
}
);
}

View File

@ -75,3 +75,32 @@ export const config = {
return data;
},
};
export function initOptions({ item, model }: any, key = "options") {
if (Array.isArray(item.options)) {
item.nodeProps[key] = item.options;
}
if (item.options && typeof item.options === "object") {
const { value, source } = item.options;
item._updateOptions = async () => {};
}
if (typeof item.options === "function") {
const loadData = item.options;
item.nodeProps[key] = reactive([]);
item._updateOptions = async () => {
let data = await loadData({ item, model });
if (Array.isArray(data?.data?.data)) {
data = data.data.data.map((i: any) => ({
...i,
label: i.name,
value: i.id,
}));
}
if (Array.isArray(data)) {
item.nodeProps[key].splice(0);
item.nodeProps[key].push(...data);
}
};
item._updateOptions();
}
}

View File

@ -16,27 +16,7 @@ import {
TimePicker,
TreeSelect,
} from "@arco-design/web-vue";
const initOptions = ({ item, model }: any, key = "options") => {
if (Array.isArray(item.options)) {
item.nodeProps[key] = item.options;
}
if (typeof item.options === "function") {
const loadData = item.options;
item.nodeProps[key] = reactive([]);
item._updateOptions = async () => {
let data = await loadData({ item, model });
if (Array.isArray(data?.data?.data)) {
data = data.data.data.map((i: any) => ({ label: i.name, value: i.id }));
}
if (Array.isArray(data)) {
item.nodeProps[key].splice(0);
item.nodeProps[key].push(...data);
}
};
item._updateOptions();
}
};
import { initOptions } from "./form-config";
/**
*
@ -114,7 +94,10 @@ export const nodeMap = {
placeholder: "请选择",
allowClear: true,
allowSearch: true,
options: [{}],
options: [],
onChange(value) {
value;
},
} as InstanceType<typeof TreeSelect>["$props"],
init: (arg: any) => initOptions(arg, "data"),
},

View File

@ -6,7 +6,7 @@ const defineColumn = <T extends TableColumn>(column: T) => {
};
export const updateColumn = defineColumn({
title: "更新",
title: "更新用户",
dataIndex: "createdAt",
width: 190,
render({ record }) {
@ -22,7 +22,7 @@ export const updateColumn = defineColumn({
});
export const createColumn = defineColumn({
title: "创建",
title: "创建用户",
dataIndex: "createdAt",
width: 190,
render({ record }) {

View File

@ -1,11 +1,6 @@
import {
TableColumnData as BaseColumn,
TableData as BaseData,
Table as BaseTable,
Message,
} from "@arco-design/web-vue";
import { TableColumnData as BaseColumn, TableData as BaseData, Table as BaseTable } from "@arco-design/web-vue";
import { merge } from "lodash-es";
import { PropType, computed, defineComponent, reactive, ref, watch } from "vue";
import { PropType, computed, defineComponent, reactive, ref } from "vue";
import { Form, FormInstance, FormModal, FormModalInstance, FormModalProps, FormProps } from "../form";
import { config } from "./table.config";
@ -72,7 +67,7 @@ export const Table = defineComponent({
},
setup(props) {
const loading = ref(false);
const tableRef = ref<InstanceType<typeof BaseTable>>()
const tableRef = ref<InstanceType<typeof BaseTable>>();
const searchRef = ref<FormInstance>();
const createRef = ref<FormModalInstance>();
const modifyRef = ref<FormModalInstance>();
@ -81,10 +76,16 @@ export const Table = defineComponent({
const reloadData = () => loadData({ current: 1, pageSize: 10 });
const openModifyModal = (data: any) => modifyRef.value?.open(data);
/**
*
* @param pagination
*/
const loadData = async (pagination: Partial<any> = {}) => {
const merged = { ...props.pagination, ...pagination };
const paging = { page: merged.current, size: merged.pageSize };
const model = searchRef.value?.getModel() ?? {};
// 本地加载
if (Array.isArray(props.data)) {
const filters = Object.entries(model);
const data = props.data.filter((item) => {
@ -99,6 +100,8 @@ export const Table = defineComponent({
props.pagination.total = renderData.value.length;
props.pagination.current = 1;
}
// 远程加载
if (typeof props.data === "function") {
try {
loading.value = true;
@ -107,30 +110,19 @@ export const Table = defineComponent({
renderData.value = data;
props.pagination.total = total;
props.pagination.current = paging.page;
} catch (error) {
const message = config.getApiErrorMessage(error);
if (message) {
Message.error(`提示:${message}`);
}
} finally {
loading.value = false;
}
}
};
watch(
() => props.data,
(data) => {
if (Array.isArray(data)) {
renderData.value = data;
props.pagination.total = data.length;
props.pagination.current = 1;
}
},
{
immediate: true,
watchEffect(() => {
if (Array.isArray(props.data)) {
renderData.value = props.data;
props.pagination.total = props.data.length;
props.pagination.current = 1;
}
);
});
onMounted(() => {
loadData();

View File

@ -248,12 +248,39 @@ export const useAniTable = (options: UseTableOptions): TableReturnType => {
props,
tableRef,
refresh: () => tableRef.value?.reloadData(),
getTableInstance() {
return tableRef.value?.tableRef;
},
getSearchInstance() {
return tableRef.value?.searchRef;
},
getCreateInstance() {
return tableRef.value?.createRef;
},
/**
*
*/
getCreateFormInstance() {
return this.getCreateInstance()?.formRef;
},
/**
*
*/
getModifyInstance() {
return tableRef.value?.modifyRef;
},
/**
*
*/
getModifyFormInstance() {
return this.getModifyInstance()?.formRef;
},
};
const aniTable = defineComponent({
name: "AniTableWrapper",
setup() {
setup(p, { slots }) {
const onRef = (el: TableInstance) => (tableRef.value = el);
return () => <Table ref={onRef} {...props}></Table>;
return () => <Table ref={onRef} {...props}>{slots}</Table>;
},
});
return [aniTable, context];

View File

@ -1,2 +0,0 @@
export * from './nprogress';
export * from './dayjs';

View File

@ -93,13 +93,6 @@ const buttons = [
Message.info("暂无通知");
},
},
{
icon: "icon-park-outline-moon",
tooltip: "主题",
onClick: () => {
appStore.toggleDark();
},
},
{
icon: "icon-park-outline-config",
tooltip: "设置",

View File

@ -56,7 +56,7 @@
<script lang="ts" setup>
import { api } from "@/api";
import { dayjs } from "@/libs";
import { dayjs } from "@/libs/dayjs";
import { useAppStore, useUserStore } from "@/store";
import { FieldRule, Form, Message, Modal, Notification } from "@arco-design/web-vue";
import { reactive } from "vue";
@ -103,8 +103,8 @@ const onSubmitForm = async () => {
const res = await api.auth.login(model);
userStore.setAccessToken(res.data.data as unknown as string);
Notification.success({
title: "提示",
content: `登陆成功!`,
title: "登陆提示",
content: `欢迎,您已成功登陆系统!`,
});
router.push({ path: (route.query.redirect as string) || "/" });
} catch (error: any) {

View File

@ -1,8 +1,8 @@
<template>
<div class="w-[210px] h-full overflow-hidden grid grid-rows-[auto_1fr]">
<div class="flex gap-2">
<a-input-search allow-clear placeholder="分组名称..." class="mb-2"></a-input-search>
<a-button @click="onCreateRow">
<a-input-search allow-clear placeholder="文件分类" class="mb-2"></a-input-search>
<a-button @click="formCtx.open">
<template #icon>
<i class="icon-park-outline-add"></i>
</template>
@ -13,15 +13,15 @@
<ul class="pl-0 mt-0">
<li
v-for="item in list"
:key="item.id"
:key="item.code"
:class="{ active: item.id === current?.id }"
class="group flex items-center justify-between gap-1 h-8 rounded mb-2 pl-3 hover:bg-gray-100 cursor-pointer"
>
<div>
<div class="flex-1 h-full flex items-center gap-2 overflow-hidden" @click="emit('change', item)">
<i class="icon-park-outline-folder-close align-[-2px]"></i>
{{ item.title }}
<span class="text-xs text-gray-500"> ({{ item.count }}) </span>
<span class="flex-1 truncate">{{ item.name }}</span>
</div>
<div>
<div class="">
<a-dropdown>
<a-button size="small" type="text">
<template #icon>
@ -29,13 +29,13 @@
</template>
</a-button>
<template #content>
<a-doption @click="onModifyRow(item)">
<a-doption @click="formCtx.open(item)">
<template #icon>
<i class="icon-park-outline-edit"></i>
</template>
修改
</a-doption>
<a-doption class="!text-red-500" @click="onDeleteRow">
<a-doption class="!text-red-500" @click="onDeleteRow(item)">
<template #icon>
<i class="icon-park-outline-delete"></i>
</template>
@ -51,86 +51,78 @@
</template>
<script setup lang="ts">
import { FileCategory, api } from "@/api";
import { useAniFormModal } from "@/components";
import { delConfirm } from "@/utils";
import { Message } from "@arco-design/web-vue";
import { PropType } from "vue";
const data = [
{
id: 1,
title: "生活笔记",
count: 23,
defineProps({
current: {
type: Object as PropType<FileCategory>,
},
{
id: 2,
title: "微信头像",
count: 52,
},
{
id: 3,
title: "文章封面",
count: 19,
},
{
id: 4,
title: "山水诗画",
count: 81,
},
{
id: 5,
title: "虾米沙雕",
count: 12,
},
];
});
const list = ref(data);
const emit = defineEmits(["change"]);
const list = ref<FileCategory[]>([]);
const onModifyRow = (row: any) => {
formCtx.props.title = "修改分组";
formCtx.open(row);
const updateFileCategories = async () => {
const res = await api.fileCategory.getFileCategorys({ size: 0 });
list.value = res.data.data ?? [];
list.value.unshift({ id: undefined, name: '全部' } as any)
list.value.length && emit("change", list.value[0]);
};
const onCreateRow = () => {
formCtx.props.title = "新建分组";
formCtx.open();
};
onMounted(updateFileCategories);
const onDeleteRow = async () => {
const onDeleteRow = async (row: FileCategory) => {
await delConfirm();
const res = await api.dictType.delDictType(row.id);
Message.success(res.data.message);
};
const [formModal, formCtx] = useAniFormModal({
title: "修改分组",
title: ({ model }) => (!model.id ? "新建分类" : "修改分类"),
trigger: false,
modalProps: {
width: 432,
width: 580,
},
model: {
id: undefined,
},
items: [
{
field: "title",
label: "分名称",
field: "name",
label: "分名称",
type: "input",
},
{
field: "code",
label: "分类编码",
type: "input",
},
{
field: "description",
label: "备注",
type: "textarea",
},
],
submit: async ({ model }) => {
let res;
if (model.id) {
const item = list.value.find((i) => i.id === model.id);
if (item) {
item.title = model.title;
}
res = await api.fileCategory.setFileCategory(model.id, model);
} else {
const ids = list.value.map((i) => i.id);
const maxId = Math.max.apply(null, ids);
list.value.push({
id: maxId,
title: model.title,
count: 0,
});
res = await api.fileCategory.addFileCategory(model);
}
updateFileCategories();
return res;
},
});
</script>
<style lang="less" scoped></style>
<style lang="less" scoped>
.active {
color: rgb(var(--primary-6));
background-color: rgb(var(--primary-1));
}
</style>

View File

@ -36,11 +36,14 @@
<ul v-if="fileList.length" class="h-[424px] overflow-hidden p-0 m-0">
<a-scrollbar outer-class="h-full overflow-hidden" class="h-full overflow-auto pr-[20px] divide-y">
<li v-for="item in fileList" :key="item.uid" class="flex items-center gap-2 py-3">
<div class="text-4xl rounded pr-0.5 flex justify-center">
<i :class="getIcon(item.file?.type ?? 'video')"></i>
</div>
<div class="flex-1 overflow-hidden">
<div class="truncate text-slate-900">
{{ item.name }}
</div>
<div class="flex items-center justify-between gap-2 text-gray-400 mb-[-4px] mt-1">
<div class="flex items-center justify-between gap-2 text-gray-400 mb-[-4px] mt-0.5">
<span class="text-xs text-gray-400">
{{ numeral(item.file?.size).format("0 b") }}
</span>
@ -48,14 +51,14 @@
<span v-if="item.status === 'init'"> </span>
<span v-else-if="item.status === 'uploading'">
<span class="text-xs">
速度{{ numeral(fileMap.get(item.uid)?.speed || 0).format("0 b") }}/s, 进度{{
Math.floor((item.percent || 0) * 100)
}}
%
速度{{ numeral(fileMap.get(item.uid)?.speed || 0).format("0 b") }}/s,
进度{{ Math.floor((item.percent || 0) * 100) }}%
</span>
</span>
<span v-else-if="item.status === 'done'" class="text-green-600">
完成(耗时{{ fileMap.get(item.uid)?.cost || 0 }})
完成(
耗时{{ fileMap.get(item.uid)?.cost || 0 }},
平均{{ numeral(fileMap.get(item.uid)?.aspeed || 0).format("0 b") }}/s)
</span>
<span v-else="item.status === 'error'" class="text-red-500">
失败(原因{{ fileMap.get(item.uid)?.error }})
@ -99,6 +102,7 @@ import { delConfirm } from "@/utils";
import { FileItem, Message, RequestOption, UploadInstance } from "@arco-design/web-vue";
import axios from "axios";
import numeral from "numeral";
import { getIcon } from "./util";
const emit = defineEmits<{
(event: "success", item: FileItem): void;
@ -115,12 +119,16 @@ const fileMap = reactive<
lastTime: number;
lastLoaded: number;
speed: number;
aspeed: number;
cost: number;
error: string;
} | null
>
>(new Map());
/**
* 统计信息
*/
const stat = computed(() => {
const result = {
initCount: 0,
@ -237,6 +245,7 @@ const upload = (option: RequestOption) => {
lastLoaded: 0,
cost: 0,
speed: 0,
aspeed: 0,
error: "网络异常",
});
}
@ -253,6 +262,7 @@ const upload = (option: RequestOption) => {
const nowTime = Date.now();
const diff = (e.loaded - lastLoaded) / (nowTime - lastTime);
const speed = Math.floor(diff * 1000);
item.aspeed = (item.speed + speed) / 2
item.speed = speed;
item.lastLoaded = e.loaded;
item.lastTime = nowTime;

View File

@ -0,0 +1,32 @@
const typeIconMap: Record<string, string> = {
video: "icon-park-outline-video-file",
audio: "icon-park-outline-audio-file",
image: "icon-park-outline-file-pdf",
text: "icon-park-outline-file-txt",
application: "icon-park-outline-file-code",
unknown: "icon-park-outline-file-question",
};
function getIconnameByMimetype(mimetype: string) {
const [type, subtype] = mimetype.split("/");
return typeIconMap[type] || typeIconMap.unknown;
}
function getIcon(mimetype: string) {
if (mimetype.startsWith("image")) {
return "icon-fmt-png";
}
if (mimetype.startsWith("video")) {
return "icon-fmt-video";
}
if (mimetype.startsWith("text")) {
return "icon-fmt-txt";
}
if (mimetype.startsWith("audio")) {
return "icon-fmt-mp";
}
return "icon-fmt-visio";
}
export { getIcon, getIconnameByMimetype };

View File

@ -1,16 +1,16 @@
<template>
<BreadPage>
<div class="overflow-hidden h-full grid grid-cols-[auto_1fr] gap-4">
<ani-group></ani-group>
<ani-group :current="current" @change="onCategoryChange"></ani-group>
<div>
<Table v-bind="table">
<file-table>
<template #action>
<ani-upload></ani-upload>
<a-button type="outline" status="danger" :disabled="!selected.length" @click="onDeleteMany">
<ani-upload @close="onUploadClose"></ani-upload>
<a-button type="primary" status="danger" :disabled="!selected.length" @click="onDeleteMany">
批量删除
</a-button>
</template>
</Table>
</file-table>
<a-image-preview v-model:visible="visible" :src="image"></a-image-preview>
</div>
</div>
@ -18,16 +18,19 @@
</template>
<script setup lang="tsx">
import { api } from "@/api";
import { Table, createColumn, updateColumn, useTable } from "@/components";
import { FileCategory, api } from "@/api";
import { createColumn, updateColumn, useAniTable } from "@/components";
import { delConfirm } from "@/utils";
import { Message } from "@arco-design/web-vue";
import numeral from "numeral";
import AniGroup from "./components/group.vue";
import AniUpload from "./components/upload.vue";
import { getIcon } from "./components/util";
const visible = ref(false);
const image = ref("");
const selected = ref<number[]>([]);
const current = ref<FileCategory>();
const preview = (record: any) => {
if (!record.mimetype.startsWith("image")) {
window.open(record.path, "_blank");
@ -37,29 +40,31 @@ const preview = (record: any) => {
visible.value = true;
};
const onUploadClose = (count: number) => {
if (count) {
fileCtx.refresh();
}
};
const onDeleteMany = async () => {
await delConfirm();
const res = await api.file.delFiles(selected.value as any[]);
selected.value = [];
Message.success(res.data.message);
fileCtx.refresh();
};
const getIcon = (mimetype: string) => {
if (mimetype.startsWith("image")) {
return "icon-file-iimage";
const onCategoryChange = (category: FileCategory) => {
if (fileCtx.props.search?.model) {
fileCtx.props.search.model.categoryId = category.id;
}
if (mimetype.startsWith("video")) {
return "icon-file-ivideo";
}
if (mimetype.startsWith("text")) {
return "icon-file-itxt";
}
if (mimetype.startsWith("audio")) {
return "icon-file-iaudio";
}
return "icon-file-iunknown";
current.value = category;
fileCtx.refresh();
};
const table = useTable({
const [fileTable, fileCtx] = useAniTable({
data: async (model, paging) => {
return api.file.getFiles();
return api.file.getFiles({ ...model, ...paging });
},
tableProps: {
rowSelection: {
@ -73,30 +78,31 @@ const table = useTable({
{
title: "文件名称",
dataIndex: "name",
render({ record }) {
return (
<div class="flex items-center gap-2">
<div>
{record.mimetype.startsWith("image") ? (
<a-avatar size={32} shape="square">
<img src={record.path}></img>
</a-avatar>
) : (
<i class={`${getIcon(record.mimetype)} text-3xl mr-2`}></i>
)}
</div>
<div class="flex flex-col overflow-hidden">
<span
class="hover:text-brand-500 hover:decoration-underline underline-offset-2 cursor-pointer"
onClick={() => preview(record)}
>
{record.name}
</span>
<span class="text-gray-400 text-xs truncate">{numeral(record.size).format("0 b")}</span>
</div>
render: ({ record }) => (
<div class="flex items-center gap-2">
<div class="w-8 flex justify-center">
{record.mimetype.startsWith("image") ? (
<a-avatar size={26} shape="square">
<img src={record.path}></img>
</a-avatar>
) : (
<i class={`${getIcon(record.mimetype)} text-4xl`}></i>
)}
</div>
);
},
<div class="flex flex-col overflow-hidden">
<span
class="hover:text-brand-500 hover:decoration-underline underline-offset-2 cursor-pointer"
onClick={() => preview(record)}
>
{record.name}
</span>
<span class="text-gray-400 text-xs truncate">
{numeral(record.size).format("0 b")}
<span class="ml-2">{record.category?.name}</span>
</span>
</div>
</div>
),
},
createColumn,
updateColumn,
@ -121,6 +127,9 @@ const table = useTable({
],
search: {
button: false,
model: {
categoryId: undefined,
},
items: [
{
field: "name",
@ -143,6 +152,12 @@ const table = useTable({
width: 580,
},
items: [
{
field: "categoryId",
label: "分类",
type: "select",
options: () => api.fileCategory.getFileCategorys({ size: 0 }),
},
{
field: "name",
label: "名称",
@ -167,7 +182,7 @@ const table = useTable({
<route lang="json">
{
"meta": {
"sort": 10304,
"sort": 10305,
"title": "素材管理",
"icon": "icon-park-outline-movie-board"
}

View File

@ -62,7 +62,7 @@
<route lang="json">
{
"meta": {
"sort": 10300,
"sort": 10301,
"title": "文章管理",
"icon": "icon-park-outline-editor"
}

View File

@ -114,6 +114,7 @@ const onOpen = () => {
<route lang="json">
{
"only": "dev",
"meta": {
"sort": 20010,
"title": "接口生成",

14
src/pages/dev/index.vue Normal file
View File

@ -0,0 +1,14 @@
<template>
<div></div>
</template>
<route lang="json">
{
"only": "dev",
"meta": {
"sort": 20010,
"title": "开发相关",
"icon": "icon-park-outline-home"
}
}
</route>

View File

@ -16,15 +16,11 @@
<route lang="json">
{
"only": "dev",
"meta": {
"sort": 20010,
"title": "接口文档",
"icon": "icon-park-outline-api"
},
"parentMeta": {
"sort": 20010,
"title": "开发相关",
"icon": "icon-park-outline-home"
}
}
</route>

View File

@ -37,16 +37,14 @@ const [dictTable, dict] = useAniTable({
{
title: "字典项",
dataIndex: "name",
render: ({ record }) => {
return (
render: ({ record }) => (
<div>
<div>
<div>
<span class="text-gray-900">{record.name}</span>: {record.code}
</div>
<div class="text-gray-400 text-xs">{record.description}</div>
{record.name}<span class="text-gray-400 ml-2 text-xs">{record.code}</span>
</div>
);
},
<div class="text-gray-400 text-xs">{record.description}</div>
</div>
),
},
createColumn,
updateColumn,
@ -88,7 +86,7 @@ const [dictTable, dict] = useAniTable({
],
},
create: {
title: '新增字典',
title: "新增字典",
model: {
typeId: undefined,
},

View File

@ -1,10 +1,6 @@
<template>
<bread-page class="">
<menu-table>
<template #action>
<a-button type="outline">展开/折叠</a-button>
</template>
</menu-table>
<menu-table> </menu-table>
</bread-page>
</template>
@ -13,6 +9,7 @@ import { api } from "@/api";
import { createColumn, updateColumn, useAniTable } from "@/components";
import { MenuTypes, MenuType } from "@/constants/menu";
import { flatedMenus } from "@/router";
import { listToTree } from "@/utils/listToTree";
const menuArr = flatedMenus.map((i) => ({ label: i.title, value: i.id }));
@ -24,23 +21,21 @@ const toggleExpand = () => {
const [menuTable, menu] = useAniTable({
data: (search, paging) => {
return api.menu.getMenus({ ...search, ...paging, tree: true });
return api.menu.getMenus({ ...search, ...paging, tree: true, size: 0 });
},
tableProps: {
defaultExpandAllRows: true,
},
columns: [
{
title: () => {
return (
<span>
菜单名称
<a-link class="ml-1 select-none" onClick={toggleExpand}>
{expanded.value ? "收起全部" : "展开全部"}
</a-link>
</span>
);
},
title: () => (
<span>
菜单名称
<a-link class="ml-1 select-none" onClick={toggleExpand}>
{expanded.value ? "收起全部" : "展开全部"}
</a-link>
</span>
),
dataIndex: "name",
render({ record }) {
let id = "";
@ -125,19 +120,24 @@ const [menuTable, menu] = useAniTable({
label: "父级",
type: "treeSelect",
async options() {
const res = await api.menu.getMenus({ size: 0, tree: true });
const data = res.data.data;
const res = await api.menu.getMenus({ size: 0 });
const data = res.data.data?.filter((i) => i.type !== MenuType.BUTTON) ?? [];
for (const item of data) {
const type = MenuTypes.fmt(item.type);
// @ts-ignore
item.icon = () => `[${type}]`;
}
const list = listToTree(data);
return [
{
id: 0,
name: "主类目",
children: data,
children: list,
},
];
},
nodeProps: {
fieldNames: {
icon: undefined,
key: "id",
title: "name",
},

View File

@ -4,6 +4,7 @@ import { progressGuard } from "../guards/guard-progress";
import { titleGuard } from "../guards/guard-title";
import { routes } from "../routes";
import { api } from "@/api";
import { store, useUserStore } from "@/store";
export const router = createRouter({
history: createWebHashHistory(),
@ -21,7 +22,9 @@ router.afterEach(progressGuard.after);
router.beforeEach(authGuard);
router.afterEach(titleGuard);
api.setTokenExpiredHandler(() => {
api.expireHandler = () => {
const userStore = useUserStore(store);
userStore.clearUser();
const redirect = router.currentRoute.value.path;
router.push({ path: "/login", query: { redirect } });
});
};

View File

@ -10,6 +10,7 @@
"vite.config.ts",
"scripts/vite/**/*.ts",
"scripts/vite/file.json",
"scripts/vite/fmt.json",
"package.json",
"src/types/env.d.ts"
]

View File

@ -10,7 +10,9 @@ import { defineConfig, loadEnv } from "vite";
import Page from "vite-plugin-pages";
import { arcoToUnoColor } from "./scripts/vite/color";
import iconFile from "./scripts/vite/file.json";
import iconFmt from "./scripts/vite/fmt.json";
import plugin from "./scripts/vite/plugin";
import { visualizer } from "rollup-plugin-visualizer";
/**
* vite
@ -63,7 +65,14 @@ export default defineConfig(({ mode }) => {
* @see https://github.com/hannoeru/vite-plugin-pages
*/
Page({
exclude: ["**/components/*.vue", "**/*.*.vue"],
exclude: ["**/components/*", "**/*.*.*"],
importMode: "async",
onRoutesGenerated(routes) {
// if (env.DEV) {
// return routes;
// }
return routes.filter((route) => route.only !== "dev");
},
}),
/**
@ -83,11 +92,21 @@ export default defineConfig(({ mode }) => {
prefix: "",
collections: {
"icon-file": iconFile,
"icon-fmt": iconFmt,
},
}),
],
}),
/**
*
* @see https://github.com/btd/rollup-plugin-visualizer
*/
visualizer({
title: "产物分析 | 自动生成",
filename: ".gitea/stat.html",
}),
/**
*
* @see ./scripts/vite/plugin.ts