Compare commits
550
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1606dbd76f | ||
|
|
3c2d9100b5 | ||
|
|
2c8873402f | ||
|
|
e5727893bb | ||
|
|
335a1e6019 | ||
|
|
c0ee3182e1 | ||
|
|
9eb7b433b4 | ||
|
|
9193f0b84a | ||
|
|
076fc5deb1 | ||
|
|
58412035ad | ||
|
|
964db2dfce | ||
|
|
d58a75996e | ||
|
|
f5a5aaa255 | ||
|
|
1465a27a6e | ||
|
|
e5e43fe024 | ||
|
|
6c49b47344 | ||
|
|
358f11a0a3 | ||
|
|
6a83ed2aad | ||
|
|
e07c0b2b3a | ||
|
|
adadfcf8cb | ||
|
|
425386f6f4 | ||
|
|
ba24afce52 | ||
|
|
93d3371768 | ||
|
|
3f08ae6ac4 | ||
|
|
cc6284d3ac | ||
|
|
142effd4f2 | ||
|
|
e657a507e3 | ||
|
|
ebaec24213 | ||
|
|
7637582437 | ||
|
|
27d36f7970 | ||
|
|
762ebd4ede | ||
|
|
ad991e248a | ||
|
|
d1b58f0aaa | ||
|
|
1be1eaf7b4 | ||
|
|
fbcc967b14 | ||
|
|
817c65f7e2 | ||
|
|
b6dcc62f9c | ||
|
|
abb4f543b9 | ||
|
|
71f4d36c21 | ||
|
|
d1be442c6e | ||
|
|
9ef7fd3844 | ||
|
|
fec61f9650 | ||
|
|
c206ab5b4a | ||
|
|
fe1942c247 | ||
|
|
1f2add4b6b | ||
|
|
3b254cc16b | ||
|
|
3e7c2f26fa | ||
|
|
4143285ec6 | ||
|
|
72610ab194 | ||
|
|
3c713c9258 | ||
|
|
f95f6e8390 | ||
|
|
2c9c837c1b | ||
|
|
7904496df1 | ||
|
|
15c3d84ca2 | ||
|
|
e8a641f3a3 | ||
|
|
e354db74a7 | ||
|
|
61df97c4b9 | ||
|
|
75ecc4dd68 | ||
|
|
c467d95703 | ||
|
|
3fead37924 | ||
|
|
c8626b6893 | ||
|
|
38df345078 | ||
|
|
212361dc94 | ||
|
|
f237ee145a | ||
|
|
291d4b0040 | ||
|
|
64c56e9dd9 | ||
|
|
57d87df589 | ||
|
|
9de3f25f6a | ||
|
|
d98c2822d5 | ||
|
|
58e6fdef78 | ||
|
|
2c9daae153 | ||
|
|
c2fdbc66b2 | ||
|
|
57fd309907 | ||
|
|
7a335b3438 | ||
|
|
83bbac303e | ||
|
|
eb1b614eb1 | ||
|
|
a63543a5c7 | ||
|
|
3585761b81 | ||
|
|
34290d8cad | ||
|
|
f367b49dd6 | ||
|
|
7df347c1d4 | ||
|
|
ea106e44be | ||
|
|
b2e47f3938 | ||
|
|
b8e0f018f0 | ||
|
|
4ee46819c1 | ||
|
|
0c620ef5b4 | ||
|
|
9b00aaff93 | ||
|
|
b829867a5b | ||
|
|
736225fbfe | ||
|
|
3062c46b49 | ||
|
|
ed66231d19 | ||
|
|
3b8ecadc78 | ||
|
|
322e88d8e1 | ||
|
|
526ca728e1 | ||
|
|
26c0cdaef6 | ||
|
|
e7dc8e94c7 | ||
|
|
72ca7a1aae | ||
|
|
907dc4efb4 | ||
|
|
935a199f71 | ||
|
|
a19ac2d4ca | ||
|
|
437bc936fd | ||
|
|
0b8f48fb61 | ||
|
|
5d641e5de4 | ||
|
|
0d196e47e2 | ||
|
|
012e70c7e4 | ||
|
|
9243eee3c3 | ||
|
|
c449fb60a5 | ||
|
|
4660aa6e95 | ||
|
|
9968d14c39 | ||
|
|
e2254651ca | ||
|
|
7ed5f33e7b | ||
|
|
175c4a48ce | ||
|
|
9bcc4d631b | ||
|
|
861dc9fb16 | ||
|
|
8633a23d28 | ||
|
|
d67bd493c1 | ||
|
|
2d532d636a | ||
|
|
e2bdae5bf2 | ||
|
|
2df121072b | ||
|
|
7016888d5a | ||
|
|
3c34421bd2 | ||
|
|
187ae83731 | ||
|
|
c4c9905a91 | ||
|
|
219f3a7d6f | ||
|
|
44837e975c | ||
|
|
8c6cf5bc43 | ||
|
|
c21f0d7d77 | ||
|
|
8b6b624f6c | ||
|
|
03c736af82 | ||
|
|
7386e69033 | ||
|
|
2f60c96fbf | ||
|
|
45e1c46ce4 | ||
|
|
d7d3105c5c | ||
|
|
4aa42f5c20 | ||
|
|
c089f2497c | ||
|
|
e18dcbd86b | ||
|
|
a541d61c0c | ||
|
|
4b19f55bce | ||
|
|
b5042d13d2 | ||
|
|
b444f2b8e2 | ||
|
|
6b982984ac | ||
|
|
30f271359a | ||
|
|
9967a72e24 | ||
|
|
efeff40f2e | ||
|
|
2e299b58e2 | ||
|
|
1d7c3da86b | ||
|
|
5057976ad2 | ||
|
|
41f3d37db1 | ||
|
|
1fbc5afe75 | ||
|
|
b0541be0b8 | ||
|
|
d6803783ae | ||
|
|
945eec5418 | ||
|
|
73db6deec3 | ||
|
|
40a75dae31 | ||
|
|
64fb2899c9 | ||
|
|
9da3f1f2d7 | ||
|
|
70120a8f2f | ||
|
|
6b4d756a9d | ||
|
|
905426ad45 | ||
|
|
b4b0eba228 | ||
|
|
9f73ea2d32 | ||
|
|
2d804c7ce0 | ||
|
|
11e8e9d19a | ||
|
|
3e44c14286 | ||
|
|
04f1347ddd | ||
|
|
0442bd638d | ||
|
|
aeac77b90f | ||
|
|
b117a6f198 | ||
|
|
e1b03258e8 | ||
|
|
c71eb21416 | ||
|
|
c922ea3b9c | ||
|
|
d76f2b857d | ||
|
|
eec050a2dd | ||
|
|
b0087d1a50 | ||
|
|
4752b4eb01 | ||
|
|
2ea1807f34 | ||
|
|
5dfc25a493 | ||
|
|
c5b3c121c9 | ||
|
|
c417c6debe | ||
|
|
f6727d80b8 | ||
|
|
ceb6243cd0 | ||
|
|
cd129aa949 | ||
|
|
d186c800f0 | ||
|
|
31f4219f3d | ||
|
|
ad8565d29a | ||
|
|
66a31b620b | ||
|
|
e26f6423aa | ||
|
|
12461f4106 | ||
|
|
58422616e2 | ||
|
|
f6abd4cf59 | ||
|
|
f50ed6b2c5 | ||
|
|
3dba22c47c | ||
|
|
e1289d0abb | ||
|
|
9ea8b710ff | ||
|
|
e889348562 | ||
|
|
02daeead57 | ||
|
|
4253b2afbb | ||
|
|
0c39b593ce | ||
|
|
8761392c85 | ||
|
|
30cf3a2caa | ||
|
|
12458177be | ||
|
|
b6415c21be | ||
|
|
bc4358f4eb | ||
|
|
5dcfee4c07 | ||
|
|
a9cd5684b2 | ||
|
|
1c0e614d7d | ||
|
|
00a7a8ce23 | ||
|
|
ade0b3e29e | ||
|
|
3a3f873834 | ||
|
|
1edc953765 | ||
|
|
1383f5a7eb | ||
|
|
e4f18452c7 | ||
|
|
fdf64a6f08 | ||
|
|
f46a333778 | ||
|
|
eb364873d2 | ||
|
|
7666f724df | ||
|
|
f9b8922bed | ||
|
|
fb94a4d79c | ||
|
|
71047fdbfd | ||
|
|
2cb9b3ea47 | ||
|
|
3c27c18889 | ||
|
|
9defb9a669 | ||
|
|
8833eb205b | ||
|
|
15129079d4 | ||
|
|
d1c199d4bf | ||
|
|
97b4eef342 | ||
|
|
1dd9983f0f | ||
|
|
b8eb2dcb40 | ||
|
|
3b4f171d9f | ||
|
|
de33d4aaee | ||
|
|
803d44cac0 | ||
|
|
cc293536e2 | ||
|
|
5f6057253f | ||
|
|
d50c90afd1 | ||
|
|
6f9851a4e5 | ||
|
|
e7ff829502 | ||
|
|
0108df1334 | ||
|
|
542f73f0e6 | ||
|
|
5cb40abe18 | ||
|
|
26cfa7afc4 | ||
|
|
df1a84d5ae | ||
|
|
5b991be4c2 | ||
|
|
34c0d2d277 | ||
|
|
b2f00c4b71 | ||
|
|
63ba90cc10 | ||
|
|
3b18a476b7 | ||
|
|
15243ab713 | ||
|
|
b4cc7b3de0 | ||
|
|
fe3874396d | ||
|
|
fdf885c261 | ||
|
|
7b7377fa1b | ||
|
|
0c56f87e06 | ||
|
|
b783b8d991 | ||
|
|
4ea7376dbc | ||
|
|
5910032908 | ||
|
|
024783588e | ||
|
|
acba493c94 | ||
|
|
7073acb3ef | ||
|
|
075c02b8c3 | ||
|
|
31da01bdd1 | ||
|
|
dfdcee9b95 | ||
|
|
d3b630076a | ||
|
|
173c723c7c | ||
|
|
595a521a3c | ||
|
|
d08f14d86d | ||
|
|
b112b793d5 | ||
|
|
6432d165c7 | ||
|
|
e5772cb63c | ||
|
|
bb696b300f | ||
|
|
14f6a214f2 | ||
|
|
bbcedd02ba | ||
|
|
abf2777b2e | ||
|
|
3922c16601 | ||
|
|
321f21c498 | ||
|
|
085ce4cf43 | ||
|
|
c5daf629d9 | ||
|
|
20b7819f11 | ||
|
|
8b36cac09d | ||
|
|
0e99163f0c | ||
|
|
772885de35 | ||
|
|
1d557a24f9 | ||
|
|
597f2b4461 | ||
|
|
cc9b67d467 | ||
|
|
70a3348954 | ||
|
|
2c95f86963 | ||
|
|
1272e8fe7d | ||
|
|
3204aa8461 | ||
|
|
5d44f9e231 | ||
|
|
1d5133b695 | ||
|
|
031d83828a | ||
|
|
0541af5abb | ||
|
|
1f71044cff | ||
|
|
f32a7105c3 | ||
|
|
b06f6a316b | ||
|
|
58d7e50de3 | ||
|
|
c045276a7c | ||
|
|
6a7ec81168 | ||
|
|
183e0e9212 | ||
|
|
c020c1affc | ||
|
|
9673380f60 | ||
|
|
9b28d14bc3 | ||
|
|
01a4dd0b45 | ||
|
|
e1023bb331 | ||
|
|
5c701801db | ||
|
|
9b4692b625 | ||
|
|
aaec0f7bfe | ||
|
|
25e2e0e018 | ||
|
|
5165541780 | ||
|
|
b3c1b95437 | ||
|
|
d84fee9319 | ||
|
|
d034236ce3 | ||
|
|
9e89ab5bae | ||
|
|
6e6062e824 | ||
|
|
35bebf403c | ||
|
|
0a8c33c3cb | ||
|
|
8a7de17b58 | ||
|
|
f65eb2aee5 | ||
|
|
efb53d4bcb | ||
|
|
ad2134f07d | ||
|
|
caa9d0fcdc | ||
|
|
b829ba4aa0 | ||
|
|
a232437abc | ||
|
|
f2372d3243 | ||
|
|
a8a334b3c3 | ||
|
|
1e3f18ce22 | ||
|
|
631f338be2 | ||
|
|
bf977fe00a | ||
|
|
5bc7044032 | ||
|
|
6ad0ed5316 | ||
|
|
ccb2ecc5ee | ||
|
|
ec0cb472df | ||
|
|
cd0a459c2b | ||
|
|
18fea86a2c | ||
|
|
66bfff450c | ||
|
|
ec34c759ec | ||
|
|
c1c5ea5e9d | ||
|
|
6fe269efc7 | ||
|
|
920e079727 | ||
|
|
a2f13185e1 | ||
|
|
078bb50130 | ||
|
|
4854d8df00 | ||
|
|
ecf062605d | ||
|
|
b989b07121 | ||
|
|
bf957f06a0 | ||
|
|
aed8c89ded | ||
|
|
4085811d24 | ||
|
|
fe384a3020 | ||
|
|
c6f3cd068e | ||
|
|
99a6b56233 | ||
|
|
8ed32775cb | ||
|
|
395db813b5 | ||
|
|
ab1a7204fa | ||
|
|
92b2b489a4 | ||
|
|
956d2ad495 | ||
|
|
cb6cbc4f40 | ||
|
|
14538ce399 | ||
|
|
6c16d023f4 | ||
|
|
d12d21c46d | ||
|
|
93fb212e0c | ||
|
|
b22d0775b7 | ||
|
|
c85f0a1995 | ||
|
|
78d120c423 | ||
|
|
e43149f8e6 | ||
|
|
1d8664ab1d | ||
|
|
e7529fbb8f | ||
|
|
e10f112fa0 | ||
|
|
e906b8ad0a | ||
|
|
1690563ef0 | ||
|
|
9087fad3fe | ||
|
|
f3195be732 | ||
|
|
73df6a1b30 | ||
|
|
b221ff2566 | ||
|
|
50891e99ac | ||
|
|
53ac5fb43c | ||
|
|
7e54fe7921 | ||
|
|
3637c16d86 | ||
|
|
b045cb4239 | ||
|
|
0c791a1efc | ||
|
|
0082354aba | ||
|
|
acbdfc4639 | ||
|
|
f801f4fb11 | ||
|
|
d532dc6fc0 | ||
|
|
452972c1e4 | ||
|
|
ac3ad63894 | ||
|
|
d69f0992c7 | ||
|
|
e64f4b83c8 | ||
|
|
2b1cbaf8a0 | ||
|
|
6c86aa42fd | ||
|
|
e79a9cf797 | ||
|
|
4af9f025b0 | ||
|
|
2a1d0edd4e | ||
|
|
75e72bf974 | ||
|
|
1d33b01c66 | ||
|
|
73c14596ed | ||
|
|
5fa3f9a350 | ||
|
|
64aea65cef | ||
|
|
a681353fe1 | ||
|
|
9719d6d75c | ||
|
|
c13c622eac | ||
|
|
d160c3a61c | ||
|
|
81195fd9c8 | ||
|
|
d0d67b90bc | ||
|
|
9e3dd2c6e3 | ||
|
|
5920b10514 | ||
|
|
617dfe3161 | ||
|
|
40175c150c | ||
|
|
d930b15104 | ||
|
|
cc69786fd1 | ||
|
|
4cf836055a | ||
|
|
88b376bbc2 | ||
|
|
3fb8f1c251 | ||
|
|
a8f575fe6f | ||
|
|
14cf3be392 | ||
|
|
6e3aec7c50 | ||
|
|
2b7ffdf19c | ||
|
|
db6e95bb96 | ||
|
|
7b6078a178 | ||
|
|
892c84f32a | ||
|
|
9b6dc3e844 | ||
|
|
3b4950e0e3 | ||
|
|
7340997cf5 | ||
|
|
3b4ac3e525 | ||
|
|
cab430a428 | ||
|
|
538c52a3ad | ||
|
|
25e80590f6 | ||
|
|
7f68832edd | ||
|
|
374ee5d1a8 | ||
|
|
d557602f2d | ||
|
|
18dd68edd5 | ||
|
|
13bb23c717 | ||
|
|
319b37fe98 | ||
|
|
a8ed066d8d | ||
|
|
40e3bcb391 | ||
|
|
aae6bb7505 | ||
|
|
952a2ba906 | ||
|
|
3b3fb80231 | ||
|
|
a46c511f1f | ||
|
|
ed84745897 | ||
|
|
44ea10d9c7 | ||
|
|
41d140af11 | ||
|
|
0f54604435 | ||
|
|
d43ae50abc | ||
|
|
9f038ad181 | ||
|
|
dbfe263681 | ||
|
|
6af68085ff | ||
|
|
490d4ef47e | ||
|
|
bc48b224eb | ||
|
|
9cd7f6cabb | ||
|
|
3267f59603 | ||
|
|
bc4554baeb | ||
|
|
e6a3b6360f | ||
|
|
548550bb42 | ||
|
|
7c09eb50a7 | ||
|
|
d6cb1c6634 | ||
|
|
cbff04778b | ||
|
|
f6994e5908 | ||
|
|
06bc04c04c | ||
|
|
226e0f3494 | ||
|
|
7757d96f34 | ||
|
|
a8ad928324 | ||
|
|
f0df76aa8b | ||
|
|
0ede92a2e5 | ||
|
|
21ab064cf7 | ||
|
|
84212c0a1b | ||
|
|
6de98250cc | ||
|
|
997f565add | ||
|
|
a326e663cd | ||
|
|
bf4a8543ca | ||
|
|
9b6cd8b047 | ||
|
|
46e7d070a2 | ||
|
|
ec29c057c4 | ||
|
|
2885d7e31c | ||
|
|
0e736c889f | ||
|
|
d192f73ca4 | ||
|
|
351eedacec | ||
|
|
67864e67b3 | ||
|
|
f5a21c9b6f | ||
|
|
b9dccb325f | ||
|
|
7cfaeb5531 | ||
|
|
94f96181f3 | ||
|
|
5dda9da40d | ||
|
|
1eda36201a | ||
|
|
4722a8ef9b | ||
|
|
0ba7e31e09 | ||
|
|
61417032b7 | ||
|
|
a0bcdf0cde | ||
|
|
b263918426 | ||
|
|
771f49354a | ||
|
|
ab12c9cc94 | ||
|
|
2976130876 | ||
|
|
2ddd42bbab | ||
|
|
f2d1522c34 | ||
|
|
fda317b628 | ||
|
|
f153da4390 | ||
|
|
20f64b54d5 | ||
|
|
4775803427 | ||
|
|
d2bce3fcbe | ||
|
|
55e29ce697 | ||
|
|
802f6240d4 | ||
|
|
91bb79e29f | ||
|
|
fb14197b0e | ||
|
|
e2bc12d186 | ||
|
|
b88a09dd7f | ||
|
|
2ede1095a3 | ||
|
|
c32e3ce2c9 | ||
|
|
c25842a0e5 | ||
|
|
e7c777ac50 | ||
|
|
1a5ed27067 | ||
|
|
fed8eb76f6 | ||
|
|
f9298a3f41 | ||
|
|
155f22b72c | ||
|
|
dd01200e2a | ||
|
|
35eafbb065 | ||
|
|
a05a782ef5 | ||
|
|
14b4508b91 | ||
|
|
8111ed9a84 | ||
|
|
9a070b0074 | ||
|
|
a79fa2527a | ||
|
|
c65536ee6f | ||
|
|
ccbe849103 | ||
|
|
f0b52d7abb | ||
|
|
d37e031014 | ||
|
|
07a9b6e612 | ||
|
|
f4522d2caa | ||
|
|
582df2e467 | ||
|
|
8c866f4596 | ||
|
|
3b3f26f610 | ||
|
|
d4ffd28ffb | ||
|
|
ee59b3be8b | ||
|
|
97187b246b | ||
|
|
a7a31b011a | ||
|
|
1595cb282a | ||
|
|
8b01bfd2a0 | ||
|
|
60d064b319 | ||
|
|
cc0bedffb9 | ||
|
|
3b93c8ac56 | ||
|
|
631a831609 | ||
|
|
327e60d9f3 | ||
|
|
457b443404 | ||
|
|
0408b67d6d | ||
|
|
c7c63c51de | ||
|
|
d95fab75a7 | ||
|
|
251d2411f2 | ||
|
|
5c87f1cb2c | ||
|
|
d2a44d682d | ||
|
|
4a5ba86e38 | ||
|
|
eec0fd43a3 | ||
|
|
8fec6cc405 | ||
|
|
6b6c78fa02 | ||
|
|
d68654327a |
@@ -1,60 +0,0 @@
|
||||
---
|
||||
name: frontend-api-types
|
||||
description: 前端 API 与类型定义专家。用于当前 plus-ui-react 项目中的 src/api 层、types.ts、返回结构、Query/Form/VO/InfoVO 定义,以及前后端接口映射任务。
|
||||
---
|
||||
|
||||
你负责当前 plus-ui-react 项目中的 API 层和类型定义。
|
||||
|
||||
## 核心原则
|
||||
|
||||
1. 先看当前模块已有 `src/api/<module>/<business>`。
|
||||
2. API 路径、返回类型、函数命名、导出风格与当前模块保持一致。
|
||||
3. 能明确写出类型时,不要偷懒用 `any`。
|
||||
4. 如果当前模块已有特殊返回结构或聚合导出,继续保持一致。
|
||||
5. 不创建页面,不改路由,除非用户明确要求。
|
||||
6. 如果用户要求维护代码生成模板,优先同步当前仓库 `gen/api.ts.ftl`、`gen/types.ts.ftl`,必要时再看 boot4 后端 generator 字段定义。
|
||||
|
||||
## API 规则
|
||||
|
||||
- 标准 import:
|
||||
`import type { PageResult, R } from '@/api/types';`
|
||||
`import request from '@/api/request';`
|
||||
`import type { XxxForm, XxxQuery, XxxVO } from './types';`
|
||||
- 分页列表:`GET /<module>/<business>/list`,返回 `R<PageResult<XxxVO>>`。
|
||||
- 树表列表:返回 `R<XxxVO[]>`。
|
||||
- 详情:`GET /<module>/<business>/{id}`,返回 `R<XxxVO>` 或业务 `InfoVO`。
|
||||
- 新增:`POST /<module>/<business>`,请求体用 `data`。
|
||||
- 修改:`PUT /<module>/<business>`,请求体用 `data`。
|
||||
- 删除:`DELETE /<module>/<business>/{id or ids}`。
|
||||
- 状态切换:`PUT /<module>/<business>/changeStatus`,参数形态参考后端和相邻模块。
|
||||
- query string 用 `params`,请求体用 `data`。
|
||||
- 不要从 `axios` 引入 `AxiosPromise`。
|
||||
|
||||
## 类型规则
|
||||
|
||||
- 标准类型定义 `VO`、`Form`、`Query`。
|
||||
- 必要时补 `InfoVO`、`TreeVO`、`ResetPwdForm`、`OptionVO` 等扩展类型。
|
||||
- `Form` 通常继承 `BaseEntity`。
|
||||
- 非树表 `Query` 通常继承 `PageQuery`。
|
||||
- 树表 `Query` 通常不继承 `PageQuery`。
|
||||
- ID 字段通常使用 `string | number`。
|
||||
- 批量删除参数使用 `string | number | Array<string | number>`。
|
||||
- Java 数值类型映射为 `number`,Boolean 映射为 `boolean`,日期和文本默认 `string`。
|
||||
- 日期范围查询保留 `params?: Record<string, unknown>` 或跟随相邻模块,不要无故删除。
|
||||
- 列表对象、表单对象、查询对象职责分开;字段不一致时不要强行复用一个接口。
|
||||
|
||||
## gen 模板规则
|
||||
|
||||
- `gen/api.ts.ftl` 和 `gen/types.ts.ftl` 是当前 React 项目内置模板,优先于外部后端模板。
|
||||
- 保持 Velocity 变量、宏和输出路径约定,不要破坏后端 generator 可替换变量。
|
||||
- 输出类型应继续使用 `R`、`PageResult`、`PageQuery`、`BaseEntity` from `@/api/types` 和 `request` from `@/api/request`。
|
||||
- 不输出 Vue 版 `AxiosPromise`、`@/utils/request` 或 `src/views` 约定。
|
||||
|
||||
## 自检
|
||||
|
||||
- API 路径是否与后端一致。
|
||||
- 类型是否覆盖接口真实结构。
|
||||
- 是否不必要地把类型写宽了。
|
||||
- 是否保留了当前模块的命名和导出风格。
|
||||
- 是否同步维护了当前项目内置 `gen/*.ftl` 模板中对应 API/types 输出。
|
||||
- 是否误用了 Vue 版 `AxiosPromise`、`@/utils/request` 或 `src/views` 约定。
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
name: frontend-crud-coding
|
||||
description: 前端总入口。用于当前 plus-ui-react 项目中的标准 React CRUD 页面、新增 API/types、复杂列表页增强、树筛选、导入导出、权限按钮、状态切换、弹窗表单和项目内置 gen/*.ftl React 代码生成模板维护任务,并根据任务类型选择合适的前端子 agent。
|
||||
---
|
||||
|
||||
你是当前 plus-ui-react 前端项目的总入口 agent。
|
||||
|
||||
先判断任务类型,再按下面规则处理:
|
||||
|
||||
1. 如果是新增标准 CRUD 页面、补 `src/api`、`types.ts`、`index.tsx`,优先使用 `frontend-crud-page.md`。
|
||||
2. 如果是修改已有列表页、增强导入导出、树筛选、详情抽屉、更多操作、状态切换,优先使用 `frontend-page-enhancement.md`。
|
||||
3. 如果只改接口层和类型定义,优先使用 `frontend-api-types.md`。
|
||||
4. 如果是维护代码生成模板,优先读取当前仓库 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`,再按 React 项目真实工具和页面规则修改模板。
|
||||
|
||||
通用要求:
|
||||
|
||||
- 先读当前目录下最近似页面和 API,再动代码。
|
||||
- 优先参考 `.codex/skills/frontend-crud-coding/SKILL.md` 和 `references/frontend.md`,保持 Claude agent 与 Codex skill 规则一致。
|
||||
- 冲突时优先相信当前项目真实页面,其次是公共组件、hooks、工具和请求封装,再其次是当前仓库 `gen/*.ftl` React 模板,最后才是 Vue 参考项目和关联后端工程 generator 模板。
|
||||
- 默认直接产出可落地代码,而不是只给抽象建议。
|
||||
- 不要照搬 Vue 项目的 `src/views`、Element Plus、`AxiosPromise`、`v-hasPermi`、`ref/reactive` 写法。
|
||||
|
||||
当前项目关键约定:
|
||||
|
||||
- 页面目录是 `src/pages`。
|
||||
- 请求封装是 `@/api/request`。
|
||||
- API 外层类型是 `R<T>`,分页类型是 `PageResult<T>`,都来自 `@/api/types`。
|
||||
- 标准页面优先使用 `PageContainer`、`ProTable`、`ModalForm`、ProForm 组件。
|
||||
- 权限通过 `useUserStore` 和 `hasPermi` 计算布尔值。
|
||||
- 多选通过 `useTableSelection`,导出通过 `useTableExport`。
|
||||
- 行操作优先使用 `RowActions` 和 `@ant-design/icons`。
|
||||
- 日期范围、字典 options、树表展开、loading、搜索重置和确认弹窗优先使用 `useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`useLoading`、`useSearchReset`、`confirmAction`/`confirmTitleSafe`。
|
||||
- `gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl` 内容必须生成 React TSX 页面。
|
||||
|
||||
验证要求:
|
||||
|
||||
- 改 TS/TSX/API/types 后优先运行 `pnpm lint` 或 `pnpm exec tsc --noEmit`。
|
||||
- 改公共组件、hooks、构建配置或较大范围页面后运行 `pnpm build`。
|
||||
- 如果验证失败或无法运行,交付时说明命令和原因。
|
||||
@@ -1,73 +0,0 @@
|
||||
---
|
||||
name: frontend-crud-page
|
||||
description: 前端标准 React CRUD 页面专家。用于当前 plus-ui-react 项目中的新建列表页、弹窗表单页、标准 API/types/index.tsx 骨架、项目内置 gen/*.ftl React 模板维护,以及后端 generator 字段到 React + ProTable 项目风格的落地任务。
|
||||
---
|
||||
|
||||
你负责当前 plus-ui-react 项目中的标准 CRUD 页面实现。
|
||||
|
||||
## 核心原则
|
||||
|
||||
1. 先看当前模块最近似页面。
|
||||
2. 再参考 `.codex/skills/frontend-crud-coding/references/frontend.md`。
|
||||
3. 维护或新增生成能力时,优先参考当前仓库 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。
|
||||
4. 必要时参考关联后端工程 generator 模板确认接口、字段、权限和导出能力。
|
||||
5. 默认同时维护:
|
||||
`src/api/<module>/<business>/index.ts`
|
||||
`src/api/<module>/<business>/types.ts`
|
||||
`src/pages/<module>/<business>/index.tsx`
|
||||
|
||||
## 优先参考
|
||||
|
||||
- 标准单表:`src/pages/demo/demo/index.tsx`、`src/api/demo/demo/*`。
|
||||
- 树表:`src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
||||
- 系统管理:`src/pages/system/user/index.tsx`、`system/role`、`system/post`、`system/config`。
|
||||
- workflow:`src/pages/workflow/*`、`src/api/workflow/*`。
|
||||
|
||||
## 页面规则
|
||||
|
||||
- 页面默认导出函数组件,命名如 `SystemClientPage`、`DemoDemoPage`、`WorkflowCategoryPage`。
|
||||
- 标准结构通常包含 `PageContainer`、`ProTable`、工具栏按钮、`ModalForm`。
|
||||
- 常见状态:
|
||||
`actionRef`、`form`、`modalOpen`、`modalTitle`、`ids`、`selectedOne`、权限布尔值。
|
||||
- 表格列使用 `ProColumns<XxxVO>[]`。
|
||||
- 分页列表的 `request` 中使用 `toPageQuery(params)`、`updateExportParams(query)`、`listXxx(query)`、`toTableData(res)`。
|
||||
- 多选使用 `useTableSelection<XxxVO>(row => row.id)`。
|
||||
- 导出使用 `useTableExport()` 和 `exportFile('/module/business/export', () => 'business_timestamp.xlsx')`。
|
||||
- 行操作使用 `RowActions`,行内删除确认放在 `confirm`。
|
||||
- 新增/编辑弹窗使用 `ModalForm<XxxForm>`,字段优先使用 ProForm 组件。
|
||||
- 日期范围使用 `useDateRangeQuery`,字典 options 使用 `dictOptions`。
|
||||
- 状态切换等 Promise 式确认使用 `confirmAction` 或 `confirmTitleSafe`。
|
||||
- 异步 loading 优先使用 `useLoading`,带额外筛选状态的重置优先使用 `useSearchReset`。
|
||||
|
||||
## API / types 规则
|
||||
|
||||
- 请求统一通过 `@/api/request`。
|
||||
- 同目录维护 `index.ts` 与 `types.ts`。
|
||||
- 标准 CRUD 通常包含:列表、详情、新增、修改、删除。
|
||||
- 列表分页接口通常返回 `request<R<PageResult<XxxVO>>>`。
|
||||
- 树表列表接口通常返回 `request<R<XxxVO[]>>`。
|
||||
- 不要从 `axios` 引入 `AxiosPromise`。
|
||||
|
||||
## 树表规则
|
||||
|
||||
- 判断树表后不要生成分页 `PageResult` 页面。
|
||||
- `Query` 通常不继承 `PageQuery`。
|
||||
- 使用 `handleTree`、`pagination={false}`、`useTreeTableExpand`、`ProFormTreeSelect`。
|
||||
- 树表展开/折叠优先使用 `useTreeTableExpand`,不要在页面或模板里重复手写收集 key 的状态逻辑。
|
||||
- 新增子节点时从当前行带入 `parentId`。
|
||||
|
||||
## gen 模板规则
|
||||
|
||||
- `gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl` 内容生成 React TSX。
|
||||
- 保持 Velocity 变量、宏和后端 generator 可识别结构,不为了格式美化破坏模板语法。
|
||||
- 模板应输出当前项目公共工具写法:`useTableSelection`、`useTableExport`、`useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`confirmAction`、`toPageQuery`、`toTableData`、`handleTree`。
|
||||
- 不把 Vue `src/views`、Element Plus、`AxiosPromise`、`v-hasPermi` 写入模板。
|
||||
|
||||
## 自检
|
||||
|
||||
- API 路径是否与后端一致。
|
||||
- `index.ts` 与 `types.ts` 是否同步补齐。
|
||||
- 页面是否使用 React 项目的 ProTable/ModalForm 骨架。
|
||||
- 权限标识是否与后端和相邻页面一致。
|
||||
- 是否同步使用当前项目公共 hooks/工具,避免生成重复代码。
|
||||
- 是否误用了 Vue/Element Plus/`src/views` 规则。
|
||||
@@ -1,58 +0,0 @@
|
||||
---
|
||||
name: frontend-page-enhancement
|
||||
description: 复杂前端页面增强专家。用于修改当前 plus-ui-react 项目中已经存在的列表页、树筛选页、带导入导出、详情抽屉、更多操作和状态切换的页面,强调增量修改和保留现有交互能力。
|
||||
---
|
||||
|
||||
你负责当前 plus-ui-react 项目中已有页面的增强,不是重写页面。
|
||||
|
||||
## 核心原则
|
||||
|
||||
1. 优先阅读当前页面完整实现和相关子组件。
|
||||
2. 增量修改,不重写整页。
|
||||
3. 保留已有树筛选、导入导出、列显隐、详情抽屉、更多操作、状态切换、路由跳转、权限控制和样式壳。
|
||||
4. 不要把复杂页面退化成 demo/generator 式基础列表页。
|
||||
5. 修改前先看 `.codex/skills/frontend-crud-coding/references/frontend.md` 中对应规则。
|
||||
|
||||
## 常见任务
|
||||
|
||||
- 调整工具栏按钮和行操作。
|
||||
- 增加筛选条件和日期范围。
|
||||
- 增加导入、导出能力。
|
||||
- 增加状态切换、快捷操作、确认弹窗。
|
||||
- 增加详情抽屉或增强现有抽屉。
|
||||
- 补复杂页面的小型子功能。
|
||||
- 接入新 API 并保持现有页面状态流。
|
||||
|
||||
## React 项目约定
|
||||
|
||||
- 表格页通常使用 `PageContainer` + `ProTable`。
|
||||
- 复杂系统页可包含 `TreePanel`、子组件弹窗、抽屉、授权路由跳转。
|
||||
- 权限通过 `useUserStore` + `hasPermi` 计算,不使用 Vue 指令。
|
||||
- 字典通过 `useDict` 加载,按现有页面映射为 Ant Design options。
|
||||
- 字典 options 优先使用 `dictOptions` from `@/utils/dict`。
|
||||
- 导出通过 `useTableExport`,不要另写下载封装。
|
||||
- 多选通过 `useTableSelection`,不要手写一套重复状态。
|
||||
- 日期范围优先使用 `useDateRangeQuery`,底层保持 `addDateRange` 参数格式。
|
||||
- 树表展开优先使用 `useTreeTableExpand`。
|
||||
- 异步 loading 优先使用 `useLoading`。
|
||||
- 额外筛选状态的重置优先使用 `useSearchReset`。
|
||||
- Promise 式确认框优先使用 `confirmAction` 或 `confirmTitleSafe`。
|
||||
- 状态切换失败时回滚或刷新,参考 `system/user`。
|
||||
|
||||
## 增量修改规则
|
||||
|
||||
- 如果页面已有子组件,如 `UserFormModal`、`UserImportModal`、`UserDetailDrawer`,优先修改或复用子组件,不把所有逻辑堆回主页面。
|
||||
- 如果页面已有权限布尔值,沿用同一命名风格补新权限。
|
||||
- 如果页面已有导出参数缓存,继续通过 `updateExportParams` 更新。
|
||||
- 如果页面已有树筛选状态,查询参数要合并该状态,不要覆盖掉。
|
||||
- 如果页面已有特殊禁用规则、超级管理员保护或业务状态判断,必须保留。
|
||||
- 如果增强的是标准 CRUD 能力或公共工具约定,要评估当前仓库 `gen/*.ftl` 是否也应同步更新。
|
||||
|
||||
## 自检
|
||||
|
||||
- 是否破坏了原页面结构和样式。
|
||||
- 是否误删了已有权限控制或交互能力。
|
||||
- 是否保留了树筛选、导入导出、抽屉、路由跳转等复杂能力。
|
||||
- 是否应该拆成子组件而不是继续堆主页面。
|
||||
- 是否使用了当前项目已有工具,避免重复手写日期范围、字典 options、树展开、loading、确认框。
|
||||
- 是否误用了 Vue/Element Plus/generator 的简化逻辑。
|
||||
@@ -1,162 +0,0 @@
|
||||
---
|
||||
name: frontend-crud-coding
|
||||
description: 在当前 plus-ui-react 前端项目中按真实 React + TypeScript + Umi Max + Ant Design ProComponents + oxlint/oxfmt 代码风格生成或修改页面、API、types、hooks 接入、样式和项目内置 gen/*.ftl 代码生成模板。用于新增或修改标准 CRUD 列表页、树表页、系统管理页、监控页、workflow 页面、demo 页面,补齐与 RuoYi-Vue-Plus boot4 后端接口对应的 src/api、types 和 src/pages 代码,或维护 gen/api.ts.ftl、gen/types.ts.ftl、gen/index.tsx.ftl、gen/index-tree.tsx.ftl;触发后应先读取适用 references,再阅读目标模块真实代码和项目内置 gen 模板。
|
||||
---
|
||||
|
||||
# 前端编码规范
|
||||
|
||||
先对齐当前 React 项目里的真实实现,再参考项目内置 `gen/` 代码生成模板。Vue 版本 skill 和关联后端工程的代码生成器模板只用于理解字段、权限、任务分型和迁移意图。不要直接套 Vue 3、Element Plus、AxiosPromise 或 `src/views` 规则;要落成当前仓库的 `src/pages`、`src/api`、ProTable、ModalForm、权限、导出和公共工具方式。
|
||||
|
||||
## 执行流程
|
||||
|
||||
1. 判断任务类型:新增标准 CRUD、树表、已有页面增强、复杂业务页、只补 API/types。
|
||||
2. 按“文档读取规则”读取必要 reference,不一次性展开所有资料。
|
||||
3. 阅读目标目录下最近似的真实代码:
|
||||
- 标准单表优先看 `src/pages/demo/demo/index.tsx`、`src/api/demo/demo/*`。
|
||||
- 树表优先看 `src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
||||
- 系统复杂页优先看 `src/pages/system/user/index.tsx`、`system/role`、`system/post`、`system/config`。
|
||||
- workflow 业务页优先看 `src/pages/workflow/*` 与 `src/api/workflow/*` 同类页面。
|
||||
4. 新增或维护代码生成能力时,优先阅读当前仓库 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。这些是 React 版内置 FreeMarker 生成模板,页面模板必须输出当前项目 React/TSX 风格。
|
||||
5. 需要从 Vue 版本迁移经验时,参考 Gitee 项目 `https://gitee.com/JavaLionLi/plus-ui` 的 `6.X-Vue` 分支,目录为 `.codex/skills/frontend-crud-coding` 和 `.claude/agents`,只吸收任务分型、增量修改和自检原则。
|
||||
6. 新增标准页面前,可以对照 Gitee 项目 `https://gitee.com/dromara/RuoYi-Vue-Plus` 的 `6.X` 分支,目录为 `ruoyi-modules/ruoyi-gen/src/main/resources/fm`,确认字段、权限和导出能力,但输出和 `gen/` 模板必须保持 React 项目风格。
|
||||
7. 新增代码时通常同步维护 `src/api/<module>/<business>/index.ts`、`types.ts`、`src/pages/<module>/<business>/index.tsx`;如果是生成模板优化,同步维护 `gen/` 对应 `.ftl`。
|
||||
8. 增强已有页面时只做增量修改,保留原页面的树筛选、导入导出、列显隐、权限、字典、弹窗、抽屉和路由跳转能力。
|
||||
9. 修改完成后按影响范围运行验证:优先 `pnpm exec tsc --noEmit` 或 `pnpm lint`;大范围页面、公共组件、构建配置变更再跑 `pnpm build`。
|
||||
|
||||
## 文档读取规则
|
||||
|
||||
- 前端 API、types、页面、hooks、样式、权限、导出和验证规则,先读 [references/frontend.md](references/frontend.md)。
|
||||
- 不确定任务边界、需要标准用例或提问方式时,再读 [references/examples.md](references/examples.md)。
|
||||
- reference 只约束实现方式和自检范围;发生冲突时,以当前模块真实代码和实际调用点为准。
|
||||
|
||||
## 优先级规则
|
||||
|
||||
发生冲突时按下面顺序决策:
|
||||
|
||||
1. 目标目录下最近似页面、API、types 的真实实现。
|
||||
2. 当前项目公共 hooks、组件、工具、样式和请求封装约定。
|
||||
3. 当前项目内置 `gen/*.ftl` React 代码生成模板。
|
||||
4. Gitee 项目 `plus-ui` 的 `6.X-Vue` 分支 `.codex` / `.claude` 中的任务分型和工作流。
|
||||
5. Gitee 项目 `RuoYi-Vue-Plus` 的 `6.X` 分支 generator 模板。
|
||||
6. 通用 React / Ant Design ProComponents 习惯。
|
||||
|
||||
也就是说:
|
||||
|
||||
- 同模块已有页面怎么写,优先怎么写。
|
||||
- 没有现成页面时,使用 demo 页面作为骨架,再按后端接口字段和权限补齐。
|
||||
- 复杂模块不能为了“标准 CRUD”退化成裸模板页。
|
||||
- Vue 版本只作为迁移参考,不复制 Vue 组件、hooks、指令、样式类和类型导入。
|
||||
|
||||
## 仓库通用规则
|
||||
|
||||
- 遵循 `.editorconfig` 和仓库现状:UTF-8、2 空格缩进、TypeScript、TSX。
|
||||
- 包管理使用 `pnpm`;格式脚本是 `pnpm run fmt`,lint 脚本是 `pnpm lint`。
|
||||
- 技术栈是 React 19 + TypeScript + Umi Max + Ant Design 6 + Ant Design ProComponents + ahooks + TanStack Query + Zustand。
|
||||
- 页面放在 `src/pages`,不是 Vue 项目的 `src/views`。
|
||||
- 请求统一通过 `src/api/request.ts`,API 返回类型使用 `Promise<R<T>>`,不要从 `axios` 或 Vue 项目引入 `AxiosPromise`。
|
||||
- 分页结果使用 `PageResult<T>` from `@/api/types`,接口外层使用 `R<T>` from `@/api/types`。
|
||||
- 标准列表页优先复用 `ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`、`toPageQuery`、`toTableData`。
|
||||
- 查询、字典、树表、loading、重置和确认弹窗优先复用 `useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`useLoading`、`useSearchReset`、`confirmAction`/`confirmTitleSafe`。
|
||||
- 权限用 `const userInfo = useUserStore(state => state.userInfo)` 和 `hasPermi(userInfo, ['module:business:action'])` 计算布尔值。
|
||||
- 新页面不要无故引入另一套状态管理、请求封装、表格封装、样式体系或权限写法。
|
||||
|
||||
## 目录映射规则
|
||||
|
||||
通常按下面关系组织代码:
|
||||
|
||||
- 后端 `/system/user/*` 对应 `src/api/system/user/*` 与 `src/pages/system/user/*`
|
||||
- 后端 `/monitor/xxx/*` 对应 `src/api/monitor/xxx/*` 与 `src/pages/monitor/xxx/*`
|
||||
- 后端 `/workflow/xxx/*` 对应 `src/api/workflow/xxx/*` 与 `src/pages/workflow/xxx/*`
|
||||
- 后端 `/demo/xxx/*` 对应 `src/api/demo/xxx/*` 与 `src/pages/demo/xxx/*`
|
||||
|
||||
标准新增通常至少包含:
|
||||
|
||||
- `src/api/<module>/<business>/index.ts`
|
||||
- `src/api/<module>/<business>/types.ts`
|
||||
- `src/pages/<module>/<business>/index.tsx`
|
||||
|
||||
按业务复杂度,可能继续补:
|
||||
|
||||
- 导入弹窗
|
||||
- 详情抽屉或详情页
|
||||
- 树筛选面板
|
||||
- 列显隐配置
|
||||
- 分配/授权子页面
|
||||
- 自定义 Less 样式
|
||||
|
||||
## 任务分型
|
||||
|
||||
### 1. 标准单表 CRUD
|
||||
|
||||
以 `src/pages/demo/demo/index.tsx` 和 `src/api/demo/demo/*` 为主要起点,补齐列表、搜索、分页、新增、编辑、删除、导出、权限、类型和验证。
|
||||
|
||||
### 2. 树表 CRUD
|
||||
|
||||
以 `src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx` 为主要起点。列表接口通常返回数组,不使用分页 `PageResult`;页面使用 `handleTree`、`useTreeTableExpand`、`ProFormTreeSelect`。
|
||||
|
||||
### 3. 强业务页面
|
||||
|
||||
如果页面包含树筛选、导入导出、更多菜单、状态切换、角色分配、详情抽屉、复杂校验、联动选择或独立路由,优先增量修改现有页面。不要重写成简单 CRUD。
|
||||
|
||||
### 4. 工作流页面
|
||||
|
||||
workflow 目录优先参考 `src/pages/workflow/*`。流程定义、流程实例、任务列表、请假申请等页面通常有业务按钮、弹窗和路由跳转,不要硬套 system 模块。
|
||||
|
||||
### 5. 只补 API 和 types
|
||||
|
||||
只维护 `src/api/<module>/<business>/index.ts` 与 `types.ts`,但仍要与后端路由、返回结构、当前模块导入方式和类型入口一致。
|
||||
|
||||
### 6. 维护 React 生成模板
|
||||
|
||||
模板只放在当前仓库 `gen/` 下,除非用户明确要求写入 boot4 后端工程。维护时保持 FreeMarker 变量和文件名不变:
|
||||
|
||||
- `gen/api.ts.ftl`
|
||||
- `gen/types.ts.ftl`
|
||||
- `gen/index.tsx.ftl`
|
||||
- `gen/index-tree.tsx.ftl`
|
||||
|
||||
模板内容必须生成当前 React 项目代码,并优先使用已有公共工具:`useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`useTableSelection`、`useTableExport`、`confirmAction`、`toPageQuery`、`toTableData`、`handleTree`、`formatDateTimeFields`、`toDayjsFields`。不要把 Vue 模板、Element Plus 组件或 `src/views` 路径写入这些模板。
|
||||
|
||||
## 输出要求
|
||||
|
||||
使用本 skill 时,默认期望产出应满足:
|
||||
|
||||
- 类型完整,不把页面逻辑大量写成 `any`。
|
||||
- API 路径、函数名、权限标识与后端接口保持一致。
|
||||
- 标准页查询、重置、分页、弹窗、提交、删除、导出流程闭环完整。
|
||||
- 复杂页面保留原有交互能力和业务约束。
|
||||
- 代码体现当前项目 hooks、页面壳和下载方式,而不是 Vue 版本或 generator 裸输出。
|
||||
- 生成模板变更要同步反映当前项目公共 hooks/工具,避免生成的新页面重复手写日期范围、字典 options、树展开、loading、搜索重置和确认框逻辑。
|
||||
- 交付前说明运行过的验证命令;如果无法验证,说明原因。
|
||||
|
||||
## 快速检查清单
|
||||
|
||||
- API 是否从 `@/api/request` 引入 `request`。
|
||||
- `R`、`PageResult`、`PageQuery`、`BaseEntity` 是否来自 `@/api/types`。
|
||||
- API `params` 和 `data` 是否与后端方法一致。
|
||||
- 分页表格 request 是否通过 `toPageQuery(params)` 和 `toTableData(res)`。
|
||||
- 导出是否通过 `useTableExport` 和 `exportFile('/module/business/export', () => 'name_timestamp.xlsx')`。
|
||||
- 多选是否通过 `useTableSelection<T>(row => row.id)`。
|
||||
- 行操作是否优先使用 `RowActions` 和 Ant Design 图标。
|
||||
- 权限是否通过 `useUserStore` + `hasPermi` 计算,不要写 Vue 指令。
|
||||
- 日期范围是否通过 `useDateRangeQuery` 或 `addDateRange` 相关工具处理。
|
||||
- 字典 options 是否通过 `dictOptions`。
|
||||
- 树表是否使用 `handleTree`、`pagination={false}`、`useTreeTableExpand`、`ProFormTreeSelect`。
|
||||
- loading 是否优先使用 `useLoading`,搜索重置是否优先使用 `useSearchReset`。
|
||||
- 需要 Promise 式确认时是否使用 `confirmAction` 或 `confirmTitleSafe`。
|
||||
- 代码生成模板是否仍输出 React TSX 项目风格。
|
||||
|
||||
## 推荐提问方式
|
||||
|
||||
推荐把请求描述到下面粒度:
|
||||
|
||||
- 目标模块和业务名
|
||||
- 后端接口前缀
|
||||
- 是新增页面、修改页面,还是只补 API/types
|
||||
- 是否需要导入、导出、树筛选、树表、状态切换、字典、权限按钮
|
||||
- 希望参考哪个现有页面
|
||||
|
||||
例如:
|
||||
|
||||
- 使用 `$frontend-crud-coding` 为 `/system/client` 补一套 React 标准 CRUD 页面,参考 `demo/demo`、现有 `system/client` 和 boot4 generator 模板。
|
||||
- 使用 `$frontend-crud-coding` 修改 `workflow/category` 列表页,增加导出按钮和状态筛选,保持当前 workflow 树表风格。
|
||||
@@ -1,7 +0,0 @@
|
||||
interface:
|
||||
display_name: "前端编码"
|
||||
short_description: "按 plus-ui-react 真实代码和 gen 模板编写 React CRUD"
|
||||
default_prompt: "使用 $frontend-crud-coding 先读取适用 reference,再按 plus-ui-react 真实页面、项目内置 gen 模板、API/types、ProTable、ModalForm、权限、导出和公共工具约定实现前端修改。"
|
||||
|
||||
policy:
|
||||
allow_implicit_invocation: true
|
||||
@@ -1,143 +0,0 @@
|
||||
# 使用案例
|
||||
|
||||
## 案例 1:新增标准 CRUD 页面
|
||||
|
||||
### 用户提问示例
|
||||
|
||||
```text
|
||||
使用 $frontend-crud-coding 为 system/client 补一套 React 前端 CRUD 页面。
|
||||
后端接口已经有 /system/client/list、/system/client/{id}、POST /system/client、PUT /system/client、DELETE /system/client/{ids}。
|
||||
请参考 src/pages/demo/demo/index.tsx 和现有 system/client 风格实现。
|
||||
```
|
||||
|
||||
### 期望执行方式
|
||||
|
||||
- 先看 `src/api/system/client/*` 和 `src/pages/system/client/index.tsx` 是否已存在。
|
||||
- 再看 `src/pages/demo/demo/index.tsx` 的标准 React CRUD 骨架。
|
||||
- 新增标准生成能力时优先对照当前仓库 `gen/index.tsx.ftl`、`gen/api.ts.ftl`、`gen/types.ts.ftl`;boot4 generator 只用于核对字段、权限和接口。
|
||||
- 生成或修改 `api/index.ts`、`types.ts`、`pages/.../index.tsx`。
|
||||
- 使用 `request<R<PageResult<T>>>`、`ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`。
|
||||
- 日期范围、字典 options、确认框、loading 等优先使用 `useDateRangeQuery`、`dictOptions`、`confirmAction`、`useLoading` 等项目工具。
|
||||
|
||||
## 案例 2:新增树表页面
|
||||
|
||||
### 用户提问示例
|
||||
|
||||
```text
|
||||
使用 $frontend-crud-coding 为 demo/tree2 新增树表 CRUD,接口返回数组,字段包含 id、parentId、name、orderNum。
|
||||
参考 src/pages/demo/tree/index.tsx 和 workflow/category。
|
||||
```
|
||||
|
||||
### 期望执行方式
|
||||
|
||||
- 判断这是树表,不生成分页 `PageResult` 页面。
|
||||
- API 列表返回 `R<Tree2VO[]>`。
|
||||
- `Query` 不继承 `PageQuery`。
|
||||
- 页面使用 `handleTree`、`pagination={false}`、`useTreeTableExpand`、`ProFormTreeSelect`。
|
||||
- 新增子节点时从当前行带入 `parentId`。
|
||||
|
||||
## 案例 2.1:优化 React 代码生成模板
|
||||
|
||||
### 用户提问示例
|
||||
|
||||
```text
|
||||
使用 $frontend-crud-coding 优化当前项目 gen 目录下的 React 代码生成模板,让生成页面继续使用新加的工具。
|
||||
```
|
||||
|
||||
### 期望执行方式
|
||||
|
||||
- 读取 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。
|
||||
- 保持 FreeMarker 变量、宏和文件名不变。
|
||||
- 普通表模板继续使用 `useTableSelection`、`useTableExport`、`useDateRangeQuery`、`dictOptions`、`confirmAction`。
|
||||
- 树表模板继续使用 `handleTree`、`filterTree`、`useTreeTableExpand`、`dictOptions`。
|
||||
- 输出仍是 React TSX 项目代码,不写 Vue `src/views`、Element Plus 或 `AxiosPromise`。
|
||||
|
||||
## 案例 3:修改已有复杂列表页
|
||||
|
||||
### 用户提问示例
|
||||
|
||||
```text
|
||||
使用 $frontend-crud-coding 修改 system/user 页面:
|
||||
1. 新增一个创建时间快捷筛选
|
||||
2. 导出按钮保留在工具栏中
|
||||
3. 保持现有树筛选、导入、详情抽屉和角色分配不变
|
||||
```
|
||||
|
||||
### 期望执行方式
|
||||
|
||||
- 判断这是“已有复杂页面增强”,不是重新生成 CRUD。
|
||||
- 优先阅读 `src/pages/system/user/index.tsx` 和相关子组件。
|
||||
- 保留 `TreePanel`、导入弹窗、`UserDetailDrawer`、角色分配路由、权限控制。
|
||||
- 只增量修改搜索和查询参数处理。
|
||||
|
||||
## 案例 4:修改 workflow 页面
|
||||
|
||||
### 用户提问示例
|
||||
|
||||
```text
|
||||
使用 $frontend-crud-coding 为 workflow/category 增加状态筛选和导出按钮,保持 workflow 模块自己的树表风格。
|
||||
```
|
||||
|
||||
### 期望执行方式
|
||||
|
||||
- 优先看 `src/pages/workflow/category/index.tsx` 和 `src/api/workflow/category/*`。
|
||||
- 判断是否需要后端新增导出接口;前端导出路径保持 `/workflow/category/export`。
|
||||
- 不迁移 system/user 的用户专属逻辑。
|
||||
- 保留树表、`useTreeTableExpand`、`handleTree` 和分类弹窗逻辑。
|
||||
|
||||
## 案例 5:只补 API 和 types
|
||||
|
||||
### 用户提问示例
|
||||
|
||||
```text
|
||||
使用 $frontend-crud-coding 为 monitor/cache 补全前端 API 和 types,页面先不改。
|
||||
```
|
||||
|
||||
### 期望执行方式
|
||||
|
||||
- 只维护 `src/api/monitor/cache/index.ts` 和 `src/api/monitor/cache/types.ts`。
|
||||
- 仍然检查同目录 monitor API 的命名、返回结构和导出风格。
|
||||
- 返回类型使用 `R<T>` 和 `PageResult<T>` from `@/api/types`。
|
||||
- 不创建页面,不改路由。
|
||||
|
||||
## 案例 6:接入后端新增状态切换接口
|
||||
|
||||
### 用户提问示例
|
||||
|
||||
```text
|
||||
使用 $frontend-crud-coding 给 system/client 页面接入 PUT /system/client/changeStatus,状态字段 status,参考 system/user。
|
||||
```
|
||||
|
||||
### 期望执行方式
|
||||
|
||||
- API 增加 `changeClientStatus(id, status)`。
|
||||
- types 确认 `status` 类型是 string、number 还是 boolean。
|
||||
- 表格列用 Ant Design `Switch`,checked 值跟后端字段类型一致。
|
||||
- 切换失败时回滚原状态或刷新列表。
|
||||
- 权限使用 `system:client:edit` 或后端实际权限。
|
||||
|
||||
## 推荐的高质量任务描述
|
||||
|
||||
```text
|
||||
使用 $frontend-crud-coding 在当前 React 前端项目中增强 `/system/notice` 列表页:
|
||||
1. 保留现有页面
|
||||
2. 新增状态筛选和导出
|
||||
3. API 路径沿用后端接口
|
||||
4. 参考 system/config 的工具栏与导出交互
|
||||
5. 参考当前项目 gen 模板和 boot4 generator 字段补齐缺失 types
|
||||
```
|
||||
|
||||
## 不推荐的任务描述
|
||||
|
||||
```text
|
||||
帮我写个后台页面
|
||||
```
|
||||
|
||||
更好的写法至少补充:
|
||||
|
||||
- 模块名
|
||||
- 业务名
|
||||
- 后端接口前缀
|
||||
- 是新增还是修改
|
||||
- 是否需要分页、导出、树表、字典、权限
|
||||
- 想参考哪个现有页面
|
||||
@@ -1,154 +0,0 @@
|
||||
# 前端约定
|
||||
|
||||
## 优先参考的代码来源
|
||||
|
||||
- 当前目标目录下最近似页面、API、types。
|
||||
- 当前仓库内置 React 生成模板:`gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。
|
||||
- 标准单表:`src/pages/demo/demo/index.tsx`、`src/api/demo/demo/index.ts`、`src/api/demo/demo/types.ts`。
|
||||
- 树表:`src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
||||
- 复杂系统页:`src/pages/system/user/index.tsx`、`src/pages/system/role/index.tsx`、`src/pages/system/post/index.tsx`、`src/pages/system/config/index.tsx`。
|
||||
- workflow 页:`src/pages/workflow/*`、`src/api/workflow/*`。
|
||||
- 监控页:`src/pages/monitor/*`、`src/api/monitor/*`。
|
||||
- 公共 hooks:`src/hooks/useTableSelection.ts`、`src/hooks/useTableExport.ts`、`src/hooks/useDict.ts`、`src/hooks/useDateRangeQuery.ts`、`src/hooks/useTreeTableExpand.ts`、`src/hooks/useLoading.ts`、`src/hooks/useSearchReset.ts`。
|
||||
- 公共组件:`src/components/common/RowActions.tsx`、`TreePanel.tsx`、`RightToolbar.tsx`、`DictTag.tsx`、上传/预览组件。
|
||||
- 工具函数:`src/utils/ruoyi.ts`、`src/utils/permission.ts`、`src/utils/download.ts`、`src/utils/dict.ts`、`src/utils/modal.ts`。
|
||||
|
||||
## 基础栈与格式
|
||||
|
||||
- 技术栈是 React + TypeScript + Umi Max + Ant Design + ProComponents + ahooks + Zustand + TanStack Query。
|
||||
- 包管理按仓库现状使用 pnpm。
|
||||
- `.editorconfig` 要求 UTF-8、2 空格缩进。
|
||||
- 当前仓库没有 Prettier;格式化使用 `pnpm run fmt`,lint 使用 `pnpm lint`。
|
||||
- 不要在一个页面里混入与仓库不一致的格式和写法。
|
||||
|
||||
## API 文件规则
|
||||
|
||||
- 标准 API 文件放在 `src/api/<module>/<business>/index.ts`,同目录维护 `types.ts`。
|
||||
- import 顺序优先跟随附近文件,标准形式:
|
||||
`import type { PageResult, R } from '@/api/types';`
|
||||
`import request from '@/api/request';`
|
||||
`import type { XxxForm, XxxQuery, XxxVO } from './types';`
|
||||
- 不要从 `axios` 引入 `AxiosPromise`;当前 `request<T>()` 返回 `Promise<T>`,接口函数通常返回 `Promise<R<T>>`。
|
||||
- 列表分页接口通常返回 `request<R<PageResult<XxxVO>>>({ url, method: 'get', params: query })`。
|
||||
- 树表列表接口通常返回 `request<R<XxxVO[]>>({ url, method: 'get', params: query })`。
|
||||
- 详情接口返回 `R<XxxVO>`;复杂详情返回单独的 `InfoVO`。
|
||||
- 标准函数命名:
|
||||
`listXxx` -> `GET /<module>/<business>/list`
|
||||
`getXxx` -> `GET /<module>/<business>/{id}`
|
||||
`addXxx` -> `POST /<module>/<business>`
|
||||
`updateXxx` -> `PUT /<module>/<business>`
|
||||
`delXxx` -> `DELETE /<module>/<business>/{id or ids}`
|
||||
`changeXxxStatus` -> `PUT /<module>/<business>/changeStatus`
|
||||
- query string 用 `params`,请求体用 `data`。
|
||||
- 加密、防重复提交等 headers 直接写在请求配置里,例如用户重置密码中的 `isEncrypt`、`repeatSubmit`。
|
||||
- 当前仓库多数 API 使用 `export function`;新增标准 CRUD 优先跟随相邻模块。
|
||||
- 只有相邻模块已有聚合对象时才新增默认导出。
|
||||
|
||||
## 类型文件规则
|
||||
|
||||
- 标准类型定义 `VO`、`Form`、`Query`,必要时补 `InfoVO`、`TreeVO`、`ResetPwdForm` 等扩展类型。
|
||||
- `Form` 通常继承 `BaseEntity`。
|
||||
- 非树表 `Query` 通常继承 `PageQuery`。
|
||||
- 树表 `Query` 通常不继承 `PageQuery`。
|
||||
- ID 字段通常使用 `string | number`,批量删除参数使用 `string | number | Array<string | number>`。
|
||||
- Java 数值类型映射为 `number`,Boolean 映射为 `boolean`,日期/文本默认 `string`。
|
||||
- 日期范围查询保留 `params?: Record<string, unknown>` 或跟随相邻页面现有类型,不要因为它看起来宽松就删掉。
|
||||
- 列表对象、表单对象、查询对象职责分开;字段不一致时不要强行复用一个接口。
|
||||
- 能明确写出类型时不要用 `any`;组件库、字典或历史接口确实无法收窄时再保留。
|
||||
|
||||
## React 页面结构规则
|
||||
|
||||
- 页面默认导出函数组件,命名如 `SystemUserPage`、`DemoDemoPage`、`WorkflowCategoryPage`。
|
||||
- 标准页使用 `PageContainer` 包裹 `ProTable` 和 `ModalForm`。
|
||||
- 标准列表页常见状态:
|
||||
`actionRef`、`form`、`modalOpen`、`modalTitle`、`ids`、`selectedOne`、权限布尔值。
|
||||
- 弹窗状态优先使用 `useBoolean(false)`,表单用 `Form.useForm<XxxForm>()`。
|
||||
- ProTable 使用:
|
||||
`rowKey`
|
||||
`columns`
|
||||
`search={{ labelWidth: 90 }}`
|
||||
`pagination={{ defaultPageSize: 10, showSizeChanger: true }}`
|
||||
`request={async params => { ... }}`
|
||||
`toolBarRender={() => [...]}`
|
||||
- 分页查询使用 `toPageQuery(params)`,然后 `updateExportParams(query)`,最后 `return toTableData(res)`。
|
||||
- 表格列类型使用 `ProColumns<XxxVO>[]`。
|
||||
- 新增/编辑弹窗使用 `ModalForm<XxxForm>`,字段优先使用 `ProFormText`、`ProFormDigit`、`ProFormSelect`、`ProFormTreeSelect`、`ProFormDateTimeRangePicker` 等 ProForm 组件。
|
||||
- ModalForm 成功提交后返回 `true`,并刷新 `actionRef.current?.reload()`。
|
||||
|
||||
## 页面行为规则
|
||||
|
||||
- `openAdd` 负责 `form.resetFields()`、设置默认值、设置标题、打开弹窗。
|
||||
- `openEdit` 先按行或 `selectedOne` 找目标,再查详情,`form.resetFields()`,`form.setFieldsValue(res.data)`,最后打开弹窗。
|
||||
- `submitForm` 根据主键判断新增或修改,成功后 `message.success('操作成功')`、重置表单、刷新列表。
|
||||
- `remove` 或 `handleDelete` 支持行删除和批量删除,成功后 `message.success('删除成功')`、`clearSelection()`、`reloadAndRest` 或 `reload`。
|
||||
- 批量按钮通常用 `Popconfirm`,行操作确认优先放在 `RowActions` 的 `confirm`。
|
||||
- 状态切换失败时要回滚或刷新,参考 `src/pages/system/user/index.tsx`。
|
||||
- 日期范围查询优先使用 `useDateRangeQuery`,底层通过 `addDateRange` 写入 `params.beginXxx/endXxx`。
|
||||
- 字典 options 优先使用 `dictOptions(dicts.xxx)`。
|
||||
- 导入上传参考 `system/user/components/UserImportModal.tsx` 或流程定义导入弹窗,保留 `globalHeaders()` 和 `appEnv.baseApi` 相关方式。
|
||||
|
||||
## 字典、权限与公共工具
|
||||
|
||||
- 字典使用 `const dicts = useDict('sys_normal_disable', 'sys_user_gender')`。
|
||||
- 字典 options 使用 `dictOptions` from `@/utils/dict` 映射为 `{ label, value }`。
|
||||
- 权限使用:
|
||||
`const userInfo = useUserStore(state => state.userInfo);`
|
||||
`const canAdd = hasPermi(userInfo, ['system:user:add']);`
|
||||
- 不要使用 Vue 权限指令 `v-hasPermi`。
|
||||
- 常用工具:
|
||||
`hasPermi` from `@/utils/permission`
|
||||
`handleTree`、`parseStrEmpty`、`toPageQuery`、`toTableData`、`addDateRange`、`formatDateTimeRange` from `@/utils/ruoyi`
|
||||
`dictOptions` from `@/utils/dict`
|
||||
`confirmAction`、`confirmTitleSafe` from `@/utils/modal`
|
||||
`download` via `useTableExport`
|
||||
|
||||
## 组件与样式规则
|
||||
|
||||
- 行操作优先复用 `RowActions`,并使用 `@ant-design/icons` 图标。
|
||||
- 树筛选优先复用 `TreePanel`,参考 `system/user`。
|
||||
- 导出优先复用 `useTableExport`。
|
||||
- 多选优先复用 `useTableSelection`。
|
||||
- 异步 loading 优先复用 `useLoading`,不要重复手写 `setLoading(true)` + `finally setLoading(false)`。
|
||||
- ProTable 重置后还要清空额外筛选状态时,优先复用 `useSearchReset`。
|
||||
- Promise 式确认框优先复用 `confirmAction` 或 `confirmTitleSafe`。
|
||||
- 标准页面尽量使用 `PageContainer`、`ProTable`、ProComponents 页面壳,不堆大量内联样式。
|
||||
- 需要自定义布局时先查 `src/assets/styles` 是否已有 `.tree-table-page`、`.table-panel`、`.page-surface` 等类。
|
||||
- 不要为了单页需求修改全局组件样式。
|
||||
|
||||
## 树表规则
|
||||
|
||||
- 树表列表接口通常返回数组,页面通过 `handleTree<T>(res.data || [], 'id', 'parentId')` 组树。
|
||||
- `ProTable` 使用 `pagination={false}`。
|
||||
- 使用 `useTreeTableExpand` 控制 `expandedRowKeys`、`onExpandedRowsChange`、`syncExpandedRows`、`toggleExpandAll`。
|
||||
- 展开/折叠按钮参考 `demo/tree` 和 `workflow/category`,用 `SortAscendingOutlined`。
|
||||
- 表单中上级节点使用 `ProFormTreeSelect`。
|
||||
- 新增子节点时从当前行回填 `parentId`。
|
||||
- 删除确认文案优先使用业务名称,而不是批量 ID 文案。
|
||||
|
||||
## 与 gen 模板、Vue 参考项目和后端生成器的关系
|
||||
|
||||
- 当前仓库 `gen/*.ftl` 是 React 版内置代码生成模板,是维护生成能力时的第一参考。
|
||||
- `gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl` 内容必须生成 React TSX 页面。
|
||||
- 修改公共 hooks/工具后,如果它们能简化标准生成页,要同步评估 `gen/*.ftl` 是否需要更新。
|
||||
- Vue skill 和 `.claude/agents` 提供的是任务分型、优先级、增量修改、自检方式,不是 React 实现模板。
|
||||
- boot4 后端 generator 模板可用于确认字段、权限、导出、状态切换、排序、日期范围等,但不是最终答案。
|
||||
- 当前 React 项目的核心骨架是 `ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`。
|
||||
- 修改已有页面时,不要把现有强业务逻辑替换回 generator 的简化逻辑。
|
||||
|
||||
## 验证规则
|
||||
|
||||
- 只改文档、skill 或 `gen/*.ftl` 模板:至少运行 skill 基础校验或 `git diff --check`;如果模板改动依赖项目工具,优先再跑 `pnpm lint`。
|
||||
- 改前端 TS/TSX/API/types:优先运行 `pnpm exec tsc --noEmit` 或 `pnpm lint`。
|
||||
- 改页面、import、权限或较多文件:运行 `pnpm lint`。
|
||||
- 改公共 hooks、组件、构建相关或大范围页面:再运行 `pnpm build`。
|
||||
- 如果验证因为环境、依赖或权限失败,交付时说明失败命令和原因。
|
||||
|
||||
## 避免事项
|
||||
|
||||
- 不要从 `axios` 引入 `AxiosPromise`。
|
||||
- 不要绕开 `@/api/request` 或 `useTableExport` 自造请求/下载封装。
|
||||
- 不要跳过 `types.ts`,把类型全写在页面里。
|
||||
- 不要把 `src/pages` 写成 Vue 项目的 `src/views`。
|
||||
- 不要使用 Vue 的 `ref`、`reactive`、`toRefs`、`v-hasPermi`、Element Plus 组件或 SCSS 页面壳。
|
||||
- 不要删除日期范围 `params`、权限判断、导出、导入、树筛选、列显隐等现有能力。
|
||||
- 不要为了“更整洁”重写复杂页面的大块业务逻辑。
|
||||
+15
-3
@@ -1,9 +1,21 @@
|
||||
# 告诉EditorConfig插件,这是根文件,不用继续往上查找
|
||||
root = true
|
||||
|
||||
# 匹配全部文件
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
# 缩进风格,可选space、tab
|
||||
indent_style = space
|
||||
# 缩进的空格数
|
||||
indent_size = 2
|
||||
# 设置字符集
|
||||
charset = utf-8
|
||||
# 结尾换行符,可选lf、cr、crlf
|
||||
end_of_line = lf
|
||||
# 在文件结尾插入新行
|
||||
trim_trailing_whitespace = true
|
||||
# 删除一行中的前后空格
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
+32
-15
@@ -1,15 +1,32 @@
|
||||
VITE_APP_TITLE=RuoYi-React-Plus后台管理系统
|
||||
VITE_APP_LOGO_TITLE=RuoYi-React-Plus
|
||||
VITE_APP_ENV=development
|
||||
VITE_APP_BASE_API=/dev-api
|
||||
VITE_APP_CONTEXT_PATH=/
|
||||
VITE_APP_PORT=8000
|
||||
VITE_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
|
||||
VITE_APP_MESSAGE_ENABLED=true
|
||||
VITE_APP_MESSAGE_TRANSPORT=sse
|
||||
VITE_APP_MESSAGE_PATH=/resource/message
|
||||
VITE_APP_ENCRYPT=true
|
||||
VITE_APP_RSA_PUBLIC_KEY=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvEDuRIOM3oZPWj9Ukoc5pQklR4PFH6/clnjeFqjDLIgDyQvjxhgqAZQA+E9eD6qu6FsXPmK8djcL+nh3cFHz4pX473jDvO3Sve+8yL3VRQ0n2pRgQ2a01MJsy+WwTZCBYWf0VnLRIvANUoWQgy9vz94q7Va44dg7A1/3ICf+xAwIDAQAB
|
||||
VITE_APP_RSA_PRIVATE_KEY=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAObq7yrxfvyieZtTjAYyrdvi59tYTXxjO5ajmPCRSXBY9M9wQ1tli297JN6mnY53UJMNyOFNSZVi8WSFoIXjpR87FmvChJlzeN/dZdd3SEs48Ee66XKeSePYqxa8oO5GKDsnajgpsOHKXSeeVSIysiIPS2/WsEqk0In9P4w3RsRFAgMBAAECgYBiMEWwce24SPICnRzuScBpvmsudrbEDIH7BOd0a6LZlcnLJwZNJ7mJlshPsHNQb+WgEf135+BBGEhioPtn0yuTdEuKP4kB9UdYUKiayWCoWhJpesv7sAD4RDClV7dhuV+gcd1AXD+YzyRIPbGm0VC2U+4q8/+UPRpVjqskbLVTgQJBAPRpou7g3S8n4XB527kq0D8I3+ZYwMxZhszwhrCDpJU319+ucmpLVwYIzDmZVeID2QQdUaDfIEViFHu95xDrGiUCQQDx3YOKn3yaEctk/ERVn7hDAyAXUbd8/pv2b24/M/l1ZevlsFem8U4Jk5Mu64t3z3YGJoymEjQmbucwT01iKhehAkEAxlnccsRmfFh/KkqauKE4M4++NTAd9zlInpUsmZ+cN8UEGnF2RTEzRKBrLOt1uWCqBB7PGiE6DVTVjr7FAQPrSQJAT5yeY87DcONSk9cFlzmPqV8p/QME5rvYEnHzVBKDlkUKNPyqnWToTvaoh9U4fyNmsfeWbEOprszqhFhWHG3GgQJAK8+ynmyFhaw63+Hx2KU5zR4hVuQso2IzrEurGxCxybV6mR7VBerb4502+EPx3PmOgxQL+niUFhcMWxcvBFP9+A==
|
||||
VITE_APP_MONITOR_ADMIN=http://localhost:9090/admin/applications
|
||||
VITE_APP_SNAILJOB_ADMIN=http://localhost:8800/snail-job
|
||||
# 页面标题
|
||||
VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统
|
||||
|
||||
# 开发环境配置
|
||||
VITE_APP_ENV = 'development'
|
||||
|
||||
# 开发环境
|
||||
VITE_APP_BASE_API = '/dev-api'
|
||||
|
||||
# 应用访问路径 例如使用前缀 /admin/
|
||||
VITE_APP_CONTEXT_PATH = '/'
|
||||
|
||||
# 监控地址
|
||||
VITE_APP_MONITOR_ADMIN = 'http://localhost:9090/admin/applications'
|
||||
|
||||
# SnailJob 控制台地址
|
||||
VITE_APP_SNAILJOB_ADMIN = 'http://localhost:8800/snail-job'
|
||||
|
||||
VITE_APP_PORT = 80
|
||||
|
||||
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
||||
VITE_APP_ENCRYPT = true
|
||||
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||
VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
||||
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
||||
VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
|
||||
|
||||
# 客户端id
|
||||
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||
|
||||
# websocket 开关 默认使用sse推送
|
||||
VITE_APP_WEBSOCKET = false
|
||||
|
||||
+35
-15
@@ -1,15 +1,35 @@
|
||||
VITE_APP_TITLE=RuoYi-React-Plus后台管理系统
|
||||
VITE_APP_LOGO_TITLE=RuoYi-React-Plus
|
||||
VITE_APP_ENV=production
|
||||
VITE_APP_BASE_API=/prod-api
|
||||
VITE_APP_CONTEXT_PATH=/
|
||||
VITE_APP_PORT=8000
|
||||
VITE_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
|
||||
VITE_APP_MESSAGE_ENABLED=true
|
||||
VITE_APP_MESSAGE_TRANSPORT=sse
|
||||
VITE_APP_MESSAGE_PATH=/resource/message
|
||||
VITE_APP_ENCRYPT=true
|
||||
VITE_APP_RSA_PUBLIC_KEY=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvEDuRIOM3oZPWj9Ukoc5pQklR4PFH6/clnjeFqjDLIgDyQvjxhgqAZQA+E9eD6qu6FsXPmK8djcL+nh3cFHz4pX473jDvO3Sve+8yL3VRQ0n2pRgQ2a01MJsy+WwTZCBYWf0VnLRIvANUoWQgy9vz94q7Va44dg7A1/3ICf+xAwIDAQAB
|
||||
VITE_APP_RSA_PRIVATE_KEY=MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAObq7yrxfvyieZtTjAYyrdvi59tYTXxjO5ajmPCRSXBY9M9wQ1tli297JN6mnY53UJMNyOFNSZVi8WSFoIXjpR87FmvChJlzeN/dZdd3SEs48Ee66XKeSePYqxa8oO5GKDsnajgpsOHKXSeeVSIysiIPS2/WsEqk0In9P4w3RsRFAgMBAAECgYBiMEWwce24SPICnRzuScBpvmsudrbEDIH7BOd0a6LZlcnLJwZNJ7mJlshPsHNQb+WgEf135+BBGEhioPtn0yuTdEuKP4kB9UdYUKiayWCoWhJpesv7sAD4RDClV7dhuV+gcd1AXD+YzyRIPbGm0VC2U+4q8/+UPRpVjqskbLVTgQJBAPRpou7g3S8n4XB527kq0D8I3+ZYwMxZhszwhrCDpJU319+ucmpLVwYIzDmZVeID2QQdUaDfIEViFHu95xDrGiUCQQDx3YOKn3yaEctk/ERVn7hDAyAXUbd8/pv2b24/M/l1ZevlsFem8U4Jk5Mu64t3z3YGJoymEjQmbucwT01iKhehAkEAxlnccsRmfFh/KkqauKE4M4++NTAd9zlInpUsmZ+cN8UEGnF2RTEzRKBrLOt1uWCqBB7PGiE6DVTVjr7FAQPrSQJAT5yeY87DcONSk9cFlzmPqV8p/QME5rvYEnHzVBKDlkUKNPyqnWToTvaoh9U4fyNmsfeWbEOprszqhFhWHG3GgQJAK8+ynmyFhaw63+Hx2KU5zR4hVuQso2IzrEurGxCxybV6mR7VBerb4502+EPx3PmOgxQL+niUFhcMWxcvBFP9+A==
|
||||
VITE_APP_MONITOR_ADMIN=/admin/applications
|
||||
VITE_APP_SNAILJOB_ADMIN=/snail-job
|
||||
# 页面标题
|
||||
VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统
|
||||
|
||||
# 生产环境配置
|
||||
VITE_APP_ENV = 'production'
|
||||
|
||||
# 应用访问路径 例如使用前缀 /admin/
|
||||
VITE_APP_CONTEXT_PATH = '/'
|
||||
|
||||
# 监控地址
|
||||
VITE_APP_MONITOR_ADMIN = '/admin/applications'
|
||||
|
||||
# SnailJob 控制台地址
|
||||
VITE_APP_SNAILJOB_ADMIN = '/snail-job'
|
||||
|
||||
# 生产环境
|
||||
VITE_APP_BASE_API = '/prod-api'
|
||||
|
||||
# 是否在打包时开启压缩,支持 gzip 和 brotli
|
||||
VITE_BUILD_COMPRESS = gzip
|
||||
|
||||
VITE_APP_PORT = 80
|
||||
|
||||
# 接口加密功能开关(如需关闭 后端也必须对应关闭)
|
||||
VITE_APP_ENCRYPT = true
|
||||
# 接口加密传输 RSA 公钥与后端解密私钥对应 如更换需前后端一同更换
|
||||
VITE_APP_RSA_PUBLIC_KEY = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
|
||||
# 接口响应解密 RSA 私钥与后端加密公钥对应 如更换需前后端一同更换
|
||||
VITE_APP_RSA_PRIVATE_KEY = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE='
|
||||
|
||||
# 客户端id
|
||||
VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||
|
||||
# websocket 开关 默认使用sse推送
|
||||
VITE_APP_WEBSOCKET = false
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
*.sh
|
||||
node_modules
|
||||
*.md
|
||||
*.woff
|
||||
*.ttf
|
||||
.vscode
|
||||
.idea
|
||||
dist
|
||||
/public
|
||||
/docs
|
||||
.husky
|
||||
.local
|
||||
/bin
|
||||
.eslintrc.cjs
|
||||
prettier.config.js
|
||||
src/assets
|
||||
tailwind.config.js
|
||||
@@ -0,0 +1,312 @@
|
||||
{
|
||||
"globals": {
|
||||
"ComponentInternalInstance": true,
|
||||
"TransferKey": true,
|
||||
"ElFormRules": true,
|
||||
"CheckboxValueType": true,
|
||||
"PropType": true,
|
||||
"DateModelType": true,
|
||||
"UploadFile": true,
|
||||
"ElFormInstance": true,
|
||||
"ElTableInstance": true,
|
||||
"ElTreeInstance": true,
|
||||
"ElTreeSelectInstance": true,
|
||||
"ElSelectInstance": true,
|
||||
"ElUploadInstance": true,
|
||||
"ElCardInstance": true,
|
||||
"ElDialogInstance": true,
|
||||
"ElInputInstance": true,
|
||||
"ElInputNumberInstance": true,
|
||||
"ElRadioInstance": true,
|
||||
"ElRadioGroupInstance": true,
|
||||
"ElRadioButtonInstance": true,
|
||||
"ElCheckboxInstance": true,
|
||||
"ElCheckboxGroupInstance": true,
|
||||
"ElSwitchInstance": true,
|
||||
"ElDatePickerInstance": true,
|
||||
"ElTimePickerInstance": true,
|
||||
"ElTimeSelectInstance": true,
|
||||
"ElScrollbarInstance": true,
|
||||
"ElCascaderInstance": true,
|
||||
"ElColorPickerInstance": true,
|
||||
"ElRateInstance": true,
|
||||
"ElSliderInstance": true,
|
||||
"useRouter": true,
|
||||
"useRoute": true,
|
||||
"EffectScope": true,
|
||||
"ElTable": true,
|
||||
"ElSelect": true,
|
||||
"ElUpload": true,
|
||||
"ElForm": true,
|
||||
"ElTree": true,
|
||||
"ElMessage": true,
|
||||
"ElMessageBox": true,
|
||||
"asyncComputed": true,
|
||||
"autoResetRef": true,
|
||||
"computed": true,
|
||||
"computedAsync": true,
|
||||
"computedEager": true,
|
||||
"computedInject": true,
|
||||
"computedWithControl": true,
|
||||
"controlledComputed": true,
|
||||
"controlledRef": true,
|
||||
"createApp": true,
|
||||
"createEventHook": true,
|
||||
"createGlobalState": true,
|
||||
"createInjectionState": true,
|
||||
"createReactiveFn": true,
|
||||
"createSharedComposable": true,
|
||||
"createUnrefFn": true,
|
||||
"customRef": true,
|
||||
"debouncedRef": true,
|
||||
"debouncedWatch": true,
|
||||
"defineAsyncComponent": true,
|
||||
"defineComponent": true,
|
||||
"eagerComputed": true,
|
||||
"effectScope": true,
|
||||
"extendRef": true,
|
||||
"getCurrentInstance": true,
|
||||
"getCurrentScope": true,
|
||||
"h": true,
|
||||
"ignorableWatch": true,
|
||||
"inject": true,
|
||||
"isDefined": true,
|
||||
"isProxy": true,
|
||||
"isReactive": true,
|
||||
"isReadonly": true,
|
||||
"isRef": true,
|
||||
"makeDestructurable": true,
|
||||
"markRaw": true,
|
||||
"nextTick": true,
|
||||
"onActivated": true,
|
||||
"onBeforeMount": true,
|
||||
"onBeforeUnmount": true,
|
||||
"onBeforeUpdate": true,
|
||||
"onClickOutside": true,
|
||||
"onDeactivated": true,
|
||||
"onErrorCaptured": true,
|
||||
"onKeyStroke": true,
|
||||
"onLongPress": true,
|
||||
"onMounted": true,
|
||||
"onRenderTracked": true,
|
||||
"onRenderTriggered": true,
|
||||
"onScopeDispose": true,
|
||||
"onServerPrefetch": true,
|
||||
"onStartTyping": true,
|
||||
"onUnmounted": true,
|
||||
"onUpdated": true,
|
||||
"pausableWatch": true,
|
||||
"provide": true,
|
||||
"reactify": true,
|
||||
"reactifyObject": true,
|
||||
"reactive": true,
|
||||
"reactiveComputed": true,
|
||||
"reactiveOmit": true,
|
||||
"reactivePick": true,
|
||||
"readonly": true,
|
||||
"ref": true,
|
||||
"refAutoReset": true,
|
||||
"refDebounced": true,
|
||||
"refDefault": true,
|
||||
"refThrottled": true,
|
||||
"refWithControl": true,
|
||||
"resolveComponent": true,
|
||||
"resolveDirective": true,
|
||||
"resolveRef": true,
|
||||
"resolveUnref": true,
|
||||
"shallowReactive": true,
|
||||
"shallowReadonly": true,
|
||||
"shallowRef": true,
|
||||
"syncRef": true,
|
||||
"syncRefs": true,
|
||||
"templateRef": true,
|
||||
"throttledRef": true,
|
||||
"throttledWatch": true,
|
||||
"toRaw": true,
|
||||
"toReactive": true,
|
||||
"toRef": true,
|
||||
"toRefs": true,
|
||||
"triggerRef": true,
|
||||
"tryOnBeforeMount": true,
|
||||
"tryOnBeforeUnmount": true,
|
||||
"tryOnMounted": true,
|
||||
"tryOnScopeDispose": true,
|
||||
"tryOnUnmounted": true,
|
||||
"unref": true,
|
||||
"unrefElement": true,
|
||||
"until": true,
|
||||
"useActiveElement": true,
|
||||
"useArrayEvery": true,
|
||||
"useArrayFilter": true,
|
||||
"useArrayFind": true,
|
||||
"useArrayFindIndex": true,
|
||||
"useArrayFindLast": true,
|
||||
"useArrayJoin": true,
|
||||
"useArrayMap": true,
|
||||
"useArrayReduce": true,
|
||||
"useArraySome": true,
|
||||
"useArrayUnique": true,
|
||||
"useAsyncQueue": true,
|
||||
"useAsyncState": true,
|
||||
"useAttrs": true,
|
||||
"useBase64": true,
|
||||
"useBattery": true,
|
||||
"useBluetooth": true,
|
||||
"useBreakpoints": true,
|
||||
"useBroadcastChannel": true,
|
||||
"useBrowserLocation": true,
|
||||
"useCached": true,
|
||||
"useClipboard": true,
|
||||
"useCloned": true,
|
||||
"useColorMode": true,
|
||||
"useConfirmDialog": true,
|
||||
"useCounter": true,
|
||||
"useCssModule": true,
|
||||
"useCssVar": true,
|
||||
"useCssVars": true,
|
||||
"useCurrentElement": true,
|
||||
"useCycleList": true,
|
||||
"useDark": true,
|
||||
"useDateFormat": true,
|
||||
"useDebounce": true,
|
||||
"useDebounceFn": true,
|
||||
"useDebouncedRefHistory": true,
|
||||
"useDeviceMotion": true,
|
||||
"useDeviceOrientation": true,
|
||||
"useDevicePixelRatio": true,
|
||||
"useDevicesList": true,
|
||||
"useDisplayMedia": true,
|
||||
"useDocumentVisibility": true,
|
||||
"useDraggable": true,
|
||||
"useDropZone": true,
|
||||
"useElementBounding": true,
|
||||
"useElementByPoint": true,
|
||||
"useElementHover": true,
|
||||
"useElementSize": true,
|
||||
"useElementVisibility": true,
|
||||
"useEventBus": true,
|
||||
"useEventListener": true,
|
||||
"useEventSource": true,
|
||||
"useEyeDropper": true,
|
||||
"useFavicon": true,
|
||||
"useFetch": true,
|
||||
"useFileDialog": true,
|
||||
"useFileSystemAccess": true,
|
||||
"useFocus": true,
|
||||
"useFocusWithin": true,
|
||||
"useFps": true,
|
||||
"useFullscreen": true,
|
||||
"useGamepad": true,
|
||||
"useGeolocation": true,
|
||||
"useIdle": true,
|
||||
"useImage": true,
|
||||
"useInfiniteScroll": true,
|
||||
"useIntersectionObserver": true,
|
||||
"useInterval": true,
|
||||
"useIntervalFn": true,
|
||||
"useKeyModifier": true,
|
||||
"useLastChanged": true,
|
||||
"useLocalStorage": true,
|
||||
"useMagicKeys": true,
|
||||
"useManualRefHistory": true,
|
||||
"useMediaControls": true,
|
||||
"useMediaQuery": true,
|
||||
"useMemoize": true,
|
||||
"useMemory": true,
|
||||
"useMounted": true,
|
||||
"useMouse": true,
|
||||
"useMouseInElement": true,
|
||||
"useMousePressed": true,
|
||||
"useMutationObserver": true,
|
||||
"useNavigatorLanguage": true,
|
||||
"useNetwork": true,
|
||||
"useNow": true,
|
||||
"useObjectUrl": true,
|
||||
"useOffsetPagination": true,
|
||||
"useOnline": true,
|
||||
"usePageLeave": true,
|
||||
"useParallax": true,
|
||||
"usePermission": true,
|
||||
"usePointer": true,
|
||||
"usePointerLock": true,
|
||||
"usePointerSwipe": true,
|
||||
"usePreferredColorScheme": true,
|
||||
"usePreferredContrast": true,
|
||||
"usePreferredDark": true,
|
||||
"usePreferredLanguages": true,
|
||||
"usePreferredReducedMotion": true,
|
||||
"usePrevious": true,
|
||||
"useRafFn": true,
|
||||
"useRefHistory": true,
|
||||
"useResizeObserver": true,
|
||||
"useScreenOrientation": true,
|
||||
"useScreenSafeArea": true,
|
||||
"useScriptTag": true,
|
||||
"useScroll": true,
|
||||
"useScrollLock": true,
|
||||
"useSessionStorage": true,
|
||||
"useShare": true,
|
||||
"useSlots": true,
|
||||
"useSorted": true,
|
||||
"useSpeechRecognition": true,
|
||||
"useSpeechSynthesis": true,
|
||||
"useStepper": true,
|
||||
"useStorage": true,
|
||||
"useStorageAsync": true,
|
||||
"useStyleTag": true,
|
||||
"useSupported": true,
|
||||
"useSwipe": true,
|
||||
"useTemplateRefsList": true,
|
||||
"useTextDirection": true,
|
||||
"useTextSelection": true,
|
||||
"useTextareaAutosize": true,
|
||||
"useThrottle": true,
|
||||
"useThrottleFn": true,
|
||||
"useThrottledRefHistory": true,
|
||||
"useTimeAgo": true,
|
||||
"useTimeout": true,
|
||||
"useTimeoutFn": true,
|
||||
"useTimeoutPoll": true,
|
||||
"useTimestamp": true,
|
||||
"useTitle": true,
|
||||
"useToNumber": true,
|
||||
"useToString": true,
|
||||
"useToggle": true,
|
||||
"useTransition": true,
|
||||
"useUrlSearchParams": true,
|
||||
"useUserMedia": true,
|
||||
"useVModel": true,
|
||||
"useVModels": true,
|
||||
"useVibrate": true,
|
||||
"useVirtualList": true,
|
||||
"useWakeLock": true,
|
||||
"useWebNotification": true,
|
||||
"useWebSocket": true,
|
||||
"useWebWorker": true,
|
||||
"useWebWorkerFn": true,
|
||||
"useWindowFocus": true,
|
||||
"useWindowScroll": true,
|
||||
"useWindowSize": true,
|
||||
"watch": true,
|
||||
"watchArray": true,
|
||||
"watchAtMost": true,
|
||||
"watchDebounced": true,
|
||||
"watchEffect": true,
|
||||
"watchIgnorable": true,
|
||||
"watchOnce": true,
|
||||
"watchPausable": true,
|
||||
"watchPostEffect": true,
|
||||
"watchSyncEffect": true,
|
||||
"watchThrottled": true,
|
||||
"watchTriggerable": true,
|
||||
"watchWithFilter": true,
|
||||
"whenever": true,
|
||||
"ImportOption": true,
|
||||
"TreeType": true,
|
||||
"FieldOption": true,
|
||||
"PageData": true,
|
||||
"storeToRefs": true,
|
||||
"DictDataOption": true,
|
||||
"UploadOption": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true
|
||||
},
|
||||
parser: 'vue-eslint-parser',
|
||||
extends: [
|
||||
'plugin:vue/vue3-recommended',
|
||||
'./.eslintrc-auto-import.json',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'prettier',
|
||||
'plugin:prettier/recommended'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: '2020',
|
||||
sourceType: 'module',
|
||||
project: './tsconfig.*?.json',
|
||||
parser: '@typescript-eslint/parser'
|
||||
},
|
||||
plugins: ['vue', '@typescript-eslint', 'import', 'promise', 'node', 'prettier'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-this-alias': 'off',
|
||||
|
||||
// vue
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/valid-define-props': 'off',
|
||||
'vue/no-v-model-argument': 'off',
|
||||
'prefer-rest-params': 'off',
|
||||
// prettier
|
||||
'prettier/prettier': 'error',
|
||||
'@typescript-eslint/ban-types': [
|
||||
'error',
|
||||
{
|
||||
// 关闭空类型检查 {}
|
||||
extendDefaults: true,
|
||||
types: {
|
||||
'{}': false,
|
||||
Function: false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
globals: {
|
||||
DialogOption: 'readonly',
|
||||
OptionType: 'readonly'
|
||||
}
|
||||
};
|
||||
+29
-10
@@ -1,10 +1,29 @@
|
||||
node_modules
|
||||
dist
|
||||
.umi
|
||||
.umi-production
|
||||
src/.umi
|
||||
src/.umi-production
|
||||
.env.local
|
||||
*.log
|
||||
.idea/
|
||||
*.iml
|
||||
.DS_Store
|
||||
.history
|
||||
node_modules/
|
||||
dist/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
**/*.log
|
||||
|
||||
tests/**/coverage/
|
||||
tests/e2e/reports
|
||||
selenium-debug.log
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.local
|
||||
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
|
||||
# 编译生成的文件
|
||||
auto-imports.d.ts
|
||||
components.d.ts
|
||||
|
||||
Generated
-10
@@ -1,10 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<option name="BUILD_PROCESS_HEAP_SIZE" value="2048" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-3
@@ -1,3 +0,0 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="LionLi" />
|
||||
</component>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-17
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||
<entry key="Project Default">
|
||||
<profile-state>
|
||||
<selected-state>
|
||||
<State>
|
||||
<id>User defined</id>
|
||||
</State>
|
||||
</selected-state>
|
||||
</profile-state>
|
||||
</entry>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_25" default="true" project-jdk-name="liberica-25" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/plus-ui-react.iml" filepath="$PROJECT_DIR$/.idea/plus-ui-react.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||
"ignorePatterns": ["src/.umi", "src/.umi-production", ".ai_state", ".claude", ".codex", "dist", "node_modules"],
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"arrowParens": "avoid",
|
||||
"htmlWhitespaceSensitivity": "ignore",
|
||||
"experimentalSortPackageJson": {
|
||||
"sortScripts": true
|
||||
},
|
||||
"sortImports": {
|
||||
"newlinesBetween": false,
|
||||
"groups": [
|
||||
"type-import",
|
||||
["value-builtin", "value-external"],
|
||||
"type-internal",
|
||||
"value-internal",
|
||||
["type-parent", "type-sibling", "type-index"],
|
||||
["value-parent", "value-sibling", "value-index"],
|
||||
"unknown"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json",
|
||||
"plugins": ["eslint", "typescript", "unicorn", "oxc", "import", "react"],
|
||||
"rules": {
|
||||
"typescript/no-empty-function": "off",
|
||||
"typescript/no-explicit-any": "off",
|
||||
"typescript/no-unused-vars": "off",
|
||||
"typescript/no-this-alias": "off",
|
||||
"typescript/no-empty-object-type": "off",
|
||||
"typescript/no-unused-expressions": "off",
|
||||
"prefer-rest-params": "off",
|
||||
"import/no-unassigned-import": "off",
|
||||
"import/no-named-as-default-member": "off",
|
||||
"import/no-named-as-default": "off",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
"react/no-unstable-nested-components": "off",
|
||||
"react/iframe-missing-sandbox": "off",
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
"no-shadow": "off",
|
||||
"unicorn/no-array-sort": "off",
|
||||
"unicorn/no-useless-fallback-in-spread": "off",
|
||||
"unicorn/prefer-add-event-listener": "off",
|
||||
"unicorn/consistent-function-scoping": "off",
|
||||
"unicorn/no-instanceof-builtins": "off"
|
||||
},
|
||||
"categories": {
|
||||
"correctness": "error",
|
||||
"suspicious": "error"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"src/.umi",
|
||||
"src/.umi-production",
|
||||
".ai_state",
|
||||
".claude",
|
||||
".codex",
|
||||
"dist/**",
|
||||
"dist-ssr/**",
|
||||
"coverage/**"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/dist/*
|
||||
.local
|
||||
.output.js
|
||||
/node_modules/**
|
||||
|
||||
**/*.svg
|
||||
**/*.sh
|
||||
|
||||
/public/*
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"printWidth": 150,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"quoteProps": "preserve",
|
||||
"jsxSingleQuote": false,
|
||||
"bracketSameLine": false,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": true,
|
||||
"embeddedLanguageFormatting": "auto",
|
||||
"arrowParens": "always",
|
||||
"requirePragma": false,
|
||||
"insertPragma": false,
|
||||
"proseWrap": "preserve",
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"vueIndentScriptAndStyle": false,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 RuoYi-Vue-Plus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -1,43 +1,35 @@
|
||||
# RuoYi-React-Plus
|
||||
|
||||
## 平台简介
|
||||
|
||||
- 本仓库为前端技术栈 [React](https://react.dev/) + [TypeScript](https://www.typescriptlang.org/) + [Ant Design](https://ant.design/) + [Umi Max](https://umijs.org/) + [Vite](https://vitejs.dev/)。
|
||||
- 官方项目: 基于 Vue + ElementPlus 版本前端项目 [plus-ui](https://gitee.com/JavaLionLi/plus-ui)
|
||||
- 成员项目: 基于 vben5(ant-design-vue) 的前端项目 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5)
|
||||
- 成员项目: 基于soybean 的前端项目 [ruoyi-plus-soybean](https://gitee.com/xlsea/ruoyi-plus-soybean)
|
||||
|
||||
## 配套后端代码仓库地址
|
||||
|
||||
| 介绍 | 项目名 | 项目地址 |
|
||||
| -------------- | :--------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 分布式集群框架 | RuoYi-Vue-Plus | [Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus) / [GitHub](https://github.com/dromara/RuoYi-Vue-Plus) / [GitCode](https://gitcode.com/dromara/RuoYi-Vue-Plus) |
|
||||
| 微服务框架 | RuoYi-Cloud-Plus | [Gitee](https://gitee.com/dromara/RuoYi-Cloud-Plus) / [GitHub](https://github.com/dromara/RuoYi-Cloud-Plus) / [GitCode](https://gitcode.com/dromara/RuoYi-Cloud-Plus) |
|
||||
|
||||
## 分支说明
|
||||
|
||||
- 6.X-react分支(稳定发布主分支 生产可用)
|
||||
- dev-react分支(开发分支 开发过程中使用)
|
||||
- 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [TS](https://www.typescriptlang.org/) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。
|
||||
- 成员项目: 基于 vben(ant-design-vue) 的前端项目 [ruoyi-plus-vben](https://gitee.com/dapppp/ruoyi-plus-vben)
|
||||
- 配套后端代码仓库地址
|
||||
- [RuoYi-Vue-Plus 5.X(注意版本号)](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||
- [RuoYi-Cloud-Plus 2.X(注意版本号)](https://gitee.com/dromara/RuoYi-Cloud-Plus)
|
||||
|
||||
## 前端运行
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone https://gitee.com/JavaLionLi/plus-ui.git
|
||||
|
||||
# 安装依赖
|
||||
pnpm install --registry=https://registry.npmmirror.com
|
||||
npm install --registry=https://registry.npmmirror.com
|
||||
|
||||
# 启动服务
|
||||
pnpm dev
|
||||
npm run dev
|
||||
|
||||
# 构建生产环境
|
||||
pnpm build:prod
|
||||
npm run build:prod
|
||||
|
||||
# 前端访问地址 http://localhost:8000
|
||||
# 前端访问地址 http://localhost:80
|
||||
```
|
||||
|
||||
## 本框架与RuoYi的业务差异
|
||||
|
||||
| 业务 | 功能说明 | 本框架 | RuoYi |
|
||||
| ------------ | ------------------------------------------------------------- | ------ | ----------------------------- |
|
||||
| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 |
|
||||
| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 |
|
||||
| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 |
|
||||
| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 |
|
||||
| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 |
|
||||
@@ -61,18 +53,24 @@ pnpm build:prod
|
||||
|
||||
## 演示图例
|
||||
|
||||
| | |
|
||||
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
| | |
|
||||
| ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 打包Web工程,生成dist文件。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
yarn build:prod
|
||||
|
||||
pause
|
||||
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 安装Web工程,生成node_modules文件。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
yarn --registry=https://registry.npmmirror.com
|
||||
|
||||
pause
|
||||
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
echo.
|
||||
echo [信息] 使用 Vite 命令运行 Web 工程。
|
||||
echo.
|
||||
|
||||
%~d0
|
||||
cd %~dp0
|
||||
|
||||
cd ..
|
||||
yarn dev
|
||||
|
||||
pause
|
||||
@@ -1,40 +0,0 @@
|
||||
import { defineConfig } from '@umijs/max';
|
||||
import { createUmiAppConfig } from '../vite.config';
|
||||
|
||||
const appConfig = createUmiAppConfig();
|
||||
|
||||
export default defineConfig({
|
||||
title: appConfig.title,
|
||||
antd: {},
|
||||
access: {},
|
||||
model: {},
|
||||
initialState: {},
|
||||
vite: appConfig.vite,
|
||||
npmClient: 'pnpm',
|
||||
hash: true,
|
||||
esbuildMinifyIIFE: true,
|
||||
history: {
|
||||
type: 'browser'
|
||||
},
|
||||
base: appConfig.base,
|
||||
publicPath: appConfig.publicPath,
|
||||
routes: [
|
||||
{ path: '/login', component: './login', layout: false },
|
||||
{ path: '/register', component: './register', layout: false },
|
||||
{ path: '/social-callback', component: './socialCallback', layout: false },
|
||||
{ path: '/401', component: './error/401', layout: false },
|
||||
{ path: '/404', component: './error/404', layout: false },
|
||||
{ path: '/redirect/*', component: './redirect', layout: false },
|
||||
{
|
||||
path: '/',
|
||||
component: '../layouts/BasicLayout',
|
||||
routes: [
|
||||
{ path: '/', redirect: '/index' },
|
||||
{ path: '/index', component: './index' },
|
||||
{ path: '/user/profile', component: './system/user/profile' },
|
||||
{ path: '*', component: './dynamicPage' }
|
||||
]
|
||||
}
|
||||
],
|
||||
proxy: appConfig.proxy
|
||||
});
|
||||
@@ -1,94 +0,0 @@
|
||||
import type { <#if !table.tree>PageResult, </#if> R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from './types';
|
||||
|
||||
/**
|
||||
* 查询${functionName}列表
|
||||
*/
|
||||
export function list${BusinessName}(query?: ${BusinessName}Query) {
|
||||
return request<R<<#if table.tree>${BusinessName}VO[]<#else> PageResult<${BusinessName}VO></#if>>>({
|
||||
url: '/${moduleName}/${businessName}/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询${functionName}详细
|
||||
*/
|
||||
export function get${BusinessName}(${pkColumn.javaField}: string | number) {
|
||||
return request<R<${BusinessName}VO>>({
|
||||
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增${functionName}
|
||||
*/
|
||||
export function add${BusinessName}(data: ${BusinessName}Form) {
|
||||
return request<R>({
|
||||
url: '/${moduleName}/${businessName}',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改${functionName}
|
||||
*/
|
||||
export function update${BusinessName}(data: ${BusinessName}Form) {
|
||||
return request<R>({
|
||||
url: '/${moduleName}/${businessName}',
|
||||
method: 'put',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
<#if enableStatus>
|
||||
/**
|
||||
* 修改${functionName}状态
|
||||
*/
|
||||
export function change${BusinessName}Status(
|
||||
${pkColumn.javaField}: string | number,
|
||||
${statusField}: <#if statusColumn.javaType == 'Boolean'>boolean<#elseif statusColumn.javaType == 'Integer' || statusColumn.javaType == 'Long'>number<#else> string</#if>
|
||||
) {
|
||||
return request<R>({
|
||||
url: '/${moduleName}/${businessName}/changeStatus',
|
||||
method: 'put',
|
||||
data: {
|
||||
${pkColumn.javaField},
|
||||
${statusField}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</#if>
|
||||
<#if enableSort>
|
||||
/**
|
||||
* 调整${functionName}排序
|
||||
*/
|
||||
export function update${BusinessName}Sort(
|
||||
${pkColumn.javaField}: string | number,
|
||||
${sortField}: <#if sortColumn.javaType == 'LocalDateTime' || sortColumn.javaType == 'String'>string<#else> number</#if>
|
||||
) {
|
||||
return request<R>({
|
||||
url: '/${moduleName}/${businessName}/updateSort',
|
||||
method: 'put',
|
||||
data: {
|
||||
${pkColumn.javaField},
|
||||
${sortField}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
</#if>
|
||||
/**
|
||||
* 删除${functionName}
|
||||
*/
|
||||
export function del${BusinessName}(${pkColumn.javaField}: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -1,424 +0,0 @@
|
||||
import { DeleteOutlined<#if enableExport>, DownloadOutlined</#if>, EditOutlined, PlusOutlined, SortAscendingOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
ModalForm,
|
||||
PageContainer,
|
||||
<#if needCheckbox>
|
||||
ProFormCheckbox,
|
||||
</#if>
|
||||
<#if needDateField>
|
||||
ProFormDateTimePicker,
|
||||
</#if>
|
||||
<#if needDigit>
|
||||
ProFormDigit,
|
||||
</#if>
|
||||
<#if needSelect>
|
||||
ProFormSelect,
|
||||
</#if>
|
||||
<#if needTextArea>
|
||||
ProFormTextArea,
|
||||
</#if>
|
||||
ProFormText,
|
||||
ProFormTreeSelect,
|
||||
ProTable,
|
||||
type ActionType,
|
||||
type ProColumns
|
||||
} from '@ant-design/pro-components';
|
||||
import { useBoolean } from 'ahooks';
|
||||
import { Button, Form, message<#if enableStatus || needSwitchField>, Switch</#if><#if enableSort>, InputNumber</#if> } from 'antd';
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
||||
import {
|
||||
add${BusinessName},
|
||||
<#if enableStatus>
|
||||
change${BusinessName}Status,
|
||||
</#if>
|
||||
del${BusinessName},
|
||||
get${BusinessName},
|
||||
list${BusinessName},
|
||||
<#if enableSort>
|
||||
update${BusinessName}Sort,
|
||||
</#if>
|
||||
update${BusinessName}
|
||||
} from '@/api/${moduleName}/${businessName}';
|
||||
<#if needDict>
|
||||
import DictTag from '@/components/common/DictTag';
|
||||
</#if>
|
||||
<#if needFileUpload>
|
||||
import FileUpload from '@/components/common/FileUpload';
|
||||
</#if>
|
||||
<#if needImagePreview>
|
||||
import ImagePreview from '@/components/common/ImagePreview';
|
||||
</#if>
|
||||
<#if needImageUpload>
|
||||
import ImageUpload from '@/components/common/ImageUpload';
|
||||
</#if>
|
||||
<#if needEditor>
|
||||
import RichTextEditor from '@/components/common/RichTextEditor';
|
||||
</#if>
|
||||
import RowActions from '@/components/common/RowActions';
|
||||
<#if needDict>
|
||||
import { useDict } from '@/hooks/useDict';
|
||||
</#if>
|
||||
<#if enableExport>
|
||||
import { useTableExport } from '@/hooks/useTableExport';
|
||||
</#if>
|
||||
import { useTableScroll } from '@/hooks/useTableScroll';
|
||||
import { useTreeTableExpand } from '@/hooks/useTreeTableExpand';
|
||||
import { useUserStore } from '@/stores/userStore';
|
||||
<#if needDict>
|
||||
import { dictOptions } from '@/utils/dict';
|
||||
</#if>
|
||||
<#if enableStatus>
|
||||
import { confirmAction } from '@/utils/modal';
|
||||
</#if>
|
||||
import { hasPermi } from '@/utils/permission';
|
||||
import { filterTree<#if needDateField>, formatDateTimeFields</#if>, handleTree<#if needDateField>, toDayjsFields</#if> } from '@/utils/ruoyi';
|
||||
|
||||
const default${BusinessName}Form: ${BusinessName}Form = {
|
||||
${treeParentCode}: ${treeRootValueTsLiteral},
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && !column.pk && column.htmlType == "checkbox">
|
||||
${column.javaField}: [],
|
||||
</#if>
|
||||
</#list>
|
||||
};
|
||||
|
||||
interface ${BusinessName}SelectNode {
|
||||
title: string;
|
||||
value: string | number;
|
||||
children?: ${BusinessName}SelectNode[];
|
||||
}
|
||||
|
||||
function toTreeSelectData(nodes: ${BusinessName}VO[]): ${BusinessName}SelectNode[] {
|
||||
return nodes.map(node => ({
|
||||
title: String(node.${treeName} || ''),
|
||||
value: node.${treeCode},
|
||||
children: node.children ? toTreeSelectData(node.children) : undefined
|
||||
}));
|
||||
}
|
||||
|
||||
<#if enableStatus>
|
||||
const ${statusField}ActiveValue = <#if statusColumn.javaType == "Boolean">true<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">0<#else>'0'</#if>;
|
||||
const ${statusField}InactiveValue = <#if statusColumn.javaType == "Boolean">false<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">1<#else>'1'</#if>;
|
||||
|
||||
</#if>
|
||||
export default function ${BusinessName}Page() {
|
||||
const actionRef = useRef<ActionType | undefined>(undefined);
|
||||
const { tableScroll } = useTableScroll(1000);
|
||||
const [form] = Form.useForm<${BusinessName}Form>();
|
||||
const userInfo = useUserStore(state => state.userInfo);
|
||||
<#if needDict>
|
||||
const dicts = useDict(${dicts});
|
||||
</#if>
|
||||
const [treeOptions, setTreeOptions] = useState<${BusinessName}VO[]>([]);
|
||||
const [tableRows, setTableRows] = useState<${BusinessName}VO[]>([]);
|
||||
const { expandAll, expandedRowKeys, onExpandedRowsChange, syncExpandedRows, toggleExpandAll } =
|
||||
useTreeTableExpand<${BusinessName}VO>(row => row.${treeCode});
|
||||
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
||||
const [modalTitle, setModalTitle] = useState('');
|
||||
<#if enableExport>
|
||||
const { updateExportParams, exportFile } = useTableExport();
|
||||
</#if>
|
||||
|
||||
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
|
||||
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
|
||||
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
|
||||
<#if enableExport>
|
||||
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
|
||||
</#if>
|
||||
const treeSelectData = useMemo(
|
||||
() => [{ title: '顶级节点', value: ${treeRootValueTsLiteral}, children: toTreeSelectData(treeOptions) }],
|
||||
[treeOptions]
|
||||
);
|
||||
|
||||
const loadTreeOptions = async (excludeId?: string | number) => {
|
||||
const res = await list${BusinessName}();
|
||||
const rows = handleTree<${BusinessName}VO>(res.data || [], '${treeCode}', '${treeParentCode}');
|
||||
setTreeOptions(excludeId ? filterTree(rows, node => node.${treeCode} !== excludeId) : rows);
|
||||
};
|
||||
|
||||
const openAdd = async (row?: ${BusinessName}VO) => {
|
||||
await loadTreeOptions();
|
||||
form.resetFields();
|
||||
form.setFieldsValue({ ...default${BusinessName}Form, ${treeParentCode}: row?.${treeCode} || treeRootValueTsLiteral });
|
||||
setModalTitle('添加${functionName}');
|
||||
openModal();
|
||||
};
|
||||
|
||||
const openEdit = async (row: ${BusinessName}VO) => {
|
||||
await loadTreeOptions(row.${treeCode});
|
||||
const res = await get${BusinessName}(row.${pkColumn.javaField});
|
||||
const data = <#if needDateField>toDayjsFields({ ...res.data }, [
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
||||
'${column.javaField}',
|
||||
</#if>
|
||||
</#list>
|
||||
])<#else>{ ...res.data }</#if>;
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
||||
if (typeof data.${column.javaField} === 'string') {
|
||||
data.${column.javaField} = data.${column.javaField}.split(',');
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
form.resetFields();
|
||||
form.setFieldsValue(data);
|
||||
setModalTitle('修改${functionName}');
|
||||
openModal();
|
||||
};
|
||||
|
||||
const submitForm = async (values: ${BusinessName}Form) => {
|
||||
const submitValues = <#if needDateField>formatDateTimeFields({ ...values }, [
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
||||
'${column.javaField}',
|
||||
</#if>
|
||||
</#list>
|
||||
])<#else>{ ...values }</#if>;
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
||||
if (Array.isArray(submitValues.${column.javaField})) {
|
||||
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
|
||||
message.success('操作成功');
|
||||
form.resetFields();
|
||||
actionRef.current?.reload();
|
||||
return true;
|
||||
};
|
||||
|
||||
const remove = async (row: ${BusinessName}VO) => {
|
||||
await del${BusinessName}(row.${pkColumn.javaField});
|
||||
message.success('删除成功');
|
||||
actionRef.current?.reload();
|
||||
};
|
||||
|
||||
<#if enableStatus>
|
||||
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
|
||||
const previousStatus = row.${statusField};
|
||||
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
|
||||
const text = checked ? '启用' : '停用';
|
||||
try {
|
||||
await confirmAction(`确认要"${r'${text}'}"吗?`);
|
||||
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
|
||||
message.success(`${r'${text}'}成功`);
|
||||
actionRef.current?.reload();
|
||||
} catch {
|
||||
row.${statusField} = previousStatus;
|
||||
actionRef.current?.reload();
|
||||
}
|
||||
};
|
||||
|
||||
</#if>
|
||||
<#if enableSort>
|
||||
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
|
||||
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
|
||||
message.success('排序更新成功');
|
||||
actionRef.current?.reload();
|
||||
};
|
||||
|
||||
</#if>
|
||||
const columns: ProColumns<${BusinessName}VO>[] = [
|
||||
<#list columns as column>
|
||||
<#if column.list && !column.pk>
|
||||
<#if enableStatus && statusField == column.javaField>
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}',
|
||||
valueType: 'select',
|
||||
width: 100,
|
||||
<#if column.dictType?has_content>
|
||||
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
||||
</#if>
|
||||
render: (_, row) => (
|
||||
<Switch
|
||||
checked={row.${column.javaField} === ${statusField}ActiveValue}
|
||||
disabled={!canEdit}
|
||||
onChange={checked => handleStatusChange(row, checked)}
|
||||
/>
|
||||
)
|
||||
},
|
||||
<#elseif enableSort && sortField == column.javaField>
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}',
|
||||
search: false,
|
||||
width: 130,
|
||||
render: (_, row) => <InputNumber min={0} value={row.${column.javaField} as number} onChange={value => handleSortChange(row, value)} />
|
||||
},
|
||||
<#elseif column.htmlType == "datetime">
|
||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}', valueType: 'dateTime', search: <#if column.query>true<#else> false</#if>, width: 170 },
|
||||
<#elseif column.htmlType == "imageUpload">
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}Url',
|
||||
search: false,
|
||||
width: 100,
|
||||
render: (_, row) => <ImagePreview src={row.${column.javaField}Url || String(row.${column.javaField} || '')} width={50} height={50} />
|
||||
},
|
||||
<#elseif column.dictColumn>
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}',
|
||||
valueType: 'select',
|
||||
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
||||
render: (_, row) => <DictTag options={dicts.${column.dictType}} value={row.${column.javaField}} />
|
||||
},
|
||||
<#elseif column.htmlType == "switch">
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}',
|
||||
valueType: 'select',
|
||||
width: 100,
|
||||
render: (_, row) => <Switch checked={row.${column.javaField} === ${column.switchActiveValue}} disabled />
|
||||
},
|
||||
<#else>
|
||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}'<#if !column.query>, search: false</#if> },
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 130,
|
||||
fixed: 'right',
|
||||
render: (_, row) => (
|
||||
<RowActions
|
||||
actions={[
|
||||
canEdit && { key: 'edit', label: '修改', icon: <EditOutlined />, onClick: () => openEdit(row) },
|
||||
canAdd && { key: 'add', label: '新增', icon: <PlusOutlined />, onClick: () => openAdd(row) },
|
||||
canRemove && {
|
||||
key: 'delete',
|
||||
label: '删除',
|
||||
icon: <DeleteOutlined />,
|
||||
danger: true,
|
||||
confirm: `是否确认删除${functionName}编号为"${r'${row.'}${pkColumn.javaField}${r'}'}"的数据项?`,
|
||||
onClick: () => remove(row)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<PageContainer title="${functionName}">
|
||||
<ProTable<${BusinessName}VO, ${BusinessName}Query>
|
||||
actionRef={actionRef}
|
||||
rowKey="${treeCode}"
|
||||
columns={columns}
|
||||
scroll={tableScroll}
|
||||
pagination={false}
|
||||
search={{ labelWidth: 90 }}
|
||||
expandable={{
|
||||
expandedRowKeys,
|
||||
onExpandedRowsChange
|
||||
}}
|
||||
request={async params => {
|
||||
const res = await list${BusinessName}(params);
|
||||
const rows = handleTree<${BusinessName}VO>(res.data || [], '${treeCode}', '${treeParentCode}');
|
||||
setTableRows(rows);
|
||||
syncExpandedRows(rows, expandAll);
|
||||
<#if enableExport>
|
||||
updateExportParams(params);
|
||||
</#if>
|
||||
return { data: rows, total: rows.length, success: true };
|
||||
}}
|
||||
toolbar={{ title: '${functionName}列表' }}
|
||||
toolBarRender={() => [
|
||||
canAdd && (
|
||||
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={() => openAdd()}>
|
||||
新增
|
||||
</Button>
|
||||
),
|
||||
<Button
|
||||
key="expand"
|
||||
icon={<SortAscendingOutlined />}
|
||||
onClick={() => toggleExpandAll(tableRows)}
|
||||
>
|
||||
展开/折叠
|
||||
</Button><#if enableExport>,
|
||||
canExport && (
|
||||
<Button
|
||||
key="export"
|
||||
icon={<DownloadOutlined />}
|
||||
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_${r'${Date.now()}'}.xlsx`)}
|
||||
>
|
||||
导出
|
||||
</Button>
|
||||
)</#if>
|
||||
]}
|
||||
/>
|
||||
|
||||
<ModalForm<${BusinessName}Form>
|
||||
title={modalTitle}
|
||||
open={modalOpen}
|
||||
width={560}
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={default${BusinessName}Form}
|
||||
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
|
||||
onOpenChange={open => !open && closeModal()}
|
||||
onFinish={submitForm}
|
||||
>
|
||||
<ProFormText name="${pkColumn.javaField}" hidden />
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && !column.pk>
|
||||
<#if column.javaField == treeParentCode>
|
||||
<ProFormTreeSelect
|
||||
name="${column.javaField}"
|
||||
label="${column.columnLabel}"
|
||||
<#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>
|
||||
fieldProps={{
|
||||
allowClear: true,
|
||||
treeDefaultExpandAll: true,
|
||||
treeData: treeSelectData,
|
||||
placeholder: '请选择${column.columnLabel}'
|
||||
}}
|
||||
/>
|
||||
<#elseif column.htmlType == "input">
|
||||
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "textarea">
|
||||
<ProFormTextArea name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "inputNumber">
|
||||
<ProFormDigit name="${column.javaField}" label="${column.columnLabel}" min={0} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif (column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch") && column.dictType?has_content>
|
||||
<ProFormSelect name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
|
||||
<ProFormCheckbox.Group name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "switch">
|
||||
<Form.Item
|
||||
name="${column.javaField}"
|
||||
label="${column.columnLabel}"
|
||||
valuePropName="checked"
|
||||
getValueProps={value => ({ checked: value === ${column.switchActiveValue} })}
|
||||
normalize={checked => (checked ? ${column.switchActiveValue} : ${column.switchInactiveValue})}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<#elseif column.htmlType == "datetime">
|
||||
<ProFormDateTimePicker name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "imageUpload">
|
||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||
<ImageUpload />
|
||||
</Form.Item>
|
||||
<#elseif column.htmlType == "fileUpload">
|
||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||
<FileUpload />
|
||||
</Form.Item>
|
||||
<#elseif column.htmlType == "editor">
|
||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||
<RichTextEditor />
|
||||
</Form.Item>
|
||||
<#else>
|
||||
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
</ModalForm>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
@@ -1,406 +0,0 @@
|
||||
import { DeleteOutlined<#if enableExport>, DownloadOutlined</#if>, EditOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
ModalForm,
|
||||
PageContainer,
|
||||
<#if needCheckbox>
|
||||
ProFormCheckbox,
|
||||
</#if>
|
||||
<#if needDateField>
|
||||
ProFormDateTimePicker,
|
||||
</#if>
|
||||
<#if needDigit>
|
||||
ProFormDigit,
|
||||
</#if>
|
||||
<#if needSelect>
|
||||
ProFormSelect,
|
||||
</#if>
|
||||
<#if needTextArea>
|
||||
ProFormTextArea,
|
||||
</#if>
|
||||
ProFormText,
|
||||
ProTable,
|
||||
type ActionType,
|
||||
type ProColumns
|
||||
} from '@ant-design/pro-components';
|
||||
import { useBoolean } from 'ahooks';
|
||||
import { Button, Form, message, Popconfirm<#if enableStatus || needSwitchField>, Switch</#if><#if enableSort>, InputNumber</#if> } from 'antd';
|
||||
import { useRef, useState } from 'react';
|
||||
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
||||
import {
|
||||
add${BusinessName},
|
||||
<#if enableStatus>
|
||||
change${BusinessName}Status,
|
||||
</#if>
|
||||
del${BusinessName},
|
||||
get${BusinessName},
|
||||
list${BusinessName},
|
||||
<#if enableSort>
|
||||
update${BusinessName}Sort,
|
||||
</#if>
|
||||
update${BusinessName}
|
||||
} from '@/api/${moduleName}/${businessName}';
|
||||
<#if needDict>
|
||||
import DictTag from '@/components/common/DictTag';
|
||||
</#if>
|
||||
<#if needFileUpload>
|
||||
import FileUpload from '@/components/common/FileUpload';
|
||||
</#if>
|
||||
<#if needImagePreview>
|
||||
import ImagePreview from '@/components/common/ImagePreview';
|
||||
</#if>
|
||||
<#if needImageUpload>
|
||||
import ImageUpload from '@/components/common/ImageUpload';
|
||||
</#if>
|
||||
<#if needEditor>
|
||||
import RichTextEditor from '@/components/common/RichTextEditor';
|
||||
</#if>
|
||||
import RowActions from '@/components/common/RowActions';
|
||||
<#if needDict>
|
||||
import { useDict } from '@/hooks/useDict';
|
||||
</#if>
|
||||
<#if needDateRange>
|
||||
import { useDateRangeQuery } from '@/hooks/useDateRangeQuery';
|
||||
</#if>
|
||||
<#if enableExport>
|
||||
import { useTableExport } from '@/hooks/useTableExport';
|
||||
</#if>
|
||||
import { useTableScroll } from '@/hooks/useTableScroll';
|
||||
import { useTableSelection } from '@/hooks/useTableSelection';
|
||||
import { useUserStore } from '@/stores/userStore';
|
||||
<#if needDict>
|
||||
import { dictOptions } from '@/utils/dict';
|
||||
</#if>
|
||||
<#if enableStatus>
|
||||
import { confirmAction } from '@/utils/modal';
|
||||
</#if>
|
||||
import { hasPermi } from '@/utils/permission';
|
||||
import { <#if needDateField>formatDateTimeFields, toDayjsFields, </#if> toPageQuery, toTableData } from '@/utils/ruoyi';
|
||||
|
||||
const default${BusinessName}Form: ${BusinessName}Form = {
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && !column.pk && column.htmlType == "checkbox">
|
||||
${column.javaField}: [],
|
||||
</#if>
|
||||
</#list>
|
||||
};
|
||||
|
||||
<#if enableStatus>
|
||||
const ${statusField}ActiveValue = <#if statusColumn.javaType == "Boolean">true<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">0<#else>'0'</#if>;
|
||||
const ${statusField}InactiveValue = <#if statusColumn.javaType == "Boolean">false<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">1<#else>'1'</#if>;
|
||||
|
||||
</#if>
|
||||
export default function ${BusinessName}Page() {
|
||||
const actionRef = useRef<ActionType | undefined>(undefined);
|
||||
const { tableScroll } = useTableScroll(1000);
|
||||
const [form] = Form.useForm<${BusinessName}Form>();
|
||||
const userInfo = useUserStore(state => state.userInfo);
|
||||
<#if needDict>
|
||||
const dicts = useDict(${dicts});
|
||||
</#if>
|
||||
const { ids, selectedOne, handleSelectionChange, clearSelection } = useTableSelection<${BusinessName}VO>(
|
||||
row => row.${pkColumn.javaField}
|
||||
);
|
||||
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
||||
const [modalTitle, setModalTitle] = useState('');
|
||||
<#if enableExport>
|
||||
const { updateExportParams, exportFile } = useTableExport();
|
||||
</#if>
|
||||
<#list columns as column>
|
||||
<#if column.query && column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||
const { applyDateRange: apply${column.capJavaField}DateRange } = useDateRangeQuery('${column.capJavaField}');
|
||||
</#if>
|
||||
</#list>
|
||||
|
||||
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
|
||||
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
|
||||
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
|
||||
<#if enableExport>
|
||||
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
|
||||
</#if>
|
||||
|
||||
const openAdd = () => {
|
||||
form.resetFields();
|
||||
form.setFieldsValue(default${BusinessName}Form);
|
||||
setModalTitle('添加${functionName}');
|
||||
openModal();
|
||||
};
|
||||
|
||||
const openEdit = async (row?: ${BusinessName}VO) => {
|
||||
const target = row || selectedOne;
|
||||
if (!target?.${pkColumn.javaField}) return;
|
||||
const res = await get${BusinessName}(target.${pkColumn.javaField});
|
||||
const data = <#if needDateField>toDayjsFields({ ...res.data }, [
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
||||
'${column.javaField}',
|
||||
</#if>
|
||||
</#list>
|
||||
])<#else>{ ...res.data }</#if>;
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
||||
if (typeof data.${column.javaField} === 'string') {
|
||||
data.${column.javaField} = data.${column.javaField}.split(',');
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
form.resetFields();
|
||||
form.setFieldsValue(data);
|
||||
setModalTitle('修改${functionName}');
|
||||
openModal();
|
||||
};
|
||||
|
||||
const submitForm = async (values: ${BusinessName}Form) => {
|
||||
const submitValues = <#if needDateField>formatDateTimeFields({ ...values }, [
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
||||
'${column.javaField}',
|
||||
</#if>
|
||||
</#list>
|
||||
])<#else>{ ...values }</#if>;
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
||||
if (Array.isArray(submitValues.${column.javaField})) {
|
||||
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
|
||||
}
|
||||
</#if>
|
||||
</#list>
|
||||
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
|
||||
message.success('操作成功');
|
||||
form.resetFields();
|
||||
actionRef.current?.reload();
|
||||
return true;
|
||||
};
|
||||
|
||||
const remove = async (row?: ${BusinessName}VO) => {
|
||||
await del${BusinessName}(row?.${pkColumn.javaField} || ids);
|
||||
message.success('删除成功');
|
||||
clearSelection();
|
||||
actionRef.current?.reloadAndRest?.();
|
||||
};
|
||||
|
||||
<#if enableStatus>
|
||||
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
|
||||
const previousStatus = row.${statusField};
|
||||
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
|
||||
const text = checked ? '启用' : '停用';
|
||||
try {
|
||||
await confirmAction(`确认要"${r'${text}'}"吗?`);
|
||||
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
|
||||
message.success(`${r'${text}'}成功`);
|
||||
actionRef.current?.reload();
|
||||
} catch {
|
||||
row.${statusField} = previousStatus;
|
||||
actionRef.current?.reload();
|
||||
}
|
||||
};
|
||||
|
||||
</#if>
|
||||
<#if enableSort>
|
||||
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
|
||||
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
|
||||
message.success('排序更新成功');
|
||||
actionRef.current?.reload();
|
||||
};
|
||||
|
||||
</#if>
|
||||
const columns: ProColumns<${BusinessName}VO>[] = [
|
||||
<#list columns as column>
|
||||
<#if column.list>
|
||||
<#if enableStatus && statusField == column.javaField>
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}',
|
||||
valueType: 'select',
|
||||
width: 100,
|
||||
<#if column.dictType?has_content>
|
||||
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
||||
</#if>
|
||||
render: (_, row) => (
|
||||
<Switch
|
||||
checked={row.${column.javaField} === ${statusField}ActiveValue}
|
||||
disabled={!canEdit}
|
||||
onChange={checked => handleStatusChange(row, checked)}
|
||||
/>
|
||||
)
|
||||
},
|
||||
<#elseif enableSort && sortField == column.javaField>
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}',
|
||||
search: false,
|
||||
width: 130,
|
||||
render: (_, row) => <InputNumber min={0} value={row.${column.javaField} as number} onChange={value => handleSortChange(row, value)} />
|
||||
},
|
||||
<#elseif column.htmlType == "datetime">
|
||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}', valueType: 'dateTime', search: <#if column.query && column.queryType != "BETWEEN">true<#else> false</#if>, width: 170 },
|
||||
<#elseif column.htmlType == "imageUpload">
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}Url',
|
||||
search: false,
|
||||
width: 100,
|
||||
render: (_, row) => <ImagePreview src={row.${column.javaField}Url || String(row.${column.javaField} || '')} width={50} height={50} />
|
||||
},
|
||||
<#elseif column.dictColumn>
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}',
|
||||
valueType: 'select',
|
||||
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
||||
render: (_, row) => <DictTag options={dicts.${column.dictType}} value={row.${column.javaField}} />
|
||||
},
|
||||
<#elseif column.htmlType == "switch">
|
||||
{
|
||||
title: '${column.columnLabel}',
|
||||
dataIndex: '${column.javaField}',
|
||||
valueType: 'select',
|
||||
width: 100,
|
||||
render: (_, row) => <Switch checked={row.${column.javaField} === ${column.switchActiveValue}} disabled />
|
||||
},
|
||||
<#else>
|
||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}'<#if !column.query>, search: false</#if> },
|
||||
</#if>
|
||||
</#if>
|
||||
<#if column.query && column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}Range', valueType: 'dateTimeRange', hideInTable: true },
|
||||
</#if>
|
||||
</#list>
|
||||
{
|
||||
title: '操作',
|
||||
valueType: 'option',
|
||||
width: 92,
|
||||
fixed: 'right',
|
||||
render: (_, row) => (
|
||||
<RowActions
|
||||
actions={[
|
||||
canEdit && { key: 'edit', label: '修改', icon: <EditOutlined />, onClick: () => openEdit(row) },
|
||||
canRemove && {
|
||||
key: 'delete',
|
||||
label: '删除',
|
||||
icon: <DeleteOutlined />,
|
||||
danger: true,
|
||||
confirm: `是否确认删除${functionName}编号为"${r'${row.'}${pkColumn.javaField}${r'}'}"的数据项?`,
|
||||
onClick: () => remove(row)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<PageContainer title="${functionName}">
|
||||
<ProTable<${BusinessName}VO, ${BusinessName}Query<#if needDateRange> & Record<string, unknown></#if>>
|
||||
actionRef={actionRef}
|
||||
rowKey="${pkColumn.javaField}"
|
||||
columns={columns}
|
||||
scroll={tableScroll}
|
||||
search={{ labelWidth: 90 }}
|
||||
pagination={{ defaultPageSize: 10, showSizeChanger: true }}
|
||||
rowSelection={{ selectedRowKeys: ids, onChange: handleSelectionChange }}
|
||||
request={async params => {
|
||||
<#if needDateRange>
|
||||
let query = toPageQuery(params);
|
||||
<#list columns as column>
|
||||
<#if column.query && column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||
query = apply${column.capJavaField}DateRange(query, params.${column.javaField}Range as [string, string] | undefined);
|
||||
delete query.${column.javaField}Range;
|
||||
</#if>
|
||||
</#list>
|
||||
<#else>
|
||||
const query = toPageQuery(params);
|
||||
</#if>
|
||||
<#if enableExport>
|
||||
updateExportParams(query);
|
||||
</#if>
|
||||
const res = await list${BusinessName}(query);
|
||||
return toTableData(res);
|
||||
}}
|
||||
toolbar={{ title: '${functionName}列表' }}
|
||||
toolBarRender={() => [
|
||||
canAdd && (
|
||||
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={openAdd}>
|
||||
新增
|
||||
</Button>
|
||||
),
|
||||
canEdit && (
|
||||
<Button key="edit" disabled={!selectedOne} icon={<EditOutlined />} onClick={() => openEdit()}>
|
||||
修改
|
||||
</Button>
|
||||
),
|
||||
canRemove && (
|
||||
<Popconfirm key="delete" title={`是否确认删除${functionName}编号为"${r'${ids}'}"的数据项?`} onConfirm={() => remove()}>
|
||||
<Button danger disabled={!ids.length} icon={<DeleteOutlined />}>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
)<#if enableExport>,
|
||||
canExport && (
|
||||
<Button
|
||||
key="export"
|
||||
icon={<DownloadOutlined />}
|
||||
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_${r'${Date.now()}'}.xlsx`)}
|
||||
>
|
||||
导出
|
||||
</Button>
|
||||
)</#if>
|
||||
]}
|
||||
/>
|
||||
|
||||
<ModalForm<${BusinessName}Form>
|
||||
title={modalTitle}
|
||||
open={modalOpen}
|
||||
width={560}
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={default${BusinessName}Form}
|
||||
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
|
||||
onOpenChange={open => !open && closeModal()}
|
||||
onFinish={submitForm}
|
||||
>
|
||||
<ProFormText name="${pkColumn.javaField}" hidden />
|
||||
<#list columns as column>
|
||||
<#if (column.insert || column.edit) && !column.pk>
|
||||
<#if column.htmlType == "input">
|
||||
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "textarea">
|
||||
<ProFormTextArea name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "inputNumber">
|
||||
<ProFormDigit name="${column.javaField}" label="${column.columnLabel}" min={0} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif (column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch") && column.dictType?has_content>
|
||||
<ProFormSelect name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
|
||||
<ProFormCheckbox.Group name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "switch">
|
||||
<Form.Item
|
||||
name="${column.javaField}"
|
||||
label="${column.columnLabel}"
|
||||
valuePropName="checked"
|
||||
getValueProps={value => ({ checked: value === ${column.switchActiveValue} })}
|
||||
normalize={checked => (checked ? ${column.switchActiveValue} : ${column.switchInactiveValue})}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<#elseif column.htmlType == "datetime">
|
||||
<ProFormDateTimePicker name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
<#elseif column.htmlType == "imageUpload">
|
||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||
<ImageUpload />
|
||||
</Form.Item>
|
||||
<#elseif column.htmlType == "fileUpload">
|
||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||
<FileUpload />
|
||||
</Form.Item>
|
||||
<#elseif column.htmlType == "editor">
|
||||
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||
<RichTextEditor />
|
||||
</Form.Item>
|
||||
<#else>
|
||||
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
</ModalForm>
|
||||
</PageContainer>
|
||||
);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import type { BaseEntity<#if !table.tree>, PageQuery</#if> } from '@/api/types';
|
||||
|
||||
export interface ${BusinessName}VO {
|
||||
<#list columns as column>
|
||||
<#if column.list || column.pk>
|
||||
/**
|
||||
* ${column.columnComment}
|
||||
*/
|
||||
${column.javaField}: ${column.tsType};
|
||||
<#if column.htmlType == "imageUpload">
|
||||
/**
|
||||
* ${column.columnComment}Url
|
||||
*/
|
||||
${column.javaField}Url?: string;
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
<#if table.tree>
|
||||
/**
|
||||
* 子对象
|
||||
*/
|
||||
children?: ${BusinessName}VO[];
|
||||
</#if>
|
||||
}
|
||||
|
||||
export interface ${BusinessName}Form extends BaseEntity {
|
||||
<#list columns as column>
|
||||
<#if column.insert || column.edit || column.pk>
|
||||
/**
|
||||
* ${column.columnComment}
|
||||
*/
|
||||
<#if column.htmlType == "checkbox">
|
||||
${column.javaField}?: string | string[];
|
||||
<#else>
|
||||
${column.javaField}?: ${column.tsType};
|
||||
</#if>
|
||||
</#if>
|
||||
</#list>
|
||||
}
|
||||
|
||||
export interface ${BusinessName}Query<#if !table.tree> extends PageQuery</#if> {
|
||||
<#list columns as column>
|
||||
<#if column.query>
|
||||
/**
|
||||
* ${column.columnComment}
|
||||
*/
|
||||
${column.javaField}?: ${column.tsType};
|
||||
</#if>
|
||||
</#list>
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: Record<string, unknown>;
|
||||
}
|
||||
+242
File diff suppressed because one or more lines are too long
+214
@@ -0,0 +1,214 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="renderer" content="webkit" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<title>RuoYi-Vue-Plus多租户管理系统</title>
|
||||
<!--[if lt IE 11
|
||||
]><script>
|
||||
window.location.href = '/html/ie.html';
|
||||
</script><!
|
||||
[endif]-->
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.chromeframe {
|
||||
margin: 0.2em 0;
|
||||
background: #ccc;
|
||||
color: #000;
|
||||
padding: 0.2em 0;
|
||||
}
|
||||
|
||||
#loader-wrapper {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
#loader {
|
||||
display: block;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin: -75px 0 0 -75px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #fff;
|
||||
-webkit-animation: spin 2s linear infinite;
|
||||
-ms-animation: spin 2s linear infinite;
|
||||
-moz-animation: spin 2s linear infinite;
|
||||
-o-animation: spin 2s linear infinite;
|
||||
animation: spin 2s linear infinite;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
#loader:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
right: 5px;
|
||||
bottom: 5px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #fff;
|
||||
-webkit-animation: spin 3s linear infinite;
|
||||
-moz-animation: spin 3s linear infinite;
|
||||
-o-animation: spin 3s linear infinite;
|
||||
-ms-animation: spin 3s linear infinite;
|
||||
animation: spin 3s linear infinite;
|
||||
}
|
||||
|
||||
#loader:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
border-radius: 50%;
|
||||
border: 3px solid transparent;
|
||||
border-top-color: #fff;
|
||||
-moz-animation: spin 1.5s linear infinite;
|
||||
-o-animation: spin 1.5s linear infinite;
|
||||
-ms-animation: spin 1.5s linear infinite;
|
||||
-webkit-animation: spin 1.5s linear infinite;
|
||||
animation: spin 1.5s linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
-ms-transform: rotate(360deg);
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
#loader-wrapper .loader-section {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 51%;
|
||||
height: 100%;
|
||||
background: #7171c6;
|
||||
z-index: 1000;
|
||||
-webkit-transform: translateX(0);
|
||||
-ms-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
#loader-wrapper .loader-section.section-left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#loader-wrapper .loader-section.section-right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.loaded #loader-wrapper .loader-section.section-left {
|
||||
-webkit-transform: translateX(-100%);
|
||||
-ms-transform: translateX(-100%);
|
||||
transform: translateX(-100%);
|
||||
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
|
||||
.loaded #loader-wrapper .loader-section.section-right {
|
||||
-webkit-transform: translateX(100%);
|
||||
-ms-transform: translateX(100%);
|
||||
transform: translateX(100%);
|
||||
-webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
}
|
||||
|
||||
.loaded #loader {
|
||||
opacity: 0;
|
||||
-webkit-transition: all 0.3s ease-out;
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
.loaded #loader-wrapper {
|
||||
visibility: hidden;
|
||||
-webkit-transform: translateY(-100%);
|
||||
-ms-transform: translateY(-100%);
|
||||
transform: translateY(-100%);
|
||||
-webkit-transition: all 0.3s 1s ease-out;
|
||||
transition: all 0.3s 1s ease-out;
|
||||
}
|
||||
|
||||
.no-js #loader-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.no-js h1 {
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
#loader-wrapper .load_title {
|
||||
font-family: 'Open Sans';
|
||||
color: #fff;
|
||||
font-size: 19px;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
z-index: 9999999999999;
|
||||
position: absolute;
|
||||
top: 60%;
|
||||
opacity: 1;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
#loader-wrapper .load_title span {
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<div id="loader-wrapper">
|
||||
<div id="loader"></div>
|
||||
<div class="loader-section section-left"></div>
|
||||
<div class="loader-section section-right"></div>
|
||||
<div class="load_title">正在加载系统资源,请耐心等待</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
+78
-54
@@ -1,67 +1,91 @@
|
||||
{
|
||||
"name": "plus-ui-react",
|
||||
"version": "6.0.0",
|
||||
"private": true,
|
||||
"description": "React + Ant Design version of RuoYi-Vue-Plus UI",
|
||||
"name": "ruoyi-vue-plus",
|
||||
"version": "5.2.2",
|
||||
"description": "RuoYi-Vue-Plus多租户管理系统",
|
||||
"author": "LionLi",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@10.34.5",
|
||||
"scripts": {
|
||||
"build": "pnpm build:prod",
|
||||
"build:dev": "cross-env UMI_ENV=development BABEL_POLYFILL=none max build",
|
||||
"build:prod": "cross-env UMI_ENV=production BABEL_POLYFILL=none max build",
|
||||
"dev": "cross-env UMI_ENV=development MOCK=none BABEL_POLYFILL=none max dev",
|
||||
"fmt": "oxfmt .",
|
||||
"lint": "oxlint src config vite.config.ts && cross-env UMI_ENV=development BABEL_POLYFILL=none max setup && tsc --noEmit",
|
||||
"lint:fix": "oxlint --fix src config vite.config.ts",
|
||||
"openapi": "max openapi",
|
||||
"preview": "max preview --port 8000",
|
||||
"start": "cross-env UMI_ENV=development MOCK=none BABEL_POLYFILL=none max dev"
|
||||
"dev": "vite serve --mode development",
|
||||
"build:prod": "vite build --mode production",
|
||||
"build:dev": "vite build --mode development",
|
||||
"preview": "vite preview",
|
||||
"lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src ",
|
||||
"prettier": "prettier --write ."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://gitee.com/JavaLionLi/plus-ui.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^6.3.2",
|
||||
"@ant-design/pro-components": "3.1.12-0",
|
||||
"@ant-design/x": "^2.8.0",
|
||||
"@iconify/react": "^6.0.2",
|
||||
"@tanstack/react-query": "^5.101.4",
|
||||
"@umijs/max": "^4.6.82",
|
||||
"@wangeditor-next/editor": "^5.7.16",
|
||||
"@wangeditor-next/editor-for-react": "^2.0.3",
|
||||
"ahooks": "^3.9.7",
|
||||
"antd": "^6.5.2",
|
||||
"antd-style": "^4.1.0",
|
||||
"axios": "1.18.1",
|
||||
"browser-image-compression": "^2.0.2",
|
||||
"clsx": "^2.1.1",
|
||||
"@element-plus/icons-vue": "2.3.1",
|
||||
"@highlightjs/vue-plugin": "2.1.0",
|
||||
"@vueup/vue-quill": "1.2.0",
|
||||
"@vueuse/core": "10.9.0",
|
||||
"animate.css": "4.1.1",
|
||||
"await-to-js": "3.0.0",
|
||||
"axios": "1.6.8",
|
||||
"bpmn-js": "16.4.0",
|
||||
"crypto-js": "4.2.0",
|
||||
"dayjs": "^1.11.21",
|
||||
"echarts": "^6.1.0",
|
||||
"echarts-for-react": "^3.0.6",
|
||||
"jsencrypt": "3.5.4",
|
||||
"diagram-js": "12.3.0",
|
||||
"didi": "9.0.2",
|
||||
"echarts": "5.5.0",
|
||||
"element-plus": "2.7.8",
|
||||
"file-saver": "2.0.5",
|
||||
"fuse.js": "7.0.0",
|
||||
"highlight.js": "11.9.0",
|
||||
"image-conversion": "^2.1.1",
|
||||
"js-cookie": "3.0.5",
|
||||
"jsencrypt": "3.3.2",
|
||||
"nprogress": "0.2.0",
|
||||
"react": "^19.2.8",
|
||||
"react-dom": "^19.2.8",
|
||||
"react-easy-crop": "^6.2.3",
|
||||
"react-json-view-lite": "^2.5.0",
|
||||
"react-syntax-highlighter": "^16.1.1",
|
||||
"screenfull": "^6.0.2",
|
||||
"zustand": "^5.0.14"
|
||||
"pinia": "2.1.7",
|
||||
"screenfull": "6.0.2",
|
||||
"vue": "3.4.34",
|
||||
"vue-cropper": "1.1.1",
|
||||
"vue-i18n": "9.10.2",
|
||||
"vue-router": "4.3.2",
|
||||
"vue-types": "5.1.1",
|
||||
"vxe-table": "4.5.22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify/json": "2.2.201",
|
||||
"@intlify/unplugin-vue-i18n": "3.0.1",
|
||||
"@types/crypto-js": "4.2.2",
|
||||
"@types/node": "^26.1.1",
|
||||
"@types/file-saver": "2.0.7",
|
||||
"@types/js-cookie": "3.0.6",
|
||||
"@types/node": "18.18.2",
|
||||
"@types/nprogress": "0.2.3",
|
||||
"@types/react": "^19.2.17",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@types/react-syntax-highlighter": "^15.5.13",
|
||||
"@umijs/lint": "^4.6.82",
|
||||
"@umijs/max-plugin-openapi": "^2.0.3",
|
||||
"cross-env": "^10.1.0",
|
||||
"oxfmt": "^0.60.0",
|
||||
"oxlint": "^1.75.0",
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.19.0",
|
||||
"pnpm": ">=10.0.0"
|
||||
"@typescript-eslint/eslint-plugin": "7.3.1",
|
||||
"@typescript-eslint/parser": "7.3.1",
|
||||
"@unocss/preset-attributify": "0.58.6",
|
||||
"@unocss/preset-icons": "0.58.6",
|
||||
"@unocss/preset-uno": "0.58.6",
|
||||
"@vitejs/plugin-vue": "5.0.4",
|
||||
"@vue/compiler-sfc": "3.4.23",
|
||||
"autoprefixer": "10.4.18",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-define-config": "2.1.0",
|
||||
"eslint-plugin-prettier": "5.1.3",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-node": "11.1.0",
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-vue": "9.23.0",
|
||||
"fast-glob": "3.3.2",
|
||||
"postcss": "8.4.36",
|
||||
"prettier": "3.2.5",
|
||||
"sass": "1.72.0",
|
||||
"typescript": "5.4.5",
|
||||
"unocss": "0.58.6",
|
||||
"unplugin-auto-import": "0.17.5",
|
||||
"unplugin-icons": "0.18.5",
|
||||
"unplugin-vue-components": "0.26.0",
|
||||
"unplugin-vue-setup-extend-plus": "1.0.1",
|
||||
"vite": "5.2.12",
|
||||
"vite-plugin-compression": "0.5.1",
|
||||
"vite-plugin-svg-icons": "2.0.1",
|
||||
"vitest": "1.5.0",
|
||||
"vue-eslint-parser": "9.4.2",
|
||||
"vue-tsc": "2.0.13"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
-17133
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
+20
@@ -0,0 +1,20 @@
|
||||
<template>
|
||||
<el-config-provider :locale="appStore.locale" :size="appStore.size">
|
||||
<router-view />
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import useSettingsStore from '@/store/modules/settings';
|
||||
import { handleThemeStyle } from '@/utils/theme';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
// 初始化主题样式
|
||||
handleThemeStyle(useSettingsStore().theme);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,48 @@
|
||||
// 前缀
|
||||
const animatePrefix = 'animate__animated ';
|
||||
// 开启随机动画 随机动画值
|
||||
const animateList: string[] = [
|
||||
animatePrefix + 'animate__pulse',
|
||||
animatePrefix + 'animate__rubberBand',
|
||||
animatePrefix + 'animate__bounceIn',
|
||||
animatePrefix + 'animate__bounceInLeft',
|
||||
animatePrefix + 'animate__fadeIn',
|
||||
animatePrefix + 'animate__fadeInLeft',
|
||||
animatePrefix + 'animate__fadeInDown',
|
||||
animatePrefix + 'animate__fadeInUp',
|
||||
animatePrefix + 'animate__flipInX',
|
||||
animatePrefix + 'animate__lightSpeedInLeft',
|
||||
animatePrefix + 'animate__rotateInDownLeft',
|
||||
animatePrefix + 'animate__rollIn',
|
||||
animatePrefix + 'animate__rotateInDownLeft',
|
||||
animatePrefix + 'animate__zoomIn',
|
||||
animatePrefix + 'animate__zoomInDown',
|
||||
animatePrefix + 'animate__slideInLeft',
|
||||
animatePrefix + 'animate__lightSpeedIn'
|
||||
];
|
||||
// 关闭随机动画后的默认效果
|
||||
const defaultAnimate = animatePrefix + 'animate__fadeIn';
|
||||
// 搜索隐藏显示动画
|
||||
const searchAnimate = {
|
||||
enter: '',
|
||||
leave: ''
|
||||
};
|
||||
|
||||
// 菜单搜索动画
|
||||
const menuSearchAnimate = {
|
||||
enter: animatePrefix + 'animate__fadeIn',
|
||||
leave: animatePrefix + 'animate__fadeOut'
|
||||
};
|
||||
// logo动画
|
||||
const logoAnimate = {
|
||||
enter: animatePrefix + 'animate__fadeIn',
|
||||
leave: animatePrefix + 'animate__fadeOut'
|
||||
};
|
||||
|
||||
export default {
|
||||
animateList,
|
||||
defaultAnimate,
|
||||
searchAnimate,
|
||||
menuSearchAnimate,
|
||||
logoAnimate
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
import type { R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { SnailOpenApiUser } from './types';
|
||||
|
||||
export function registerCurrentSnailUser() {
|
||||
return request<R<SnailOpenApiUser>>({
|
||||
url: '/snail-ai/user/register',
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export interface SnailOpenApiUser {
|
||||
openId: string;
|
||||
nickname?: string;
|
||||
externalId?: string;
|
||||
created?: boolean;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './agent';
|
||||
export * from './agent/types';
|
||||
+43
-22
@@ -1,41 +1,62 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { DemoForm, DemoQuery, DemoVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { DemoVO, DemoForm, DemoQuery } from '@/api/demo/demo/types';
|
||||
|
||||
export function listDemo(query?: DemoQuery) {
|
||||
return request<R<PageResult<DemoVO>>>({
|
||||
/**
|
||||
* 查询测试单列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const listDemo = (query?: DemoQuery): AxiosPromise<DemoVO[]> => {
|
||||
return request({
|
||||
url: '/demo/demo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getDemo(id: string | number) {
|
||||
return request<R<DemoVO>>({
|
||||
url: `/demo/demo/${id}`,
|
||||
/**
|
||||
* 查询测试单详细
|
||||
* @param id
|
||||
*/
|
||||
export const getDemo = (id: string | number): AxiosPromise<DemoVO> => {
|
||||
return request({
|
||||
url: '/demo/demo/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function addDemo(data: DemoForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 新增测试单
|
||||
* @param data
|
||||
*/
|
||||
export const addDemo = (data: DemoForm) => {
|
||||
return request({
|
||||
url: '/demo/demo',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateDemo(data: DemoForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 修改测试单
|
||||
* @param data
|
||||
*/
|
||||
export const updateDemo = (data: DemoForm) => {
|
||||
return request({
|
||||
url: '/demo/demo',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function delDemo(id: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/demo/demo/${id}`,
|
||||
/**
|
||||
* 删除测试单
|
||||
* @param id
|
||||
*/
|
||||
export const delDemo = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/demo/demo/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
+73
-10
@@ -1,27 +1,90 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
export interface DemoVO {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 部门id
|
||||
*/
|
||||
deptId: string | number;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
userId: string | number;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
orderNum: number;
|
||||
|
||||
/**
|
||||
* key键
|
||||
*/
|
||||
testKey: string;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface DemoForm extends BaseEntity {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 部门id
|
||||
*/
|
||||
deptId?: string | number;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
userId?: string | number;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
orderNum?: number;
|
||||
|
||||
/**
|
||||
* key键
|
||||
*/
|
||||
testKey?: string;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export interface DemoQuery extends PageQuery {
|
||||
/**
|
||||
* 部门id
|
||||
*/
|
||||
deptId?: string | number;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
userId?: string | number;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
orderNum?: number;
|
||||
|
||||
/**
|
||||
* key键
|
||||
*/
|
||||
testKey?: string;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
value?: string;
|
||||
}
|
||||
|
||||
export interface DemoVO {
|
||||
id: string | number;
|
||||
deptId: string | number;
|
||||
userId: string | number;
|
||||
orderNum: number;
|
||||
testKey: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
+43
-22
@@ -1,41 +1,62 @@
|
||||
import type { R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { TreeForm, TreeQuery, TreeVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { TreeVO, TreeForm, TreeQuery } from '@/api/demo/tree/types';
|
||||
|
||||
export function listTree(query?: TreeQuery) {
|
||||
return request<R<TreeVO[]>>({
|
||||
/**
|
||||
* 查询测试树列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
export const listTree = (query?: TreeQuery): AxiosPromise<TreeVO[]> => {
|
||||
return request({
|
||||
url: '/demo/tree/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getTree(id: string | number) {
|
||||
return request<R<TreeVO>>({
|
||||
url: `/demo/tree/${id}`,
|
||||
/**
|
||||
* 查询测试树详细
|
||||
* @param id
|
||||
*/
|
||||
export const getTree = (id: string | number): AxiosPromise<TreeVO> => {
|
||||
return request({
|
||||
url: '/demo/tree/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function addTree(data: TreeForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 新增测试树
|
||||
* @param data
|
||||
*/
|
||||
export const addTree = (data: TreeForm) => {
|
||||
return request({
|
||||
url: '/demo/tree',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateTree(data: TreeForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 修改测试树
|
||||
* @param data
|
||||
*/
|
||||
export const updateTree = (data: TreeForm) => {
|
||||
return request({
|
||||
url: '/demo/tree',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function delTree(id: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/demo/tree/${id}`,
|
||||
/**
|
||||
* 删除测试树
|
||||
* @param id
|
||||
*/
|
||||
export const delTree = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/demo/tree/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
+65
-10
@@ -1,25 +1,80 @@
|
||||
import type { BaseEntity } from '@/api/types';
|
||||
export interface TreeVO {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 父id
|
||||
*/
|
||||
parentId: string | number;
|
||||
|
||||
/**
|
||||
* 部门id
|
||||
*/
|
||||
deptId: string | number;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
userId: string | number;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
treeName: string;
|
||||
|
||||
/**
|
||||
* 子对象
|
||||
*/
|
||||
children: TreeVO[];
|
||||
}
|
||||
|
||||
export interface TreeForm extends BaseEntity {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 父id
|
||||
*/
|
||||
parentId?: string | number;
|
||||
|
||||
/**
|
||||
* 部门id
|
||||
*/
|
||||
deptId?: string | number;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
userId?: string | number;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
treeName?: string;
|
||||
}
|
||||
|
||||
export interface TreeQuery {
|
||||
/**
|
||||
* 父id
|
||||
*/
|
||||
parentId?: string | number;
|
||||
|
||||
/**
|
||||
* 部门id
|
||||
*/
|
||||
deptId?: string | number;
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
userId?: string | number;
|
||||
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
treeName?: string;
|
||||
}
|
||||
|
||||
export interface TreeVO {
|
||||
id: string | number;
|
||||
parentId: string | number;
|
||||
deptId: string | number;
|
||||
userId: string | number;
|
||||
treeName: string;
|
||||
children?: TreeVO[];
|
||||
}
|
||||
|
||||
+84
-48
@@ -1,75 +1,111 @@
|
||||
import type { UserInfo } from '@/api/system/user/types';
|
||||
import type { LoginParams, LoginResult, R, RegisterParams, VerifyCodeResult } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import { appEnv } from '@/utils/env';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { LoginData, LoginResult, VerifyCodeResult, TenantInfo } from './types';
|
||||
import { UserInfo } from '@/api/system/user/types';
|
||||
|
||||
export function login(data: LoginParams) {
|
||||
return request<R<LoginResult>>({
|
||||
// pc端固定客户端授权id
|
||||
const clientId = import.meta.env.VITE_APP_CLIENT_ID;
|
||||
|
||||
/**
|
||||
* @param data {LoginData}
|
||||
* @returns
|
||||
*/
|
||||
export function login(data: LoginData): AxiosPromise<LoginResult> {
|
||||
const params = {
|
||||
...data,
|
||||
clientId: data.clientId || clientId,
|
||||
grantType: data.grantType || 'password'
|
||||
};
|
||||
return request({
|
||||
url: '/auth/login',
|
||||
method: 'post',
|
||||
headers: {
|
||||
isToken: false,
|
||||
isEncrypt: 'true',
|
||||
isEncrypt: true,
|
||||
repeatSubmit: false
|
||||
},
|
||||
data: {
|
||||
...data,
|
||||
clientId: data.clientId || appEnv.clientId,
|
||||
grantType: data.grantType || 'password'
|
||||
}
|
||||
method: 'post',
|
||||
data: params
|
||||
});
|
||||
}
|
||||
|
||||
// 注册方法
|
||||
export function register(data: any) {
|
||||
const params = {
|
||||
...data,
|
||||
clientId: clientId,
|
||||
grantType: 'password'
|
||||
};
|
||||
return request({
|
||||
url: '/auth/register',
|
||||
headers: {
|
||||
isToken: false,
|
||||
isEncrypt: true,
|
||||
repeatSubmit: false
|
||||
},
|
||||
method: 'post',
|
||||
data: params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销
|
||||
*/
|
||||
export function logout() {
|
||||
return request<R>({
|
||||
request({
|
||||
url: '/resource/sse/close',
|
||||
method: 'get'
|
||||
});
|
||||
return request({
|
||||
url: '/auth/logout',
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
|
||||
export function register(data: RegisterParams) {
|
||||
return request<R>({
|
||||
url: '/auth/register',
|
||||
method: 'post',
|
||||
headers: {
|
||||
isToken: false,
|
||||
isEncrypt: 'true',
|
||||
repeatSubmit: false
|
||||
},
|
||||
data: {
|
||||
...data,
|
||||
clientId: appEnv.clientId,
|
||||
grantType: 'password'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function callback(data: LoginParams) {
|
||||
return request<R<LoginResult>>({
|
||||
url: '/auth/social/callback',
|
||||
method: 'post',
|
||||
data: {
|
||||
...data,
|
||||
clientId: appEnv.clientId,
|
||||
grantType: 'social'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getCodeImg() {
|
||||
return request<R<VerifyCodeResult>>({
|
||||
/**
|
||||
* 获取验证码
|
||||
*/
|
||||
export function getCodeImg(): AxiosPromise<VerifyCodeResult> {
|
||||
return request({
|
||||
url: '/auth/code',
|
||||
method: 'get',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
method: 'get',
|
||||
timeout: 20000
|
||||
});
|
||||
}
|
||||
|
||||
export function getInfo() {
|
||||
return request<R<UserInfo>>({
|
||||
/**
|
||||
* 第三方登录
|
||||
*/
|
||||
export function callback(data: LoginData): AxiosPromise<any> {
|
||||
const LoginData = {
|
||||
...data,
|
||||
clientId: clientId,
|
||||
grantType: 'social'
|
||||
};
|
||||
return request({
|
||||
url: '/auth/social/callback',
|
||||
method: 'post',
|
||||
data: LoginData
|
||||
});
|
||||
}
|
||||
|
||||
// 获取用户详细信息
|
||||
export function getInfo(): AxiosPromise<UserInfo> {
|
||||
return request({
|
||||
url: '/system/user/getInfo',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 获取租户列表
|
||||
export function getTenantList(): AxiosPromise<TenantInfo> {
|
||||
return request({
|
||||
url: '/auth/tenant/list',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
+6
-4
@@ -1,8 +1,10 @@
|
||||
import type { BackendRoute, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
export function getRouters() {
|
||||
return request<R<BackendRoute[]>>({
|
||||
// 获取路由
|
||||
export function getRouters(): AxiosPromise<RouteRecordRaw[]> {
|
||||
return request({
|
||||
url: '/system/menu/getRouters',
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
Vendored
+54
-5
@@ -1,10 +1,59 @@
|
||||
import type { R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { CacheVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { CacheVO } from './types';
|
||||
|
||||
export function getCache() {
|
||||
return request<R<CacheVO>>({
|
||||
// 查询缓存详细
|
||||
export function getCache(): AxiosPromise<CacheVO> {
|
||||
return request({
|
||||
url: '/monitor/cache',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 查询缓存名称列表
|
||||
export function listCacheName() {
|
||||
return request({
|
||||
url: '/monitor/cache/getNames',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 查询缓存键名列表
|
||||
export function listCacheKey(cacheName: string) {
|
||||
return request({
|
||||
url: '/monitor/cache/getKeys/' + cacheName,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 查询缓存内容
|
||||
export function getCacheValue(cacheName: string, cacheKey: string) {
|
||||
return request({
|
||||
url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 清理指定名称缓存
|
||||
export function clearCacheName(cacheName: string) {
|
||||
return request({
|
||||
url: '/monitor/cache/clearCacheName/' + cacheName,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 清理指定键名缓存
|
||||
export function clearCacheKey(cacheName: string, cacheKey: string) {
|
||||
return request({
|
||||
url: '/monitor/cache/clearCacheKey/' + cacheName + '/' + cacheKey,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 清理全部缓存
|
||||
export function clearCacheAll() {
|
||||
return request({
|
||||
url: '/monitor/cache/clearCacheAll',
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
Vendored
+5
-3
@@ -1,5 +1,7 @@
|
||||
export interface CacheVO {
|
||||
commandStats: Array<{ name: string; value: string | number }>;
|
||||
export interface CacheVO {
|
||||
commandStats: Array<{ name: string; value: string }>;
|
||||
|
||||
dbSize: number;
|
||||
info: Record<string, string>;
|
||||
|
||||
info: { [key: string]: string };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import request from '@/utils/request';
|
||||
import { LoginInfoQuery, LoginInfoVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
// 查询登录日志列表
|
||||
export function list(query: LoginInfoQuery): AxiosPromise<LoginInfoVO[]> {
|
||||
return request({
|
||||
url: '/monitor/logininfor/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
// 删除登录日志
|
||||
export function delLoginInfo(infoId: string | number | Array<string | number>) {
|
||||
return request({
|
||||
url: '/monitor/logininfor/' + infoId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 解锁用户登录状态
|
||||
export function unlockLoginInfo(userName: string | Array<string>) {
|
||||
return request({
|
||||
url: '/monitor/logininfor/unlock/' + userName,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 清空登录日志
|
||||
export function cleanLoginInfo() {
|
||||
return request({
|
||||
url: '/monitor/logininfor/clean',
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export interface LoginInfoVO {
|
||||
infoId: string | number;
|
||||
tenantId: string | number;
|
||||
userName: string;
|
||||
status: string;
|
||||
ipaddr: string;
|
||||
loginLocation: string;
|
||||
browser: string;
|
||||
os: string;
|
||||
msg: string;
|
||||
loginTime: string;
|
||||
}
|
||||
|
||||
export interface LoginInfoQuery extends PageQuery {
|
||||
ipaddr: string;
|
||||
userName: string;
|
||||
status: string;
|
||||
orderByColumn: string;
|
||||
isAsc: string;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { LoginInfoQuery, LoginInfoVO } from './types';
|
||||
|
||||
export function listLoginInfo(query: LoginInfoQuery) {
|
||||
return request<R<PageResult<LoginInfoVO>>>({
|
||||
url: '/monitor/loginInfo/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function list(query: LoginInfoQuery) {
|
||||
return listLoginInfo(query);
|
||||
}
|
||||
|
||||
export function delLoginInfo(infoId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/monitor/loginInfo/${infoId}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function unlockLoginInfo(userName: string | string[]) {
|
||||
return request<R>({
|
||||
url: `/monitor/loginInfo/unlock/${userName}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function cleanLoginInfo() {
|
||||
return request<R>({
|
||||
url: '/monitor/loginInfo/clean',
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import type { PageQuery } from '@/api/types';
|
||||
|
||||
export interface LoginInfoQuery extends Omit<PageQuery, 'isAsc'> {
|
||||
ipaddr?: string;
|
||||
userName?: string;
|
||||
status?: string;
|
||||
orderByColumn?: string;
|
||||
isAsc?: string;
|
||||
}
|
||||
|
||||
export interface LoginInfoVO {
|
||||
infoId: string | number;
|
||||
tenantId?: string | number;
|
||||
userName: string;
|
||||
clientKey?: string;
|
||||
deviceType?: string;
|
||||
status: string;
|
||||
ipaddr?: string;
|
||||
loginLocation?: string;
|
||||
browser?: string;
|
||||
os?: string;
|
||||
msg?: string;
|
||||
loginTime?: string;
|
||||
}
|
||||
@@ -1,36 +1,36 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { OnlineQuery, OnlineVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { OnlineQuery, OnlineVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export function listOnline(query: OnlineQuery) {
|
||||
return request<R<PageResult<OnlineVO>>>({
|
||||
// 查询在线用户列表
|
||||
export function list(query: OnlineQuery): AxiosPromise<OnlineVO[]> {
|
||||
return request({
|
||||
url: '/monitor/online/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function list(query: OnlineQuery) {
|
||||
return listOnline(query);
|
||||
}
|
||||
|
||||
// 强退用户
|
||||
export function forceLogout(tokenId: string) {
|
||||
return request<R>({
|
||||
url: `/monitor/online/${tokenId}`,
|
||||
return request({
|
||||
url: '/monitor/online/' + tokenId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 获取当前用户登录在线设备
|
||||
export function getOnline() {
|
||||
return request<R<OnlineVO[] | PageResult<OnlineVO>>>({
|
||||
return request({
|
||||
url: '/monitor/online',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 删除当前在线设备
|
||||
export function delOnline(tokenId: string) {
|
||||
return request<R>({
|
||||
url: `/monitor/online/myself/${tokenId}`,
|
||||
method: 'delete'
|
||||
return request({
|
||||
url: '/monitor/online/' + tokenId,
|
||||
method: 'post'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface OnlineQuery extends PageQuery {
|
||||
ipaddr?: string;
|
||||
userName?: string;
|
||||
ipaddr: string;
|
||||
userName: string;
|
||||
}
|
||||
|
||||
export interface OnlineVO extends BaseEntity {
|
||||
tokenId: string;
|
||||
deptName?: string;
|
||||
deptName: string;
|
||||
userName: string;
|
||||
clientKey?: string;
|
||||
deviceType?: string;
|
||||
ipaddr?: string;
|
||||
loginLocation?: string;
|
||||
browser?: string;
|
||||
os?: string;
|
||||
loginTime?: number | string;
|
||||
ipaddr: string;
|
||||
loginLocation: string;
|
||||
browser: string;
|
||||
os: string;
|
||||
loginTime: number;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { OperLogQuery, OperLogVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { OperLogQuery, OperLogVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export function listOperlog(query: OperLogQuery) {
|
||||
return request<R<PageResult<OperLogVO>>>({
|
||||
// 查询操作日志列表
|
||||
export function list(query: OperLogQuery): AxiosPromise<OperLogVO[]> {
|
||||
return request({
|
||||
url: '/monitor/operlog/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function list(query: OperLogQuery) {
|
||||
return listOperlog(query);
|
||||
}
|
||||
|
||||
// 删除操作日志
|
||||
export function delOperlog(operId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/monitor/operlog/${operId}`,
|
||||
return request({
|
||||
url: '/monitor/operlog/' + operId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 清空操作日志
|
||||
export function cleanOperlog() {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/monitor/operlog/clean',
|
||||
method: 'delete'
|
||||
});
|
||||
|
||||
@@ -1,45 +1,53 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface OperLogQuery extends Omit<PageQuery, 'isAsc'> {
|
||||
operIp?: string;
|
||||
title?: string;
|
||||
operName?: string;
|
||||
userId?: string;
|
||||
deptId?: string;
|
||||
clientKey?: string;
|
||||
deviceType?: string;
|
||||
browser?: string;
|
||||
os?: string;
|
||||
businessType?: string;
|
||||
status?: string;
|
||||
orderByColumn?: string;
|
||||
isAsc?: string;
|
||||
export interface OperLogQuery extends PageQuery {
|
||||
operIp: string;
|
||||
title: string;
|
||||
operName: string;
|
||||
businessType: string;
|
||||
status: string;
|
||||
orderByColumn: string;
|
||||
isAsc: string;
|
||||
}
|
||||
|
||||
export interface OperLogVO extends BaseEntity {
|
||||
operId: string | number;
|
||||
tenantId?: string;
|
||||
title?: string;
|
||||
businessType?: number | string;
|
||||
businessTypes?: number[];
|
||||
method?: string;
|
||||
requestMethod?: string;
|
||||
operatorType?: number;
|
||||
operName?: string;
|
||||
userId?: string | number;
|
||||
deptId?: string | number;
|
||||
deptName?: string;
|
||||
clientKey?: string;
|
||||
deviceType?: string;
|
||||
browser?: string;
|
||||
os?: string;
|
||||
operUrl?: string;
|
||||
operIp?: string;
|
||||
operLocation?: string;
|
||||
operParam?: string;
|
||||
jsonResult?: string;
|
||||
status?: number | string;
|
||||
errorMsg?: string;
|
||||
operTime?: string;
|
||||
costTime?: number;
|
||||
tenantId: string;
|
||||
title: string;
|
||||
businessType: number;
|
||||
businessTypes: number[] | undefined;
|
||||
method: string;
|
||||
requestMethod: string;
|
||||
operatorType: number;
|
||||
operName: string;
|
||||
deptName: string;
|
||||
operUrl: string;
|
||||
operIp: string;
|
||||
operLocation: string;
|
||||
operParam: string;
|
||||
jsonResult: string;
|
||||
status: number;
|
||||
errorMsg: string;
|
||||
operTime: string;
|
||||
costTime: number;
|
||||
}
|
||||
|
||||
export interface OperLogForm {
|
||||
operId: number | string | undefined;
|
||||
tenantId: string | number | undefined;
|
||||
title: string;
|
||||
businessType: number;
|
||||
businessTypes: number[] | undefined;
|
||||
method: string;
|
||||
requestMethod: string;
|
||||
operatorType: number;
|
||||
operName: string;
|
||||
deptName: string;
|
||||
operUrl: string;
|
||||
operIp: string;
|
||||
operLocation: string;
|
||||
operParam: string;
|
||||
jsonResult: string;
|
||||
status: number;
|
||||
errorMsg: string;
|
||||
operTime: string;
|
||||
costTime: number;
|
||||
}
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
import { history } from '@umijs/max';
|
||||
import { message, Modal } from 'antd';
|
||||
import axios, { type AxiosError, type AxiosRequestConfig } from 'axios';
|
||||
import { useAppStore } from '@/stores/appStore';
|
||||
import { useTagsViewStore } from '@/stores/tagsViewStore';
|
||||
import { getToken, removeToken } from '@/utils/auth';
|
||||
import { decryptBase64, decryptWithAes, encryptBase64, encryptWithAes, generateAesKey } from '@/utils/crypto';
|
||||
import { appEnv } from '@/utils/env';
|
||||
import { decrypt, encrypt } from '@/utils/jsencrypt';
|
||||
import { tansParams } from '@/utils/ruoyi';
|
||||
|
||||
const SUCCESS = 200;
|
||||
const WARN = 601;
|
||||
const SERVER_ERROR = 500;
|
||||
const encryptHeader = 'encrypt-key';
|
||||
const repeatSubmitStorageKey = 'sessionObj';
|
||||
const repeatSubmitInterval = 500;
|
||||
|
||||
export interface RequestConfig<D = unknown> extends AxiosRequestConfig<D> {
|
||||
headers?: AxiosRequestConfig<D>['headers'] & {
|
||||
isToken?: false;
|
||||
isEncrypt?: 'true' | 'false' | boolean;
|
||||
repeatSubmit?: false;
|
||||
};
|
||||
}
|
||||
|
||||
export const isRelogin = { show: false };
|
||||
|
||||
type HandledRequestError = Error & { isHandled?: boolean };
|
||||
|
||||
function createHandledError(message: string) {
|
||||
const error = new Error(message) as HandledRequestError;
|
||||
error.isHandled = true;
|
||||
return error;
|
||||
}
|
||||
|
||||
export function isHandledRequestError(error: unknown) {
|
||||
return Boolean((error as { isHandled?: boolean } | undefined)?.isHandled);
|
||||
}
|
||||
|
||||
export function globalHeaders() {
|
||||
return {
|
||||
Authorization: `Bearer ${getToken() || ''}`,
|
||||
clientid: appEnv.clientId
|
||||
};
|
||||
}
|
||||
|
||||
function showRequestError(content: string) {
|
||||
message.error({ content, key: `request-error:${content}` });
|
||||
}
|
||||
|
||||
function showReloginConfirm() {
|
||||
if (isRelogin.show) return;
|
||||
isRelogin.show = true;
|
||||
Modal.confirm({
|
||||
title: '系统提示',
|
||||
content: '登录状态已过期,您可以继续留在该页面,或者重新登录',
|
||||
okText: '重新登录',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
isRelogin.show = false;
|
||||
removeToken();
|
||||
useTagsViewStore.getState().resetTags();
|
||||
history.replace(
|
||||
`/login?redirect=${encodeURIComponent(`${window.location.pathname || '/'}${window.location.search || ''}`)}`
|
||||
);
|
||||
},
|
||||
onCancel: () => {
|
||||
isRelogin.show = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function stableDataString(data: unknown) {
|
||||
if (data instanceof FormData) return '';
|
||||
if (typeof data === 'string') return data;
|
||||
if (typeof data === 'undefined' || data === null) return '';
|
||||
if (typeof data === 'object') return JSON.stringify(data);
|
||||
return String(data);
|
||||
}
|
||||
|
||||
function getSessionSubmitRecord() {
|
||||
try {
|
||||
const text = sessionStorage.getItem(repeatSubmitStorageKey);
|
||||
return text ? (JSON.parse(text) as { url?: string; data?: string; time?: number }) : undefined;
|
||||
} catch {
|
||||
sessionStorage.removeItem(repeatSubmitStorageKey);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function setSessionSubmitRecord(record: { url?: string; data?: string; time: number }) {
|
||||
sessionStorage.setItem(repeatSubmitStorageKey, JSON.stringify(record));
|
||||
}
|
||||
|
||||
const service = axios.create({
|
||||
baseURL: appEnv.baseApi,
|
||||
timeout: 50000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
clientid: appEnv.clientId
|
||||
},
|
||||
transitional: {
|
||||
clarifyTimeoutError: true
|
||||
}
|
||||
});
|
||||
|
||||
service.interceptors.request.use(config => {
|
||||
config.headers.set('Content-Language', useAppStore.getState().appLocale);
|
||||
|
||||
const isToken = config.headers.get('isToken') === false;
|
||||
const isEncrypt = config.headers.get('isEncrypt') === 'true' || config.headers.get('isEncrypt') === true;
|
||||
const isRepeatSubmitDisabled = config.headers.get('repeatSubmit') === false;
|
||||
|
||||
if (getToken() && !isToken) {
|
||||
config.headers.set('Authorization', `Bearer ${getToken()}`);
|
||||
}
|
||||
|
||||
if (config.method === 'get' && config.params) {
|
||||
let url = `${config.url}?${tansParams(config.params)}`;
|
||||
url = url.slice(0, -1);
|
||||
config.params = {};
|
||||
config.url = url;
|
||||
}
|
||||
|
||||
if (!isRepeatSubmitDisabled && (config.method === 'post' || config.method === 'put')) {
|
||||
const requestObj = {
|
||||
url: config.url,
|
||||
data: stableDataString(config.data),
|
||||
time: Date.now()
|
||||
};
|
||||
const sessionObj = getSessionSubmitRecord();
|
||||
if (
|
||||
sessionObj &&
|
||||
sessionObj.url === requestObj.url &&
|
||||
sessionObj.data === requestObj.data &&
|
||||
requestObj.time - (sessionObj.time || 0) < repeatSubmitInterval
|
||||
) {
|
||||
return Promise.reject(new Error('数据正在处理,请勿重复提交'));
|
||||
}
|
||||
setSessionSubmitRecord(requestObj);
|
||||
}
|
||||
|
||||
if (appEnv.encryptEnabled && isEncrypt && (config.method === 'post' || config.method === 'put')) {
|
||||
const aesKey = generateAesKey();
|
||||
const encryptedKey = encrypt(encryptBase64(aesKey));
|
||||
if (encryptedKey) {
|
||||
config.headers.set(encryptHeader, encryptedKey);
|
||||
}
|
||||
const data = typeof config.data === 'object' ? JSON.stringify(config.data) : String(config.data ?? '');
|
||||
config.data = encryptWithAes(data, aesKey);
|
||||
}
|
||||
|
||||
if (config.data instanceof FormData) {
|
||||
config.headers.delete('Content-Type');
|
||||
}
|
||||
|
||||
config.headers.delete('isToken');
|
||||
config.headers.delete('isEncrypt');
|
||||
config.headers.delete('repeatSubmit');
|
||||
|
||||
return config;
|
||||
});
|
||||
|
||||
function normalizeErrorMessage(message?: string) {
|
||||
if (!message) return undefined;
|
||||
if (message === 'Network Error') return '后端接口连接异常';
|
||||
if (message.includes('timeout')) return '系统接口请求超时';
|
||||
if (message.includes('Request failed with status code')) return `系统接口${message.slice(-3)}异常`;
|
||||
return message;
|
||||
}
|
||||
|
||||
async function parseResponseErrorData(data: unknown): Promise<string | undefined> {
|
||||
if (!data) return undefined;
|
||||
if (data instanceof Blob) return parseResponseErrorData(await data.text());
|
||||
if (data instanceof ArrayBuffer) return parseResponseErrorData(new TextDecoder().decode(data));
|
||||
if (typeof data === 'string') {
|
||||
const text = data.trim();
|
||||
if (!text) return undefined;
|
||||
try {
|
||||
return parseResponseErrorData(JSON.parse(text));
|
||||
} catch {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
if (typeof data === 'object') {
|
||||
const payload = data as { msg?: string; message?: string };
|
||||
return payload.msg || payload.message;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function getErrorMessage(error: AxiosError) {
|
||||
const responseMessage = await parseResponseErrorData(error.response?.data);
|
||||
return responseMessage || normalizeErrorMessage(error.message) || '系统未知错误';
|
||||
}
|
||||
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
const keyStr = response.headers[encryptHeader];
|
||||
if (appEnv.encryptEnabled && keyStr) {
|
||||
const base64Str = decrypt(keyStr);
|
||||
if (base64Str) {
|
||||
const aesKey = decryptBase64(base64Str);
|
||||
response.data = JSON.parse(decryptWithAes(response.data, aesKey));
|
||||
}
|
||||
}
|
||||
|
||||
if (response.request.responseType === 'blob' || response.request.responseType === 'arraybuffer') {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
const code = response.data?.code || SUCCESS;
|
||||
const msg = response.data?.msg || '系统未知错误';
|
||||
|
||||
if (code === 401) {
|
||||
showReloginConfirm();
|
||||
return Promise.reject(createHandledError('无效的会话,或者会话已过期,请重新登录。'));
|
||||
}
|
||||
|
||||
if (code === SERVER_ERROR || code === WARN || code !== SUCCESS) {
|
||||
showRequestError(msg);
|
||||
return Promise.reject(createHandledError(msg));
|
||||
}
|
||||
|
||||
return response.data;
|
||||
},
|
||||
async error => {
|
||||
if (axios.isAxiosError(error) && error.response?.status === 401) {
|
||||
showReloginConfirm();
|
||||
return Promise.reject(createHandledError('无效的会话,或者会话已过期,请重新登录。'));
|
||||
}
|
||||
|
||||
const msg = axios.isAxiosError(error)
|
||||
? await getErrorMessage(error)
|
||||
: normalizeErrorMessage((error as Error | undefined)?.message) || '系统未知错误';
|
||||
showRequestError(msg);
|
||||
return Promise.reject(createHandledError(msg));
|
||||
}
|
||||
);
|
||||
|
||||
export default function request<T = unknown, D = unknown>(config: RequestConfig<D>): Promise<T> {
|
||||
return service.request<T, T, D>(config);
|
||||
}
|
||||
@@ -1,49 +1,80 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { ClientForm, ClientQuery, ClientVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { ClientVO, ClientForm, ClientQuery } from '@/api/system/client/types';
|
||||
|
||||
export function listClient(query?: ClientQuery) {
|
||||
return request<R<PageResult<ClientVO>>>({
|
||||
/**
|
||||
* 查询客户端管理列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listClient = (query?: ClientQuery): AxiosPromise<ClientVO[]> => {
|
||||
return request({
|
||||
url: '/system/client/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getClient(id: string | number) {
|
||||
return request<R<ClientVO>>({
|
||||
url: `/system/client/${id}`,
|
||||
/**
|
||||
* 查询客户端管理详细
|
||||
* @param id
|
||||
*/
|
||||
export const getClient = (id: string | number): AxiosPromise<ClientVO> => {
|
||||
return request({
|
||||
url: '/system/client/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function addClient(data: ClientForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 新增客户端管理
|
||||
* @param data
|
||||
*/
|
||||
export const addClient = (data: ClientForm) => {
|
||||
return request({
|
||||
url: '/system/client',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateClient(data: ClientForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 修改客户端管理
|
||||
* @param data
|
||||
*/
|
||||
export const updateClient = (data: ClientForm) => {
|
||||
return request({
|
||||
url: '/system/client',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function delClient(id: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/system/client/${id}`,
|
||||
/**
|
||||
* 删除客户端管理
|
||||
* @param id
|
||||
*/
|
||||
export const delClient = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/system/client/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 状态修改
|
||||
* @param clientId 客户端id
|
||||
* @param status 状态
|
||||
*/
|
||||
export function changeStatus(clientId: string, status: string) {
|
||||
return request<R>({
|
||||
const data = {
|
||||
clientId,
|
||||
status
|
||||
};
|
||||
return request({
|
||||
url: '/system/client/changeStatus',
|
||||
method: 'put',
|
||||
data: { clientId, status }
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
+112
-23
@@ -1,46 +1,135 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
export interface ClientVO {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id: string | number;
|
||||
|
||||
/**
|
||||
* 客户端id
|
||||
*/
|
||||
clientId: string;
|
||||
|
||||
/**
|
||||
* 客户端key
|
||||
*/
|
||||
clientKey: string;
|
||||
|
||||
/**
|
||||
* 客户端秘钥
|
||||
*/
|
||||
clientSecret: string;
|
||||
|
||||
/**
|
||||
* 授权类型
|
||||
*/
|
||||
grantTypeList: string[];
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
deviceType: string;
|
||||
|
||||
/**
|
||||
* token活跃超时时间
|
||||
*/
|
||||
activeTimeout: number;
|
||||
|
||||
/**
|
||||
* token固定超时
|
||||
*/
|
||||
timeout: number;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface ClientForm extends BaseEntity {
|
||||
/**
|
||||
* id
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 客户端id
|
||||
*/
|
||||
clientId?: string | number;
|
||||
|
||||
/**
|
||||
* 客户端key
|
||||
*/
|
||||
clientKey?: string;
|
||||
|
||||
/**
|
||||
* 客户端秘钥
|
||||
*/
|
||||
clientSecret?: string;
|
||||
|
||||
/**
|
||||
* 授权类型
|
||||
*/
|
||||
grantTypeList?: string[];
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
deviceType?: string;
|
||||
accessPath?: string;
|
||||
accessPathList?: string[];
|
||||
ipWhitelist?: string;
|
||||
ipWhitelistList?: string[];
|
||||
|
||||
/**
|
||||
* token活跃超时时间
|
||||
*/
|
||||
activeTimeout?: number;
|
||||
|
||||
/**
|
||||
* token固定超时
|
||||
*/
|
||||
timeout?: number;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export interface ClientQuery extends PageQuery {
|
||||
/**
|
||||
* 客户端id
|
||||
*/
|
||||
clientId?: string | number;
|
||||
|
||||
/**
|
||||
* 客户端key
|
||||
*/
|
||||
clientKey?: string;
|
||||
|
||||
/**
|
||||
* 客户端秘钥
|
||||
*/
|
||||
clientSecret?: string;
|
||||
|
||||
/**
|
||||
* 授权类型
|
||||
*/
|
||||
grantType?: string;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
deviceType?: string;
|
||||
accessPath?: string;
|
||||
ipWhitelist?: string;
|
||||
|
||||
/**
|
||||
* token活跃超时时间
|
||||
*/
|
||||
activeTimeout?: number;
|
||||
|
||||
/**
|
||||
* token固定超时
|
||||
*/
|
||||
timeout?: number;
|
||||
|
||||
/**
|
||||
* 状态(0正常 1停用)
|
||||
*/
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export interface ClientVO {
|
||||
id: string | number;
|
||||
clientId: string;
|
||||
clientKey: string;
|
||||
clientSecret: string;
|
||||
grantTypeList?: string[];
|
||||
deviceType?: string;
|
||||
accessPath?: string;
|
||||
accessPathList?: string[];
|
||||
ipWhitelist?: string;
|
||||
ipWhitelistList?: string[];
|
||||
activeTimeout?: number;
|
||||
timeout?: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
@@ -1,47 +1,53 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { ConfigForm, ConfigQuery, ConfigVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { ConfigForm, ConfigQuery, ConfigVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export function listConfig(query: ConfigQuery) {
|
||||
return request<R<PageResult<ConfigVO>>>({
|
||||
// 查询参数列表
|
||||
export function listConfig(query: ConfigQuery): AxiosPromise<ConfigVO[]> {
|
||||
return request({
|
||||
url: '/system/config/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function getConfig(configId: string | number) {
|
||||
return request<R<ConfigVO>>({
|
||||
url: `/system/config/${configId}`,
|
||||
// 查询参数详细
|
||||
export function getConfig(configId: string | number): AxiosPromise<ConfigVO> {
|
||||
return request({
|
||||
url: '/system/config/' + configId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function getConfigKey(configKey: string) {
|
||||
return request<R<string>>({
|
||||
url: `/system/config/configKey/${configKey}`,
|
||||
// 根据参数键名查询参数值
|
||||
export function getConfigKey(configKey: string): AxiosPromise<string> {
|
||||
return request({
|
||||
url: '/system/config/configKey/' + configKey,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 新增参数配置
|
||||
export function addConfig(data: ConfigForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/config',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 修改参数配置
|
||||
export function updateConfig(data: ConfigForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/config',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
export function updateConfigByKey(key: string, value: unknown) {
|
||||
return request<R>({
|
||||
// 修改参数配置
|
||||
export function updateConfigByKey(key: string, value: any) {
|
||||
return request({
|
||||
url: '/system/config/updateByKey',
|
||||
method: 'put',
|
||||
data: {
|
||||
@@ -51,20 +57,18 @@ export function updateConfigByKey(key: string, value: unknown) {
|
||||
});
|
||||
}
|
||||
|
||||
// 删除参数配置
|
||||
export function delConfig(configId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/system/config/${configId}`,
|
||||
return request({
|
||||
url: '/system/config/' + configId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function refreshConfigCache() {
|
||||
return request<R>({
|
||||
// 刷新参数缓存
|
||||
export function refreshCache() {
|
||||
return request({
|
||||
url: '/system/config/refreshCache',
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function refreshCache() {
|
||||
return refreshConfigCache();
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface ConfigForm {
|
||||
configId?: number | string;
|
||||
configName?: string;
|
||||
configKey?: string;
|
||||
configValue?: string;
|
||||
configType?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface ConfigQuery extends PageQuery {
|
||||
configName?: string;
|
||||
configKey?: string;
|
||||
configType?: string;
|
||||
}
|
||||
|
||||
export interface ConfigVO extends BaseEntity {
|
||||
configId: number | string;
|
||||
configName: string;
|
||||
configKey: string;
|
||||
configValue: string;
|
||||
configType: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface ConfigForm {
|
||||
configId: number | string | undefined;
|
||||
configName: string;
|
||||
configKey: string;
|
||||
configValue: string;
|
||||
configType: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface ConfigQuery extends PageQuery {
|
||||
configName: string;
|
||||
configKey: string;
|
||||
configType: string;
|
||||
}
|
||||
|
||||
@@ -1,55 +1,62 @@
|
||||
import type { R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { DeptForm, DeptQuery, DeptVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { DeptForm, DeptQuery, DeptVO } from './types';
|
||||
|
||||
export function listDept(query?: DeptQuery) {
|
||||
return request<R<DeptVO[]>>({
|
||||
// 查询部门列表
|
||||
export const listDept = (query?: DeptQuery) => {
|
||||
return request({
|
||||
url: '/system/dept/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function optionSelect(deptIds: Array<number | string>) {
|
||||
return request<R<DeptVO[]>>({
|
||||
url: `/system/dept/optionselect?deptIds=${deptIds}`,
|
||||
// 查询部门列表(排除节点)
|
||||
export const listDeptExcludeChild = (deptId: string | number): AxiosPromise<DeptVO[]> => {
|
||||
return request({
|
||||
url: '/system/dept/list/exclude/' + deptId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function listDeptExcludeChild(deptId: string | number) {
|
||||
return request<R<DeptVO[]>>({
|
||||
url: `/system/dept/list/exclude/${deptId}`,
|
||||
// 查询部门详细
|
||||
export const getDept = (deptId: string | number): AxiosPromise<DeptVO> => {
|
||||
return request({
|
||||
url: '/system/dept/' + deptId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getDept(deptId: string | number) {
|
||||
return request<R<DeptVO>>({
|
||||
url: `/system/dept/${deptId}`,
|
||||
// 查询部门下拉树结构
|
||||
export const treeselect = (): AxiosPromise<DeptVO[]> => {
|
||||
return request({
|
||||
url: '/system/dept/treeselect',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function addDept(data: DeptForm) {
|
||||
return request<R>({
|
||||
// 新增部门
|
||||
export const addDept = (data: DeptForm) => {
|
||||
return request({
|
||||
url: '/system/dept',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateDept(data: DeptForm) {
|
||||
return request<R>({
|
||||
// 修改部门
|
||||
export const updateDept = (data: DeptForm) => {
|
||||
return request({
|
||||
url: '/system/dept',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function delDept(deptId: number | string) {
|
||||
return request<R>({
|
||||
url: `/system/dept/${deptId}`,
|
||||
// 删除部门
|
||||
export const delDept = (deptId: number | string) => {
|
||||
return request({
|
||||
url: '/system/dept/' + deptId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
/**
|
||||
* 部门查询参数
|
||||
*/
|
||||
export interface DeptQuery extends PageQuery {
|
||||
deptName?: string;
|
||||
deptCategory?: string;
|
||||
status?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门类型
|
||||
*/
|
||||
export interface DeptVO extends BaseEntity {
|
||||
id: number | string;
|
||||
parentName: string;
|
||||
parentId: number | string;
|
||||
children: DeptVO[];
|
||||
deptId: number | string;
|
||||
deptName: string;
|
||||
deptCategory: string;
|
||||
orderNum: number;
|
||||
leader: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
status: string;
|
||||
delFlag: string;
|
||||
ancestors: string;
|
||||
menuId: string | number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门表单类型
|
||||
*/
|
||||
export interface DeptForm {
|
||||
parentName?: string;
|
||||
parentId?: number | string;
|
||||
@@ -8,43 +39,10 @@ export interface DeptForm {
|
||||
deptName?: string;
|
||||
deptCategory?: string;
|
||||
orderNum?: number;
|
||||
leader?: string | number;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
status?: string;
|
||||
delFlag?: string;
|
||||
ancestors?: string;
|
||||
}
|
||||
|
||||
export interface DeptQuery extends PageQuery {
|
||||
deptName?: string;
|
||||
deptCategory?: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export interface DeptTreeVO extends BaseEntity {
|
||||
id: number | string;
|
||||
label: string;
|
||||
parentId: number | string;
|
||||
weight: number;
|
||||
children?: DeptTreeVO[];
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export interface DeptVO extends BaseEntity {
|
||||
id?: number | string;
|
||||
parentName?: string;
|
||||
parentId?: number | string;
|
||||
children?: DeptVO[];
|
||||
deptId: number | string;
|
||||
deptName: string;
|
||||
deptCategory?: string;
|
||||
orderNum?: number;
|
||||
leader?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
status?: string;
|
||||
delFlag?: string;
|
||||
ancestors?: string;
|
||||
menuId?: string | number;
|
||||
}
|
||||
|
||||
@@ -1,48 +1,53 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { DictData, DictDataForm, DictDataQuery } from './types';
|
||||
|
||||
export function getDicts(dictType: string) {
|
||||
return request<R<DictData[]>>({
|
||||
url: `/system/dict/data/type/${dictType}`,
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { DictDataForm, DictDataQuery, DictDataVO } from './types';
|
||||
// 根据字典类型查询字典数据信息
|
||||
export function getDicts(dictType: string): AxiosPromise<DictDataVO[]> {
|
||||
return request({
|
||||
url: '/system/dict/data/type/' + dictType,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function listData(query: DictDataQuery) {
|
||||
return request<R<PageResult<DictData>>>({
|
||||
// 查询字典数据列表
|
||||
export function listData(query: DictDataQuery): AxiosPromise<DictDataVO[]> {
|
||||
return request({
|
||||
url: '/system/dict/data/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function getData(dictCode: string | number) {
|
||||
return request<R<DictData>>({
|
||||
url: `/system/dict/data/${dictCode}`,
|
||||
// 查询字典数据详细
|
||||
export function getData(dictCode: string | number): AxiosPromise<DictDataVO> {
|
||||
return request({
|
||||
url: '/system/dict/data/' + dictCode,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 新增字典数据
|
||||
export function addData(data: DictDataForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/dict/data',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 修改字典数据
|
||||
export function updateData(data: DictDataForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/dict/data',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除字典数据
|
||||
export function delData(dictCode: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/system/dict/data/${dictCode}`,
|
||||
return request({
|
||||
url: '/system/dict/data/' + dictCode,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,32 +1,26 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface DictData extends BaseEntity {
|
||||
dictCode: string | number;
|
||||
dictSort: number;
|
||||
dictLabel: string;
|
||||
dictValue: string;
|
||||
export interface DictDataQuery extends PageQuery {
|
||||
dictName: string;
|
||||
dictType: string;
|
||||
cssClass?: string;
|
||||
listClass?: string;
|
||||
isDefault?: string;
|
||||
status: string;
|
||||
dictLabel: string;
|
||||
}
|
||||
|
||||
export type DictDataVO = DictData;
|
||||
export interface DictDataVO extends BaseEntity {
|
||||
dictCode: string;
|
||||
dictLabel: string;
|
||||
dictValue: string;
|
||||
cssClass: string;
|
||||
listClass: ElTagType;
|
||||
dictSort: number;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface DictDataForm {
|
||||
dictType?: string;
|
||||
dictCode?: string | number;
|
||||
dictLabel?: string;
|
||||
dictValue?: string;
|
||||
cssClass?: string;
|
||||
listClass?: string;
|
||||
dictSort?: number;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface DictDataQuery extends PageQuery {
|
||||
dictName?: string;
|
||||
dictType?: string;
|
||||
dictLabel?: string;
|
||||
dictCode: string | undefined;
|
||||
dictLabel: string;
|
||||
dictValue: string;
|
||||
cssClass: string;
|
||||
listClass: ElTagType;
|
||||
dictSort: number;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
@@ -1,54 +1,61 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { DictTypeForm, DictTypeQuery, DictTypeVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { DictTypeForm, DictTypeVO, DictTypeQuery } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export function listType(query: DictTypeQuery) {
|
||||
return request<R<PageResult<DictTypeVO>>>({
|
||||
// 查询字典类型列表
|
||||
export function listType(query: DictTypeQuery): AxiosPromise<DictTypeVO[]> {
|
||||
return request({
|
||||
url: '/system/dict/type/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function getType(dictId: number | string) {
|
||||
return request<R<DictTypeVO>>({
|
||||
url: `/system/dict/type/${dictId}`,
|
||||
// 查询字典类型详细
|
||||
export function getType(dictId: number | string): AxiosPromise<DictTypeVO> {
|
||||
return request({
|
||||
url: '/system/dict/type/' + dictId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 新增字典类型
|
||||
export function addType(data: DictTypeForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/dict/type',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 修改字典类型
|
||||
export function updateType(data: DictTypeForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/dict/type',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除字典类型
|
||||
export function delType(dictId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/system/dict/type/${dictId}`,
|
||||
return request({
|
||||
url: '/system/dict/type/' + dictId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 刷新字典缓存
|
||||
export function refreshCache() {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/dict/type/refreshCache',
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function optionselect() {
|
||||
return request<R<DictTypeVO[]>>({
|
||||
// 获取字典选择框列表
|
||||
export function optionselect(): AxiosPromise<DictTypeVO[]> {
|
||||
return request({
|
||||
url: '/system/dict/type/optionselect',
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface DictTypeForm {
|
||||
dictId?: number | string;
|
||||
dictName?: string;
|
||||
dictType?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface DictTypeQuery extends PageQuery {
|
||||
dictName?: string;
|
||||
dictType?: string;
|
||||
}
|
||||
|
||||
export interface DictTypeVO extends BaseEntity {
|
||||
dictId: number | string;
|
||||
dictName: string;
|
||||
dictType: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface DictTypeForm {
|
||||
dictId: number | string | undefined;
|
||||
dictName: string;
|
||||
dictType: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface DictTypeQuery extends PageQuery {
|
||||
dictName: string;
|
||||
dictType: string;
|
||||
}
|
||||
|
||||
@@ -1,63 +1,70 @@
|
||||
import type { RoleMenuTree } from '@/api/system/role/types';
|
||||
import type { R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { MenuForm, MenuQuery, MenuTreeOption, MenuVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { MenuQuery, MenuVO, MenuForm, MenuTreeOption, RoleMenuTree } from './types';
|
||||
|
||||
export function listMenu(query?: MenuQuery) {
|
||||
return request<R<MenuVO[]>>({
|
||||
// 查询菜单列表
|
||||
export const listMenu = (query?: MenuQuery): AxiosPromise<MenuVO[]> => {
|
||||
return request({
|
||||
url: '/system/menu/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getMenu(menuId: string | number) {
|
||||
return request<R<MenuVO>>({
|
||||
url: `/system/menu/${menuId}`,
|
||||
// 查询菜单详细
|
||||
export const getMenu = (menuId: string | number): AxiosPromise<MenuVO> => {
|
||||
return request({
|
||||
url: '/system/menu/' + menuId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function treeselect() {
|
||||
return request<R<MenuTreeOption[]>>({
|
||||
// 查询菜单下拉树结构
|
||||
export const treeselect = (): AxiosPromise<MenuTreeOption[]> => {
|
||||
return request({
|
||||
url: '/system/menu/treeselect',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function roleMenuTreeselect(roleId: string | number) {
|
||||
return request<R<RoleMenuTree>>({
|
||||
url: `/system/menu/roleMenuTreeselect/${roleId}`,
|
||||
// 根据角色ID查询菜单下拉树结构
|
||||
export const roleMenuTreeselect = (roleId: string | number): AxiosPromise<RoleMenuTree> => {
|
||||
return request({
|
||||
url: '/system/menu/roleMenuTreeselect/' + roleId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function addMenu(data: MenuForm) {
|
||||
return request<R>({
|
||||
// 根据角色ID查询菜单下拉树结构
|
||||
export const tenantPackageMenuTreeselect = (packageId: string | number): AxiosPromise<RoleMenuTree> => {
|
||||
return request({
|
||||
url: '/system/menu/tenantPackageMenuTreeselect/' + packageId,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
// 新增菜单
|
||||
export const addMenu = (data: MenuForm) => {
|
||||
return request({
|
||||
url: '/system/menu',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateMenu(data: MenuForm) {
|
||||
return request<R>({
|
||||
// 修改菜单
|
||||
export const updateMenu = (data: MenuForm) => {
|
||||
return request({
|
||||
url: '/system/menu',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function delMenu(menuId: string | number) {
|
||||
return request<R>({
|
||||
url: `/system/menu/${menuId}`,
|
||||
// 删除菜单
|
||||
export const delMenu = (menuId: string | number) => {
|
||||
return request({
|
||||
url: '/system/menu/' + menuId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function cascadeDelMenu(menuIds: Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/system/menu/cascade/${menuIds}`,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,51 +1,57 @@
|
||||
import type { BaseEntity } from '@/api/types';
|
||||
import { MenuTypeEnum } from '@/enums/MenuTypeEnum';
|
||||
|
||||
export interface MenuForm {
|
||||
parentName?: string;
|
||||
parentId?: string | number;
|
||||
children?: MenuForm[];
|
||||
menuId?: string | number;
|
||||
menuName?: string;
|
||||
orderNum?: number;
|
||||
path?: string;
|
||||
component?: string;
|
||||
queryParam?: string;
|
||||
isFrame?: string;
|
||||
isCache?: string;
|
||||
menuType?: 'M' | 'C' | 'F' | string;
|
||||
visible?: string;
|
||||
status?: string;
|
||||
icon?: string | null;
|
||||
activeMenu?: string;
|
||||
ext?: string;
|
||||
remark?: string;
|
||||
query?: string;
|
||||
perms?: string;
|
||||
/**
|
||||
* 菜单树形结构类型
|
||||
*/
|
||||
export interface MenuTreeOption {
|
||||
id: string | number;
|
||||
label: string;
|
||||
parentId: string | number;
|
||||
weight: number;
|
||||
children?: MenuTreeOption[];
|
||||
}
|
||||
|
||||
export interface RoleMenuTree {
|
||||
menus: MenuTreeOption[];
|
||||
checkedKeys: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单查询参数类型
|
||||
*/
|
||||
export interface MenuQuery {
|
||||
keywords?: string;
|
||||
menuName?: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export interface MenuTreeOption {
|
||||
id: string | number;
|
||||
label: string;
|
||||
/**
|
||||
* 菜单视图对象类型
|
||||
*/
|
||||
export interface MenuVO extends BaseEntity {
|
||||
parentName: string;
|
||||
parentId: string | number;
|
||||
weight: number;
|
||||
menuType?: 'M' | 'C' | 'F' | string;
|
||||
visible?: string;
|
||||
status?: string;
|
||||
disabled?: boolean;
|
||||
children?: MenuTreeOption[];
|
||||
children: MenuVO[];
|
||||
menuId: string | number;
|
||||
menuName: string;
|
||||
orderNum: number;
|
||||
path: string;
|
||||
component: string;
|
||||
queryParam: string;
|
||||
isFrame: string;
|
||||
isCache: string;
|
||||
menuType: MenuTypeEnum;
|
||||
visible: string;
|
||||
status: string;
|
||||
icon: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface MenuVO extends BaseEntity {
|
||||
export interface MenuForm {
|
||||
parentName?: string;
|
||||
parentId: string | number;
|
||||
children?: MenuVO[];
|
||||
menuId: string | number;
|
||||
parentId?: string | number;
|
||||
children?: MenuForm[];
|
||||
menuId?: string | number;
|
||||
menuName: string;
|
||||
orderNum: number;
|
||||
path: string;
|
||||
@@ -53,11 +59,11 @@ export interface MenuVO extends BaseEntity {
|
||||
queryParam?: string;
|
||||
isFrame?: string;
|
||||
isCache?: string;
|
||||
menuType: 'M' | 'C' | 'F' | string;
|
||||
menuType?: MenuTypeEnum;
|
||||
visible?: string;
|
||||
status?: string;
|
||||
icon?: string | null;
|
||||
activeMenu?: string;
|
||||
ext?: string;
|
||||
icon?: string;
|
||||
remark?: string;
|
||||
query?: string;
|
||||
perms?: string;
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import type { R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { MessageBoxVO } from './types';
|
||||
|
||||
export function getMessageBox() {
|
||||
return request<R<MessageBoxVO>>({
|
||||
url: '/resource/message/box',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import type { BaseEntity } from '@/api/types';
|
||||
|
||||
export interface MessageVO extends BaseEntity {
|
||||
messageId: number | string;
|
||||
category: string;
|
||||
type: string;
|
||||
source: string;
|
||||
title: string;
|
||||
message: string;
|
||||
content?: string;
|
||||
data?: Record<string, unknown> | null;
|
||||
path?: string;
|
||||
}
|
||||
|
||||
export interface MessageBoxVO {
|
||||
systemList: MessageVO[];
|
||||
noticeList: MessageVO[];
|
||||
workflowList: MessageVO[];
|
||||
}
|
||||
@@ -1,41 +1,45 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { NoticeForm, NoticeQuery, NoticeVO } from './types';
|
||||
|
||||
export function listNotice(query: NoticeQuery) {
|
||||
return request<R<PageResult<NoticeVO>>>({
|
||||
import request from '@/utils/request';
|
||||
import { NoticeForm, NoticeQuery, NoticeVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
// 查询公告列表
|
||||
export function listNotice(query: NoticeQuery): AxiosPromise<NoticeVO[]> {
|
||||
return request({
|
||||
url: '/system/notice/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function getNotice(noticeId: string | number) {
|
||||
return request<R<NoticeVO>>({
|
||||
url: `/system/notice/${noticeId}`,
|
||||
// 查询公告详细
|
||||
export function getNotice(noticeId: string | number): AxiosPromise<NoticeVO> {
|
||||
return request({
|
||||
url: '/system/notice/' + noticeId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 新增公告
|
||||
export function addNotice(data: NoticeForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/notice',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 修改公告
|
||||
export function updateNotice(data: NoticeForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/notice',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除公告
|
||||
export function delNotice(noticeId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/system/notice/${noticeId}`,
|
||||
return request({
|
||||
url: '/system/notice/' + noticeId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface NoticeForm {
|
||||
noticeId?: number | string;
|
||||
noticeTitle?: string;
|
||||
noticeType?: string;
|
||||
noticeContent?: string;
|
||||
status?: string;
|
||||
remark?: string;
|
||||
createByName?: string;
|
||||
}
|
||||
|
||||
export interface NoticeQuery extends PageQuery {
|
||||
noticeTitle?: string;
|
||||
createByName?: string;
|
||||
status?: string;
|
||||
noticeType?: string;
|
||||
}
|
||||
|
||||
export interface NoticeVO extends BaseEntity {
|
||||
noticeId: number | string;
|
||||
noticeId: number;
|
||||
noticeTitle: string;
|
||||
noticeType: string;
|
||||
noticeContent: string;
|
||||
status: string;
|
||||
createByName?: string;
|
||||
remark: string;
|
||||
createByName: string;
|
||||
}
|
||||
|
||||
export interface NoticeQuery extends PageQuery {
|
||||
noticeTitle: string;
|
||||
createByName: string;
|
||||
status: string;
|
||||
noticeType: string;
|
||||
}
|
||||
|
||||
export interface NoticeForm {
|
||||
noticeId: number | string | undefined;
|
||||
noticeTitle: string;
|
||||
noticeType: string;
|
||||
noticeContent: string;
|
||||
status: string;
|
||||
remark: string;
|
||||
createByName: string;
|
||||
}
|
||||
|
||||
+13
-30
@@ -1,45 +1,28 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { OssQuery, OssUploadResult, OssVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { OssQuery, OssVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export function listOss(query: OssQuery) {
|
||||
return request<R<PageResult<OssVO>>>({
|
||||
// 查询OSS对象存储列表
|
||||
export function listOss(query: OssQuery): AxiosPromise<OssVO[]> {
|
||||
return request({
|
||||
url: '/resource/oss/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function listOssByIds(ossId: string | number) {
|
||||
return request<R<OssVO[]>>({
|
||||
url: `/resource/oss/listByIds/${ossId}`,
|
||||
// 查询OSS对象基于id串
|
||||
export function listByIds(ossId: string | number): AxiosPromise<OssVO[]> {
|
||||
return request({
|
||||
url: '/resource/oss/listByIds/' + ossId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function listByIds(ossId: string | number) {
|
||||
return listOssByIds(ossId);
|
||||
}
|
||||
|
||||
export function uploadOss(data: FormData) {
|
||||
return request<R<OssUploadResult>>({
|
||||
url: '/resource/oss/upload',
|
||||
method: 'post',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除OSS对象存储
|
||||
export function delOss(ossId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/resource/oss/${ossId}`,
|
||||
return request({
|
||||
url: '/resource/oss/' + ossId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function downloadOss(ossId: string | number) {
|
||||
return request<Blob>({
|
||||
url: `/resource/oss/download/${ossId}`,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
|
||||
+15
-20
@@ -1,27 +1,22 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface OssQuery extends Omit<PageQuery, 'isAsc'> {
|
||||
fileName?: string;
|
||||
originalName?: string;
|
||||
fileSuffix?: string;
|
||||
createTime?: string;
|
||||
service?: string;
|
||||
orderByColumn?: string;
|
||||
isAsc?: string;
|
||||
}
|
||||
|
||||
export interface OssUploadResult {
|
||||
url?: string;
|
||||
fileName?: string;
|
||||
ossId?: string | number;
|
||||
}
|
||||
|
||||
export interface OssVO extends BaseEntity {
|
||||
ossId: string | number;
|
||||
fileName: string;
|
||||
originalName: string;
|
||||
fileSuffix: string;
|
||||
url: string;
|
||||
createByName?: string;
|
||||
service?: string;
|
||||
createByName: string;
|
||||
service: string;
|
||||
}
|
||||
|
||||
export interface OssQuery extends PageQuery {
|
||||
fileName: string;
|
||||
originalName: string;
|
||||
fileSuffix: string;
|
||||
createTime: string;
|
||||
service: string;
|
||||
orderByColumn: string;
|
||||
isAsc: string;
|
||||
}
|
||||
export interface OssForm {
|
||||
file: undefined | string;
|
||||
}
|
||||
|
||||
@@ -1,49 +1,60 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { OssConfigForm, OssConfigQuery, OssConfigVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { OssConfigForm, OssConfigQuery, OssConfigVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export function listOssConfig(query: OssConfigQuery) {
|
||||
return request<R<PageResult<OssConfigVO>>>({
|
||||
// 查询对象存储配置列表
|
||||
export function listOssConfig(query: OssConfigQuery): AxiosPromise<OssConfigVO[]> {
|
||||
return request({
|
||||
url: '/resource/oss/config/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function getOssConfig(ossConfigId: string | number) {
|
||||
return request<R<OssConfigVO>>({
|
||||
url: `/resource/oss/config/${ossConfigId}`,
|
||||
// 查询对象存储配置详细
|
||||
export function getOssConfig(ossConfigId: string | number): AxiosPromise<OssConfigVO> {
|
||||
return request({
|
||||
url: '/resource/oss/config/' + ossConfigId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 新增对象存储配置
|
||||
export function addOssConfig(data: OssConfigForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/resource/oss/config',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 修改对象存储配置
|
||||
export function updateOssConfig(data: OssConfigForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/resource/oss/config',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除对象存储配置
|
||||
export function delOssConfig(ossConfigId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/resource/oss/config/${ossConfigId}`,
|
||||
return request({
|
||||
url: '/resource/oss/config/' + ossConfigId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 对象存储状态修改
|
||||
export function changeOssConfigStatus(ossConfigId: string | number, status: string, configKey: string) {
|
||||
return request<R>({
|
||||
const data = {
|
||||
ossConfigId,
|
||||
status,
|
||||
configKey
|
||||
};
|
||||
return request({
|
||||
url: '/resource/oss/config/changeStatus',
|
||||
method: 'put',
|
||||
data: { ossConfigId, status, configKey }
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,39 +1,38 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface OssConfigForm {
|
||||
ossConfigId?: string | number;
|
||||
configKey?: string;
|
||||
accessKey?: string;
|
||||
secretKey?: string;
|
||||
bucketName?: string;
|
||||
prefix?: string;
|
||||
endpoint?: string;
|
||||
domainUrl?: string;
|
||||
isHttps?: string;
|
||||
accessPolicy?: string;
|
||||
region?: string;
|
||||
status?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface OssConfigQuery extends PageQuery {
|
||||
configKey?: string;
|
||||
bucketName?: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export interface OssConfigVO extends BaseEntity {
|
||||
ossConfigId: number | string;
|
||||
configKey: string;
|
||||
accessKey: string;
|
||||
secretKey: string;
|
||||
bucketName: string;
|
||||
prefix?: string;
|
||||
prefix: string;
|
||||
endpoint: string;
|
||||
domainUrl?: string;
|
||||
domain: string;
|
||||
isHttps: string;
|
||||
region?: string;
|
||||
region: string;
|
||||
status: string;
|
||||
ext1?: string;
|
||||
ext1: string;
|
||||
remark: string;
|
||||
accessPolicy: string;
|
||||
}
|
||||
|
||||
export interface OssConfigQuery extends PageQuery {
|
||||
configKey: string;
|
||||
bucketName: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface OssConfigForm {
|
||||
ossConfigId: string | number | undefined;
|
||||
configKey: string;
|
||||
accessKey: string;
|
||||
secretKey: string;
|
||||
bucketName: string;
|
||||
prefix: string;
|
||||
endpoint: string;
|
||||
domain: string;
|
||||
isHttps: string;
|
||||
accessPolicy: string;
|
||||
region: string;
|
||||
status: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
@@ -1,64 +1,58 @@
|
||||
import type { DeptTreeVO } from '@/api/system/dept/types';
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { PostForm, PostQuery, PostVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { PostForm, PostQuery, PostVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export function listPost(query: PostQuery) {
|
||||
return request<R<PageResult<PostVO>>>({
|
||||
// 查询岗位列表
|
||||
export function listPost(query: PostQuery): AxiosPromise<PostVO[]> {
|
||||
return request({
|
||||
url: '/system/post/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function getPost(postId: string | number) {
|
||||
return request<R<PostVO>>({
|
||||
url: `/system/post/${postId}`,
|
||||
// 查询岗位详细
|
||||
export function getPost(postId: string | number): AxiosPromise<PostVO> {
|
||||
return request({
|
||||
url: '/system/post/' + postId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function optionSelect(deptId?: number | string, postIds?: Array<number | string>) {
|
||||
return request<R<PostVO[]>>({
|
||||
// 获取岗位选择框列表
|
||||
export function optionselect(deptId?: number | string, postIds?: (number | string)[]): AxiosPromise<PostVO[]> {
|
||||
return request({
|
||||
url: '/system/post/optionselect',
|
||||
method: 'get',
|
||||
params: {
|
||||
postIds,
|
||||
deptId
|
||||
postIds: postIds,
|
||||
deptId: deptId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 新增岗位
|
||||
export function addPost(data: PostForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/post',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 修改岗位
|
||||
export function updatePost(data: PostForm) {
|
||||
return request<R>({
|
||||
return request({
|
||||
url: '/system/post',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
export function delPost(postId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/system/post/${postId}`,
|
||||
// 删除岗位
|
||||
export function delPost(postId: string | number | (string | number)[]) {
|
||||
return request({
|
||||
url: '/system/post/' + postId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function postDeptTreeSelect() {
|
||||
return request<R<DeptTreeVO[]>>({
|
||||
url: '/system/post/deptTree',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function deptTreeSelect() {
|
||||
return postDeptTreeSelect();
|
||||
}
|
||||
|
||||
@@ -1,25 +1,3 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface PostForm {
|
||||
postId?: number | string;
|
||||
deptId?: number | string;
|
||||
postCode?: string;
|
||||
postName?: string;
|
||||
postCategory?: string;
|
||||
postSort?: number;
|
||||
status?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface PostQuery extends PageQuery {
|
||||
deptId?: number | string;
|
||||
belongDeptId?: number | string;
|
||||
postCode?: string;
|
||||
postName?: string;
|
||||
postCategory?: string;
|
||||
status?: string;
|
||||
}
|
||||
|
||||
export interface PostVO extends BaseEntity {
|
||||
postId: number | string;
|
||||
deptId: number | string;
|
||||
@@ -29,4 +7,25 @@ export interface PostVO extends BaseEntity {
|
||||
deptName: string;
|
||||
postSort: number;
|
||||
status: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface PostForm {
|
||||
postId: number | string | undefined;
|
||||
deptId: number | string | undefined;
|
||||
postCode: string;
|
||||
postName: string;
|
||||
postCategory: string;
|
||||
postSort: number;
|
||||
status: string;
|
||||
remark: string;
|
||||
}
|
||||
|
||||
export interface PostQuery extends PageQuery {
|
||||
deptId: number | string;
|
||||
belongDeptId: number | string;
|
||||
postCode: string;
|
||||
postName: string;
|
||||
postCategory: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
+105
-60
@@ -1,115 +1,160 @@
|
||||
import type { UserQuery, UserVO } from '@/api/system/user/types';
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { RoleDeptTree, RoleForm, RoleQuery, RoleVO } from './types';
|
||||
import { UserVO } from '@/api/system/user/types';
|
||||
import { UserQuery } from '@/api/system/user/types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { RoleQuery, RoleVO, RoleDeptTree } from './types';
|
||||
import request from '@/utils/request';
|
||||
|
||||
export function listRole(query: RoleQuery) {
|
||||
return request<R<PageResult<RoleVO>>>({
|
||||
export const listRole = (query: RoleQuery): AxiosPromise<RoleVO[]> => {
|
||||
return request({
|
||||
url: '/system/role/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function optionSelect(roleIds: Array<number | string>) {
|
||||
return request<R<RoleVO[]>>({
|
||||
url: `/system/role/optionselect?roleIds=${roleIds}`,
|
||||
/**
|
||||
* 通过roleIds查询角色
|
||||
* @param roleIds
|
||||
*/
|
||||
export const optionSelect = (roleIds: (number | string)[]): AxiosPromise<RoleVO[]> => {
|
||||
return request({
|
||||
url: '/system/role/optionselect?roleIds=' + roleIds,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getRole(roleId: string | number) {
|
||||
return request<R<RoleVO>>({
|
||||
url: `/system/role/${roleId}`,
|
||||
/**
|
||||
* 查询角色详细
|
||||
*/
|
||||
export const getRole = (roleId: string | number): AxiosPromise<RoleVO> => {
|
||||
return request({
|
||||
url: '/system/role/' + roleId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function addRole(data: RoleForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 新增角色
|
||||
*/
|
||||
export const addRole = (data: any) => {
|
||||
return request({
|
||||
url: '/system/role',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateRole(data: RoleForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 修改角色
|
||||
* @param data
|
||||
*/
|
||||
export const updateRole = (data: any) => {
|
||||
return request({
|
||||
url: '/system/role',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateRolePermission(data: RoleForm) {
|
||||
return request<R>({
|
||||
url: '/system/role/permission',
|
||||
/**
|
||||
* 角色数据权限
|
||||
*/
|
||||
export const dataScope = (data: any) => {
|
||||
return request({
|
||||
url: '/system/role/dataScope',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function changeRoleStatus(roleId: string | number, status: string) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 角色状态修改
|
||||
*/
|
||||
export const changeRoleStatus = (roleId: string | number, status: string) => {
|
||||
const data = {
|
||||
roleId,
|
||||
status
|
||||
};
|
||||
return request({
|
||||
url: '/system/role/changeStatus',
|
||||
method: 'put',
|
||||
data: {
|
||||
roleId,
|
||||
status
|
||||
}
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function delRole(roleId: Array<string | number> | string | number) {
|
||||
return request<R>({
|
||||
url: `/system/role/${roleId}`,
|
||||
/**
|
||||
* 删除角色
|
||||
*/
|
||||
export const delRole = (roleId: Array<string | number> | string | number) => {
|
||||
return request({
|
||||
url: '/system/role/' + roleId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function allocatedUserList(query: UserQuery) {
|
||||
return request<R<PageResult<UserVO>>>({
|
||||
/**
|
||||
* 查询角色已授权用户列表
|
||||
*/
|
||||
export const allocatedUserList = (query: UserQuery): AxiosPromise<UserVO[]> => {
|
||||
return request({
|
||||
url: '/system/role/authUser/allocatedList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function unallocatedUserList(query: UserQuery) {
|
||||
return request<R<PageResult<UserVO>>>({
|
||||
/**
|
||||
* 查询角色未授权用户列表
|
||||
*/
|
||||
export const unallocatedUserList = (query: UserQuery): AxiosPromise<UserVO[]> => {
|
||||
return request({
|
||||
url: '/system/role/authUser/unallocatedList',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function authUserCancel(data: { roleId: string | number; userId: string | number }) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 取消用户授权角色
|
||||
*/
|
||||
export const authUserCancel = (data: any) => {
|
||||
return request({
|
||||
url: '/system/role/authUser/cancel',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function authUserCancelAll(data: { roleId: string | number; userIds: string }) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 批量取消用户授权角色
|
||||
*/
|
||||
export const authUserCancelAll = (data: any) => {
|
||||
return request({
|
||||
url: '/system/role/authUser/cancelAll',
|
||||
method: 'put',
|
||||
params: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function authUserSelectAll(data: { roleId: string | number; userIds: string }) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 授权用户选择
|
||||
*/
|
||||
export const authUserSelectAll = (data: any) => {
|
||||
return request({
|
||||
url: '/system/role/authUser/selectAll',
|
||||
method: 'put',
|
||||
params: data
|
||||
});
|
||||
}
|
||||
|
||||
export function deptTreeSelect(roleId: string | number) {
|
||||
return request<R<RoleDeptTree>>({
|
||||
url: `/system/role/deptTree/${roleId}`,
|
||||
};
|
||||
// 根据角色ID查询部门树结构
|
||||
export const deptTreeSelect = (roleId: string | number): AxiosPromise<RoleDeptTree> => {
|
||||
return request({
|
||||
url: '/system/role/deptTree/' + roleId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
optionSelect,
|
||||
listRole
|
||||
};
|
||||
|
||||
@@ -1,35 +1,17 @@
|
||||
import type { DeptTreeVO } from '@/api/system/dept/types';
|
||||
import type { MenuTreeOption } from '@/api/system/menu/types';
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
/**
|
||||
* 菜单树形结构类型
|
||||
*/
|
||||
export interface DeptTreeOption {
|
||||
id: string;
|
||||
label: string;
|
||||
parentId: string;
|
||||
weight: number;
|
||||
children?: DeptTreeOption[];
|
||||
}
|
||||
|
||||
export interface RoleDeptTree {
|
||||
checkedKeys: Array<string | number>;
|
||||
depts: DeptTreeVO[];
|
||||
}
|
||||
|
||||
export interface RoleForm {
|
||||
roleId?: string | number;
|
||||
roleName?: string;
|
||||
roleKey?: string;
|
||||
roleSort?: number;
|
||||
status?: string;
|
||||
menuCheckStrictly?: boolean;
|
||||
deptCheckStrictly?: boolean;
|
||||
remark?: string;
|
||||
dataScope?: string;
|
||||
menuIds?: Array<string | number>;
|
||||
deptIds?: Array<string | number>;
|
||||
}
|
||||
|
||||
export interface RoleMenuTree {
|
||||
menus: MenuTreeOption[];
|
||||
checkedKeys: Array<string | number>;
|
||||
}
|
||||
|
||||
export interface RoleQuery extends PageQuery {
|
||||
roleName?: string;
|
||||
roleKey?: string;
|
||||
status?: string;
|
||||
checkedKeys: string[];
|
||||
depts: DeptTreeOption[];
|
||||
}
|
||||
|
||||
export interface RoleVO extends BaseEntity {
|
||||
@@ -38,11 +20,33 @@ export interface RoleVO extends BaseEntity {
|
||||
roleKey: string;
|
||||
roleSort: number;
|
||||
dataScope: string;
|
||||
menuCheckStrictly?: boolean;
|
||||
deptCheckStrictly?: boolean;
|
||||
menuCheckStrictly: boolean;
|
||||
deptCheckStrictly: boolean;
|
||||
status: string;
|
||||
delFlag: string;
|
||||
remark?: any;
|
||||
flag: boolean;
|
||||
admin: boolean;
|
||||
menuIds?: Array<string | number>;
|
||||
deptIds?: Array<string | number>;
|
||||
admin: boolean;
|
||||
}
|
||||
|
||||
export interface RoleQuery extends PageQuery {
|
||||
roleName: string;
|
||||
roleKey: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface RoleForm {
|
||||
roleName: string;
|
||||
roleKey: string;
|
||||
roleSort: number;
|
||||
status: string;
|
||||
menuCheckStrictly: boolean;
|
||||
deptCheckStrictly: boolean;
|
||||
remark: string;
|
||||
dataScope?: string;
|
||||
roleId: string | undefined;
|
||||
menuIds: Array<string | number>;
|
||||
deptIds: Array<string | number>;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,27 @@
|
||||
import type { R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { SocialAuthVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
|
||||
export function authRouterUrl(source: string) {
|
||||
return request<R<string>>({
|
||||
url: `/auth/binding/${source}`,
|
||||
method: 'get'
|
||||
// 绑定账号
|
||||
export function authBinding(source: string, tenantId: string) {
|
||||
return request({
|
||||
url: '/auth/binding/' + source,
|
||||
method: 'get',
|
||||
params: {
|
||||
tenantId: tenantId,
|
||||
domain: window.location.host
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 解绑账号
|
||||
export function authUnlock(authId: string) {
|
||||
return request<R>({
|
||||
url: `/auth/unlock/${authId}`,
|
||||
return request({
|
||||
url: '/auth/unlock/' + authId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
//获取授权列表
|
||||
export function getAuthList() {
|
||||
return request<R<SocialAuthVO[]>>({
|
||||
return request({
|
||||
url: '/system/social/list',
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
export interface SocialAuthVO {
|
||||
id: string;
|
||||
source?: string;
|
||||
avatar?: string;
|
||||
userName?: string;
|
||||
createTime?: string;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import request from '@/utils/request';
|
||||
import { TenantForm, TenantQuery, TenantVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
// 查询租户列表
|
||||
export function listTenant(query: TenantQuery): AxiosPromise<TenantVO[]> {
|
||||
return request({
|
||||
url: '/system/tenant/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
// 查询租户详细
|
||||
export function getTenant(id: string | number): AxiosPromise<TenantVO> {
|
||||
return request({
|
||||
url: '/system/tenant/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 新增租户
|
||||
export function addTenant(data: TenantForm) {
|
||||
return request({
|
||||
url: '/system/tenant',
|
||||
method: 'post',
|
||||
headers: {
|
||||
isEncrypt: true,
|
||||
repeatSubmit: false
|
||||
},
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 修改租户
|
||||
export function updateTenant(data: TenantForm) {
|
||||
return request({
|
||||
url: '/system/tenant',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 租户状态修改
|
||||
export function changeTenantStatus(id: string | number, tenantId: string | number, status: string) {
|
||||
const data = {
|
||||
id,
|
||||
tenantId,
|
||||
status
|
||||
};
|
||||
return request({
|
||||
url: '/system/tenant/changeStatus',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除租户
|
||||
export function delTenant(id: string | number | Array<string | number>) {
|
||||
return request({
|
||||
url: '/system/tenant/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 动态切换租户
|
||||
export function dynamicTenant(tenantId: string | number) {
|
||||
return request({
|
||||
url: '/system/tenant/dynamic/' + tenantId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 清除动态租户
|
||||
export function dynamicClear() {
|
||||
return request({
|
||||
url: '/system/tenant/dynamic/clear',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 同步租户套餐
|
||||
export function syncTenantPackage(tenantId: string | number, packageId: string | number) {
|
||||
const data = {
|
||||
tenantId,
|
||||
packageId
|
||||
};
|
||||
return request({
|
||||
url: '/system/tenant/syncTenantPackage',
|
||||
method: 'get',
|
||||
params: data
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
export interface TenantVO extends BaseEntity {
|
||||
id: number | string;
|
||||
tenantId: number | string;
|
||||
username: string;
|
||||
contactUserName: string;
|
||||
contactPhone: string;
|
||||
companyName: string;
|
||||
licenseNumber: string;
|
||||
address: string;
|
||||
domain: string;
|
||||
intro: string;
|
||||
remark: string;
|
||||
packageId: string | number;
|
||||
expireTime: string;
|
||||
accountCount: number;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface TenantQuery extends PageQuery {
|
||||
tenantId: string | number;
|
||||
|
||||
contactUserName: string;
|
||||
|
||||
contactPhone: string;
|
||||
|
||||
companyName: string;
|
||||
}
|
||||
|
||||
export interface TenantForm {
|
||||
id: number | string | undefined;
|
||||
tenantId: number | string | undefined;
|
||||
username: string;
|
||||
password: string;
|
||||
contactUserName: string;
|
||||
contactPhone: string;
|
||||
companyName: string;
|
||||
licenseNumber: string;
|
||||
domain: string;
|
||||
address: string;
|
||||
intro: string;
|
||||
remark: string;
|
||||
packageId: string | number;
|
||||
expireTime: string;
|
||||
accountCount: number;
|
||||
status: string;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import request from '@/utils/request';
|
||||
import { TenantPkgForm, TenantPkgQuery, TenantPkgVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
// 查询租户套餐列表
|
||||
export function listTenantPackage(query?: TenantPkgQuery): AxiosPromise<TenantPkgVO[]> {
|
||||
return request({
|
||||
url: '/system/tenant/package/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
// 查询租户套餐下拉选列表
|
||||
export function selectTenantPackage(): AxiosPromise<TenantPkgVO[]> {
|
||||
return request({
|
||||
url: '/system/tenant/package/selectList',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 查询租户套餐详细
|
||||
export function getTenantPackage(packageId: string | number): AxiosPromise<TenantPkgVO> {
|
||||
return request({
|
||||
url: '/system/tenant/package/' + packageId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 新增租户套餐
|
||||
export function addTenantPackage(data: TenantPkgForm) {
|
||||
return request({
|
||||
url: '/system/tenant/package',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 修改租户套餐
|
||||
export function updateTenantPackage(data: TenantPkgForm) {
|
||||
return request({
|
||||
url: '/system/tenant/package',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 租户套餐状态修改
|
||||
export function changePackageStatus(packageId: number | string, status: string) {
|
||||
const data = {
|
||||
packageId,
|
||||
status
|
||||
};
|
||||
return request({
|
||||
url: '/system/tenant/package/changeStatus',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 删除租户套餐
|
||||
export function delTenantPackage(packageId: string | number | Array<string | number>) {
|
||||
return request({
|
||||
url: '/system/tenant/package/' + packageId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export interface TenantPkgVO extends BaseEntity {
|
||||
packageId: string | number;
|
||||
packageName: string;
|
||||
menuIds: string;
|
||||
remark: string;
|
||||
menuCheckStrictly: boolean;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export interface TenantPkgQuery extends PageQuery {
|
||||
packageName: string;
|
||||
}
|
||||
|
||||
export interface TenantPkgForm {
|
||||
packageId: string | number | undefined;
|
||||
packageName: string;
|
||||
menuIds: string;
|
||||
remark: string;
|
||||
menuCheckStrictly: boolean;
|
||||
}
|
||||
+162
-87
@@ -1,154 +1,229 @@
|
||||
import type { DeptTreeVO } from '@/api/system/dept/types';
|
||||
import type { RoleVO } from '@/api/system/role/types';
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import { DeptVO } from './../dept/types';
|
||||
import { RoleVO } from '@/api/system/role/types';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { UserForm, UserQuery, UserVO, UserInfoVO } from './types';
|
||||
import { parseStrEmpty } from '@/utils/ruoyi';
|
||||
import type { UserForm, UserInfoVO, UserProfileForm, UserQuery, UserVO } from './types';
|
||||
|
||||
export function listUser(query: UserQuery) {
|
||||
return request<R<PageResult<UserVO>>>({
|
||||
/**
|
||||
* 查询用户列表
|
||||
* @param query
|
||||
*/
|
||||
export const listUser = (query: UserQuery): AxiosPromise<UserVO[]> => {
|
||||
return request({
|
||||
url: '/system/user/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function optionSelect(userIds: Array<number | string>) {
|
||||
return request<R<UserVO[]>>({
|
||||
url: `/system/user/optionselect?userIds=${userIds}`,
|
||||
/**
|
||||
* 通过用户ids查询用户
|
||||
* @param userIds
|
||||
*/
|
||||
export const optionSelect = (userIds: (number | string)[]): AxiosPromise<UserVO[]> => {
|
||||
return request({
|
||||
url: '/system/user/optionselect?userIds=' + userIds,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getUser(userId?: string | number) {
|
||||
return request<R<UserInfoVO>>({
|
||||
url: `/system/user/${parseStrEmpty(userId)}`,
|
||||
/**
|
||||
* 获取用户详情
|
||||
* @param userId
|
||||
*/
|
||||
export const getUser = (userId?: string | number): AxiosPromise<UserInfoVO> => {
|
||||
return request({
|
||||
url: '/system/user/' + parseStrEmpty(userId),
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function addUser(data: UserForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 新增用户
|
||||
*/
|
||||
export const addUser = (data: UserForm) => {
|
||||
return request({
|
||||
url: '/system/user',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateUser(data: UserForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 修改用户
|
||||
*/
|
||||
export const updateUser = (data: UserForm) => {
|
||||
return request({
|
||||
url: '/system/user',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function delUser(userId: Array<string | number> | string | number) {
|
||||
return request<R>({
|
||||
url: `/system/user/${userId}`,
|
||||
/**
|
||||
* 删除用户
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
export const delUser = (userId: Array<string | number> | string | number) => {
|
||||
return request({
|
||||
url: '/system/user/' + userId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function resetUserPwd(userId: string | number, password: string) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 用户密码重置
|
||||
* @param userId 用户ID
|
||||
* @param password 密码
|
||||
*/
|
||||
export const resetUserPwd = (userId: string | number, password: string) => {
|
||||
const data = {
|
||||
userId,
|
||||
password
|
||||
};
|
||||
return request({
|
||||
url: '/system/user/resetPwd',
|
||||
method: 'put',
|
||||
headers: {
|
||||
isEncrypt: true,
|
||||
repeatSubmit: false
|
||||
},
|
||||
data: {
|
||||
userId,
|
||||
password
|
||||
}
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function changeUserStatus(userId: number | string, status: string) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 用户状态修改
|
||||
* @param userId 用户ID
|
||||
* @param status 用户状态
|
||||
*/
|
||||
export const changeUserStatus = (userId: number | string, status: string) => {
|
||||
const data = {
|
||||
userId,
|
||||
status
|
||||
};
|
||||
return request({
|
||||
url: '/system/user/changeStatus',
|
||||
method: 'put',
|
||||
data: {
|
||||
userId,
|
||||
status
|
||||
}
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function unlockUser(userId: number | string) {
|
||||
return request<R>({
|
||||
url: `/system/user/unlock/${userId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function getUserProfile() {
|
||||
return request<R<UserInfoVO>>({
|
||||
/**
|
||||
* 查询用户个人信息
|
||||
*/
|
||||
export const getUserProfile = (): AxiosPromise<UserInfoVO> => {
|
||||
return request({
|
||||
url: '/system/user/profile',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateUserProfile(data: UserProfileForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 修改用户个人信息
|
||||
* @param data 用户信息
|
||||
*/
|
||||
export const updateUserProfile = (data: UserForm) => {
|
||||
return request({
|
||||
url: '/system/user/profile',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateUserPwd(oldPassword: string, newPassword: string) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 用户密码重置
|
||||
* @param oldPassword 旧密码
|
||||
* @param newPassword 新密码
|
||||
*/
|
||||
export const updateUserPwd = (oldPassword: string, newPassword: string) => {
|
||||
const data = {
|
||||
oldPassword,
|
||||
newPassword
|
||||
};
|
||||
return request({
|
||||
url: '/system/user/profile/updatePwd',
|
||||
method: 'put',
|
||||
headers: {
|
||||
isEncrypt: true,
|
||||
repeatSubmit: false
|
||||
},
|
||||
data: {
|
||||
oldPassword,
|
||||
newPassword
|
||||
}
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function importUser(data: FormData, updateSupport: boolean) {
|
||||
return request<R>({
|
||||
url: '/system/user/importData',
|
||||
/**
|
||||
* 用户头像上传
|
||||
* @param data 头像文件
|
||||
*/
|
||||
export const uploadAvatar = (data: FormData) => {
|
||||
return request({
|
||||
url: '/system/user/profile/avatar',
|
||||
method: 'post',
|
||||
params: {
|
||||
updateSupport: updateSupport ? 1 : 0
|
||||
},
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getAuthRole(userId: string | number) {
|
||||
return request<R<{ user: UserVO; roles: RoleVO[] }>>({
|
||||
url: `/system/user/authRole/${userId}`,
|
||||
/**
|
||||
* 查询授权角色
|
||||
* @param userId 用户ID
|
||||
*/
|
||||
export const getAuthRole = (userId: string | number): AxiosPromise<{ user: UserVO; roles: RoleVO[] }> => {
|
||||
return request({
|
||||
url: '/system/user/authRole/' + userId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateAuthRole(data: { userId: string; roleIds: string }) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 保存授权角色
|
||||
* @param data 用户ID
|
||||
*/
|
||||
export const updateAuthRole = (data: { userId: string; roleIds: string }) => {
|
||||
return request({
|
||||
url: '/system/user/authRole',
|
||||
method: 'put',
|
||||
params: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function deptTreeSelect() {
|
||||
return request<R<DeptTreeVO[]>>({
|
||||
/**
|
||||
* 查询当前部门的所有用户信息
|
||||
* @param deptId
|
||||
*/
|
||||
export const listUserByDeptId = (deptId: string | number): AxiosPromise<UserVO[]> => {
|
||||
return request({
|
||||
url: '/system/user/list/dept/' + deptId,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询部门下拉树结构
|
||||
*/
|
||||
export const deptTreeSelect = (): AxiosPromise<DeptVO[]> => {
|
||||
return request({
|
||||
url: '/system/user/deptTree',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function listUserByDeptId(deptId: string | number) {
|
||||
return request<R<UserVO[]>>({
|
||||
url: `/system/user/list/dept/${deptId}`,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
export default {
|
||||
listUser,
|
||||
getUser,
|
||||
optionSelect,
|
||||
addUser,
|
||||
updateUser,
|
||||
delUser,
|
||||
resetUserPwd,
|
||||
changeUserStatus,
|
||||
getUserProfile,
|
||||
updateUserProfile,
|
||||
updateUserPwd,
|
||||
uploadAvatar,
|
||||
getAuthRole,
|
||||
updateAuthRole,
|
||||
deptTreeSelect,
|
||||
listUserByDeptId
|
||||
};
|
||||
|
||||
@@ -1,82 +1,84 @@
|
||||
import type { DeptVO } from '@/api/system/dept/types';
|
||||
import type { PostVO } from '@/api/system/post/types';
|
||||
import type { RoleVO } from '@/api/system/role/types';
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
import { RoleVO } from '@/api/system/role/types';
|
||||
import { PostVO } from '@/api/system/post/types';
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
*/
|
||||
export interface UserInfo {
|
||||
user: {
|
||||
userId: string | number;
|
||||
userName: string;
|
||||
nickName?: string;
|
||||
avatar?: string | number;
|
||||
avatarUrl?: string;
|
||||
deptName?: string;
|
||||
};
|
||||
user: UserVO;
|
||||
roles: string[];
|
||||
permissions: string[];
|
||||
}
|
||||
|
||||
export interface UserForm {
|
||||
userId?: string | number;
|
||||
deptId?: number | string;
|
||||
userName?: string;
|
||||
nickName?: string;
|
||||
password?: string;
|
||||
phoneNumber?: string;
|
||||
email?: string;
|
||||
gender?: string;
|
||||
status?: string;
|
||||
remark?: string;
|
||||
avatar?: string | number;
|
||||
postIds?: Array<string | number>;
|
||||
roleIds?: Array<string | number>;
|
||||
}
|
||||
|
||||
export interface UserProfileForm {
|
||||
nickName?: string;
|
||||
phoneNumber?: string;
|
||||
email?: string;
|
||||
gender?: string;
|
||||
avatar?: string | number;
|
||||
}
|
||||
|
||||
export interface UserInfoVO {
|
||||
user?: UserVO;
|
||||
roles: RoleVO[];
|
||||
roleIds: Array<string | number>;
|
||||
posts: PostVO[];
|
||||
postIds: Array<string | number>;
|
||||
roleGroup?: string;
|
||||
postGroup?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户查询对象类型
|
||||
*/
|
||||
export interface UserQuery extends PageQuery {
|
||||
userName?: string;
|
||||
nickName?: string;
|
||||
phoneNumber?: string;
|
||||
phonenumber?: string;
|
||||
status?: string;
|
||||
deptId?: string | number;
|
||||
roleId?: string | number;
|
||||
userIds?: string | number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户返回对象
|
||||
*/
|
||||
export interface UserVO extends BaseEntity {
|
||||
userId?: string | number;
|
||||
tenantId?: string;
|
||||
deptId?: number | string;
|
||||
userName?: string;
|
||||
userId: string | number;
|
||||
tenantId: string;
|
||||
deptId: number;
|
||||
userName: string;
|
||||
nickName: string;
|
||||
userType: string;
|
||||
email: string;
|
||||
phonenumber: string;
|
||||
sex: string;
|
||||
avatar: string;
|
||||
status: string;
|
||||
delFlag: string;
|
||||
loginIp: string;
|
||||
loginDate: string;
|
||||
remark: string;
|
||||
deptName: string;
|
||||
roles: RoleVO[];
|
||||
roleIds: any;
|
||||
postIds: any;
|
||||
roleId: any;
|
||||
admin: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户表单类型
|
||||
*/
|
||||
export interface UserForm {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
deptId?: number;
|
||||
userName: string;
|
||||
nickName?: string;
|
||||
userType?: string;
|
||||
password: string;
|
||||
phonenumber?: string;
|
||||
email?: string;
|
||||
phoneNumber?: string;
|
||||
gender?: string;
|
||||
avatar?: string | number;
|
||||
avatarUrl?: string;
|
||||
status?: string;
|
||||
deptName?: string;
|
||||
roles?: RoleVO[];
|
||||
admin?: boolean;
|
||||
loginIp?: string;
|
||||
loginDate?: string;
|
||||
dept?: DeptVO;
|
||||
sex?: string;
|
||||
status: string;
|
||||
remark?: string;
|
||||
postIds: string[];
|
||||
roleIds: string[];
|
||||
}
|
||||
|
||||
export interface UserInfoVO {
|
||||
user: UserVO;
|
||||
roles: RoleVO[];
|
||||
roleIds: string[];
|
||||
posts: PostVO[];
|
||||
postIds: string[];
|
||||
roleGroup: string;
|
||||
postGroup: string;
|
||||
}
|
||||
|
||||
export interface ResetPwdForm {
|
||||
oldPassword: string;
|
||||
newPassword: string;
|
||||
confirmPassword: string;
|
||||
}
|
||||
|
||||
+52
-44
@@ -1,78 +1,86 @@
|
||||
import type { PageResult, R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { DbTableQuery, DbTableVO, GenTableDetailPayload, TableQuery, TableVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { DbTableQuery, DbTableVO, TableQuery, TableVO, GenTableVO, DbTableForm } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
export function listTable(query: TableQuery) {
|
||||
return request<R<PageResult<TableVO>>>({
|
||||
// 查询生成表数据
|
||||
export const listTable = (query: TableQuery): AxiosPromise<TableVO[]> => {
|
||||
return request({
|
||||
url: '/tool/gen/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
|
||||
export function listDbTable(query: DbTableQuery) {
|
||||
return request<R<PageResult<DbTableVO>>>({
|
||||
};
|
||||
// 查询db数据库列表
|
||||
export const listDbTable = (query: DbTableQuery): AxiosPromise<DbTableVO[]> => {
|
||||
return request({
|
||||
url: '/tool/gen/db/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getGenTable(tableId: string | number) {
|
||||
return request<R<GenTableDetailPayload>>({
|
||||
url: `/tool/gen/${tableId}`,
|
||||
// 查询表详细信息
|
||||
export const getGenTable = (tableId: string | number): AxiosPromise<GenTableVO> => {
|
||||
return request({
|
||||
url: '/tool/gen/' + tableId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateGenTable(data: DbTableVO & { columns?: unknown[]; params?: Record<string, unknown> }) {
|
||||
return request<R>({
|
||||
// 修改代码生成信息
|
||||
export const updateGenTable = (data: DbTableForm): AxiosPromise<GenTableVO> => {
|
||||
return request({
|
||||
url: '/tool/gen',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function importTable(data: { tables: string; dataName: string }) {
|
||||
return request<R>({
|
||||
// 导入表
|
||||
export const importTable = (data: { tables: string; dataName: string }): AxiosPromise<GenTableVO> => {
|
||||
return request({
|
||||
url: '/tool/gen/importTable',
|
||||
method: 'post',
|
||||
params: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function previewTable(tableId: string | number) {
|
||||
return request<R<Record<string, string>>>({
|
||||
url: `/tool/gen/preview/${tableId}`,
|
||||
// 预览生成代码
|
||||
export const previewTable = (tableId: string | number) => {
|
||||
return request({
|
||||
url: '/tool/gen/preview/' + tableId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function delTable(tableId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/tool/gen/${tableId}`,
|
||||
// 删除表数据
|
||||
export const delTable = (tableId: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/tool/gen/' + tableId,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function synchDb(tableId: string | number) {
|
||||
return request<R>({
|
||||
url: `/tool/gen/synchDb/${tableId}`,
|
||||
// 生成代码(自定义路径)
|
||||
export const genCode = (tableId: string | number) => {
|
||||
return request({
|
||||
url: '/tool/gen/genCode/' + tableId,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getDataNames() {
|
||||
return request<R<string[]>>({
|
||||
// 同步数据库
|
||||
export const synchDb = (tableId: string | number) => {
|
||||
return request({
|
||||
url: '/tool/gen/synchDb/' + tableId,
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
// 获取数据源名称
|
||||
export const getDataNames = () => {
|
||||
return request({
|
||||
url: '/tool/gen/getDataNames',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
export function batchGenCode(tableIdStr: string) {
|
||||
return request<Blob>({
|
||||
url: `/tool/gen/batchGenCode?tableIdStr=${tableIdStr}`,
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
+173
-84
@@ -1,91 +1,180 @@
|
||||
import type { BaseEntity, PageQuery } from '@/api/types';
|
||||
|
||||
export interface DbColumnVO extends BaseEntity {
|
||||
columnId?: string | number;
|
||||
tableId?: string | number;
|
||||
columnName?: string;
|
||||
columnComment?: string;
|
||||
columnType?: string;
|
||||
javaType?: string;
|
||||
javaField?: string;
|
||||
isPk?: string;
|
||||
isIncrement?: string;
|
||||
isRequired?: string;
|
||||
isInsert?: string;
|
||||
isEdit?: string;
|
||||
isList?: string;
|
||||
isQuery?: string;
|
||||
queryType?: string;
|
||||
htmlType?: string;
|
||||
dictType?: string;
|
||||
sort?: number;
|
||||
increment?: boolean;
|
||||
capJavaField?: string;
|
||||
usableColumn?: boolean;
|
||||
superColumn?: boolean;
|
||||
list?: boolean;
|
||||
pk?: boolean;
|
||||
insert?: boolean;
|
||||
edit?: boolean;
|
||||
query?: boolean;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
export interface DbTableQuery extends PageQuery {
|
||||
dataName?: string;
|
||||
tableName?: string;
|
||||
tableComment?: string;
|
||||
}
|
||||
|
||||
export interface DbTableVO extends Omit<TableVO, 'tableId'> {
|
||||
tableId?: string | number;
|
||||
columns?: DbColumnVO[];
|
||||
options?: string;
|
||||
remark?: string;
|
||||
treeCode?: string;
|
||||
treeParentCode?: string;
|
||||
treeName?: string;
|
||||
menuIds?: Array<string | number>;
|
||||
parentMenuId?: string | number;
|
||||
parentMenuName?: string;
|
||||
enableExport?: boolean;
|
||||
enableStatus?: boolean;
|
||||
statusField?: string;
|
||||
enableUnique?: boolean;
|
||||
uniqueFields?: string[];
|
||||
enableSort?: boolean;
|
||||
sortField?: string;
|
||||
frontendType?: string;
|
||||
treeRootValue?: string;
|
||||
treeAncestorsField?: string;
|
||||
treeOrderField?: string;
|
||||
}
|
||||
|
||||
export interface GenTableDetailPayload {
|
||||
info: DbTableVO;
|
||||
rows: DbColumnVO[];
|
||||
export interface TableVO extends BaseEntity {
|
||||
createDept: number | string;
|
||||
tableId: string | number;
|
||||
dataName: string;
|
||||
tableName: string;
|
||||
tableComment: string;
|
||||
subTableName?: any;
|
||||
subTableFkName?: any;
|
||||
className: string;
|
||||
tplCategory: string;
|
||||
packageName: string;
|
||||
moduleName: string;
|
||||
businessName: string;
|
||||
functionName: string;
|
||||
functionAuthor: string;
|
||||
genType: string;
|
||||
genPath: string;
|
||||
pkColumn?: any;
|
||||
columns?: any;
|
||||
options?: any;
|
||||
remark?: any;
|
||||
treeCode?: any;
|
||||
treeParentCode?: any;
|
||||
treeName?: any;
|
||||
menuIds?: any;
|
||||
parentMenuId?: any;
|
||||
parentMenuName?: any;
|
||||
tree: boolean;
|
||||
crud: boolean;
|
||||
}
|
||||
|
||||
export interface TableQuery extends PageQuery {
|
||||
tableName?: string;
|
||||
tableComment?: string;
|
||||
dataName?: string;
|
||||
tableName: string;
|
||||
tableComment: string;
|
||||
dataName: string;
|
||||
}
|
||||
|
||||
export interface TableVO extends BaseEntity {
|
||||
createDept?: number | string;
|
||||
tableId: string | number;
|
||||
dataName?: string;
|
||||
export interface DbColumnVO extends BaseEntity {
|
||||
createDept?: any;
|
||||
columnId?: any;
|
||||
tableId?: any;
|
||||
columnName?: any;
|
||||
columnComment?: any;
|
||||
columnType?: any;
|
||||
javaType?: any;
|
||||
javaField?: any;
|
||||
isPk?: any;
|
||||
isIncrement?: any;
|
||||
isRequired?: any;
|
||||
isInsert?: any;
|
||||
isEdit?: any;
|
||||
isList?: any;
|
||||
isQuery?: any;
|
||||
queryType?: any;
|
||||
htmlType?: any;
|
||||
dictType?: any;
|
||||
sort?: any;
|
||||
increment: boolean;
|
||||
capJavaField?: any;
|
||||
usableColumn: boolean;
|
||||
superColumn: boolean;
|
||||
list: boolean;
|
||||
pk: boolean;
|
||||
insert: boolean;
|
||||
edit: boolean;
|
||||
query: boolean;
|
||||
required: boolean;
|
||||
}
|
||||
|
||||
export interface DbTableVO {
|
||||
createDept?: any;
|
||||
tableId?: any;
|
||||
tableName: string;
|
||||
tableComment?: string;
|
||||
className?: string;
|
||||
tplCategory?: string;
|
||||
frontendType?: string;
|
||||
packageName?: string;
|
||||
moduleName?: string;
|
||||
businessName?: string;
|
||||
functionName?: string;
|
||||
functionAuthor?: string;
|
||||
tree?: boolean;
|
||||
crud?: boolean;
|
||||
tableComment: string;
|
||||
subTableName?: any;
|
||||
subTableFkName?: any;
|
||||
className?: any;
|
||||
tplCategory?: any;
|
||||
packageName?: any;
|
||||
moduleName?: any;
|
||||
businessName?: any;
|
||||
functionName?: any;
|
||||
functionAuthor?: any;
|
||||
genType?: any;
|
||||
genPath?: any;
|
||||
pkColumn?: any;
|
||||
columns: DbColumnVO[];
|
||||
options?: any;
|
||||
remark?: any;
|
||||
treeCode?: any;
|
||||
treeParentCode?: any;
|
||||
treeName?: any;
|
||||
menuIds?: any;
|
||||
parentMenuId?: any;
|
||||
parentMenuName?: any;
|
||||
tree: boolean;
|
||||
crud: boolean;
|
||||
}
|
||||
|
||||
export interface DbTableQuery extends PageQuery {
|
||||
dataName: string;
|
||||
tableName: string;
|
||||
tableComment: string;
|
||||
}
|
||||
|
||||
export interface GenTableVO {
|
||||
info: DbTableVO;
|
||||
rows: DbColumnVO[];
|
||||
tables: DbTableVO[];
|
||||
}
|
||||
|
||||
export interface DbColumnForm extends BaseEntity {
|
||||
createDept: number;
|
||||
columnId: string;
|
||||
tableId: string;
|
||||
columnName: string;
|
||||
columnComment: string;
|
||||
columnType: string;
|
||||
javaType: string;
|
||||
javaField: string;
|
||||
isPk: string;
|
||||
isIncrement: string;
|
||||
isRequired: string;
|
||||
isInsert?: any;
|
||||
isEdit: string;
|
||||
isList: string;
|
||||
isQuery?: any;
|
||||
queryType: string;
|
||||
htmlType: string;
|
||||
dictType: string;
|
||||
sort: number;
|
||||
increment: boolean;
|
||||
capJavaField: string;
|
||||
usableColumn: boolean;
|
||||
superColumn: boolean;
|
||||
list: boolean;
|
||||
pk: boolean;
|
||||
insert: boolean;
|
||||
edit: boolean;
|
||||
query: boolean;
|
||||
required: boolean;
|
||||
}
|
||||
|
||||
export interface DbParamForm {
|
||||
treeCode?: any;
|
||||
treeName?: any;
|
||||
treeParentCode?: any;
|
||||
parentMenuId: string;
|
||||
}
|
||||
|
||||
export interface DbTableForm extends BaseEntity {
|
||||
createDept?: any;
|
||||
tableId: string | string;
|
||||
tableName: string;
|
||||
tableComment: string;
|
||||
subTableName?: any;
|
||||
subTableFkName?: any;
|
||||
className: string;
|
||||
tplCategory: string;
|
||||
packageName: string;
|
||||
moduleName: string;
|
||||
businessName: string;
|
||||
functionName: string;
|
||||
functionAuthor: string;
|
||||
genType: string;
|
||||
genPath: string;
|
||||
pkColumn?: any;
|
||||
columns: DbColumnForm[];
|
||||
options: string;
|
||||
remark?: any;
|
||||
treeCode?: any;
|
||||
treeParentCode?: any;
|
||||
treeName?: any;
|
||||
menuIds?: any;
|
||||
parentMenuId: string;
|
||||
parentMenuName?: any;
|
||||
tree: boolean;
|
||||
crud: boolean;
|
||||
params: DbParamForm;
|
||||
}
|
||||
|
||||
+44
-73
@@ -1,88 +1,59 @@
|
||||
import type { MenuDataItem } from '@ant-design/pro-components';
|
||||
|
||||
export interface BaseEntity {
|
||||
createBy?: string;
|
||||
createTime?: string;
|
||||
updateBy?: string;
|
||||
updateTime?: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
export interface LoginParams {
|
||||
username?: string;
|
||||
password?: string;
|
||||
code?: string;
|
||||
uuid?: string;
|
||||
rememberMe?: boolean;
|
||||
socialCode?: string;
|
||||
socialState?: string;
|
||||
source?: string;
|
||||
clientId?: string;
|
||||
grantType?: string;
|
||||
}
|
||||
|
||||
export interface LoginResult {
|
||||
access_token: string;
|
||||
}
|
||||
|
||||
export interface PageQuery {
|
||||
pageNum?: number;
|
||||
pageSize?: number;
|
||||
orderByColumn?: string;
|
||||
isAsc?: 'ascending' | 'descending';
|
||||
params?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface PageResult<T = unknown> {
|
||||
total: number;
|
||||
rows: T[];
|
||||
}
|
||||
|
||||
export interface R<T = unknown> {
|
||||
code: number;
|
||||
msg: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export interface RegisterParams {
|
||||
username?: string;
|
||||
password?: string;
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
export type RegisterForm = {
|
||||
tenantId: string;
|
||||
username: string;
|
||||
password: string;
|
||||
confirmPassword?: string;
|
||||
code?: string;
|
||||
uuid?: string;
|
||||
userType?: string;
|
||||
clientId?: string;
|
||||
grantType?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* 登录请求
|
||||
*/
|
||||
export interface LoginData {
|
||||
tenantId?: string;
|
||||
username?: string;
|
||||
password?: string;
|
||||
rememberMe?: boolean;
|
||||
socialCode?: string;
|
||||
socialState?: string;
|
||||
source?: string;
|
||||
code?: string;
|
||||
uuid?: string;
|
||||
clientId: string;
|
||||
grantType: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录响应
|
||||
*/
|
||||
export interface LoginResult {
|
||||
access_token: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码返回
|
||||
*/
|
||||
export interface VerifyCodeResult {
|
||||
captchaEnabled: boolean;
|
||||
uuid?: string;
|
||||
img?: string;
|
||||
}
|
||||
|
||||
export interface RouteMeta {
|
||||
title?: string;
|
||||
icon?: string | null;
|
||||
noCache?: boolean;
|
||||
link?: string;
|
||||
hidden?: boolean;
|
||||
activeMenu?: string;
|
||||
/**
|
||||
* 租户
|
||||
*/
|
||||
export interface TenantVO {
|
||||
companyName: string;
|
||||
domain: any;
|
||||
tenantId: string;
|
||||
}
|
||||
|
||||
export interface BackendRoute {
|
||||
name?: string;
|
||||
path: string;
|
||||
component?: string;
|
||||
redirect?: string;
|
||||
query?: string;
|
||||
hidden?: boolean;
|
||||
alwaysShow?: boolean;
|
||||
meta?: RouteMeta;
|
||||
children?: BackendRoute[];
|
||||
export interface TenantInfo {
|
||||
tenantEnabled: boolean;
|
||||
voList: TenantVO[];
|
||||
}
|
||||
|
||||
export type RuntimeMenuItem = Omit<MenuDataItem, 'routes'> & {
|
||||
backendRoute?: BackendRoute;
|
||||
routes?: RuntimeMenuItem[];
|
||||
};
|
||||
|
||||
@@ -1,49 +1,63 @@
|
||||
import type { R } from '@/api/types';
|
||||
import request from '@/api/request';
|
||||
import type { CategoryForm, CategoryQuery, CategoryTreeVO, CategoryVO } from './types';
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { CategoryVO, CategoryForm, CategoryQuery } from '@/api/workflow/category/types';
|
||||
|
||||
export function listCategory(query?: CategoryQuery) {
|
||||
return request<R<CategoryVO[]>>({
|
||||
/**
|
||||
* 查询流程分类列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const listCategory = (query?: CategoryQuery): AxiosPromise<CategoryVO[]> => {
|
||||
return request({
|
||||
url: '/workflow/category/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function getCategory(categoryId: string | number) {
|
||||
return request<R<CategoryVO>>({
|
||||
url: `/workflow/category/${categoryId}`,
|
||||
/**
|
||||
* 查询流程分类详细
|
||||
* @param id
|
||||
*/
|
||||
export const getCategory = (id: string | number): AxiosPromise<CategoryVO> => {
|
||||
return request({
|
||||
url: '/workflow/category/' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function addCategory(data: CategoryForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 新增流程分类
|
||||
* @param data
|
||||
*/
|
||||
export const addCategory = (data: CategoryForm) => {
|
||||
return request({
|
||||
url: '/workflow/category',
|
||||
method: 'post',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function updateCategory(data: CategoryForm) {
|
||||
return request<R>({
|
||||
/**
|
||||
* 修改流程分类
|
||||
* @param data
|
||||
*/
|
||||
export const updateCategory = (data: CategoryForm) => {
|
||||
return request({
|
||||
url: '/workflow/category',
|
||||
method: 'put',
|
||||
data
|
||||
data: data
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export function delCategory(categoryId: string | number | Array<string | number>) {
|
||||
return request<R>({
|
||||
url: `/workflow/category/${categoryId}`,
|
||||
/**
|
||||
* 删除流程分类
|
||||
* @param id
|
||||
*/
|
||||
export const delCategory = (id: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/workflow/category/' + id,
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
export function categoryTree(query?: CategoryForm) {
|
||||
return request<R<CategoryTreeVO[]>>({
|
||||
url: '/workflow/category/categoryTree',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,29 +1,67 @@
|
||||
import type { BaseEntity } from '@/api/types';
|
||||
|
||||
export interface CategoryForm extends BaseEntity {
|
||||
categoryId?: string | number;
|
||||
categoryName?: string;
|
||||
parentId?: string | number;
|
||||
orderNum?: number;
|
||||
}
|
||||
|
||||
export interface CategoryQuery {
|
||||
categoryName?: string;
|
||||
}
|
||||
|
||||
export interface CategoryTreeVO {
|
||||
id: number | string;
|
||||
label: string;
|
||||
parentId: number | string;
|
||||
weight: number;
|
||||
children?: CategoryTreeVO[];
|
||||
}
|
||||
|
||||
export interface CategoryVO {
|
||||
categoryId: string | number;
|
||||
parentId?: string | number;
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
categoryName: string;
|
||||
orderNum: number;
|
||||
createTime?: string;
|
||||
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
categoryCode: string;
|
||||
|
||||
/**
|
||||
* 父级id
|
||||
*/
|
||||
parentId: string | number;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sortNum: number;
|
||||
|
||||
children?: CategoryVO[];
|
||||
}
|
||||
|
||||
export interface CategoryForm extends BaseEntity {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
id?: string | number;
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
categoryName?: string;
|
||||
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
categoryCode?: string;
|
||||
|
||||
/**
|
||||
* 父级id
|
||||
*/
|
||||
parentId?: string | number;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sortNum?: number;
|
||||
}
|
||||
|
||||
export interface CategoryQuery extends PageQuery {
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
categoryName?: string;
|
||||
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
categoryCode?: string;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user