Compare commits
451 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d1cb99c74a | |
|
|
b46b1647eb | |
|
|
2f7ec5b78f | |
|
|
37c70daaaf | |
|
|
944dd34d9e | |
|
|
ff3c7884cc | |
|
|
595b8c5bb4 | |
|
|
e6c0976c52 | |
|
|
ed31f0d3c1 | |
|
|
2e68890c7d | |
|
|
8405a07dd0 | |
|
|
1b7fb5ed5d | |
|
|
aff1439629 | |
|
|
9a4f9b6995 | |
|
|
d08413a68e | |
|
|
89a49cf19c | |
|
|
763e11eb78 | |
|
|
664904bd06 | |
|
|
811b93d9f1 | |
|
|
e80e5203a4 | |
|
|
c8b132433a | |
|
|
57596361ef | |
|
|
685ada8475 | |
|
|
e1b8370267 | |
|
|
a4dfb717aa | |
|
|
06a008b030 | |
|
|
f3807e30d5 | |
|
|
dc1a582fbd | |
|
|
8b06efe5ee | |
|
|
309a4bf4d0 | |
|
|
2ede2b371f | |
|
|
00f273ca77 | |
|
|
dd009a1de0 | |
|
|
fa42f8e574 | |
|
|
a1c43ed427 | |
|
|
31a7f6248a | |
|
|
02c0d0cb3b | |
|
|
a2fbf5b712 | |
|
|
cb78c2935d | |
|
|
798318ef7d | |
|
|
8971c37059 | |
|
|
7dd7309e9c | |
|
|
1612e3e1b6 | |
|
|
72d8c499a4 | |
|
|
fa653ac887 | |
|
|
1888757854 | |
|
|
38ecc4f40c | |
|
|
9893aedbb2 | |
|
|
5a983bb1eb | |
|
|
b5bc537f86 | |
|
|
fead282395 | |
|
|
73aa578c9b | |
|
|
7a236b4378 | |
|
|
1015423431 | |
|
|
3949e0c89f | |
|
|
29b257b8cd | |
|
|
1e08e9fbca | |
|
|
69653163b0 | |
|
|
8468d9bf4d | |
|
|
f7cda1fc4e | |
|
|
fee633b0c8 | |
|
|
b63492199a | |
|
|
c6b6e723e0 | |
|
|
0a07d4a2e4 | |
|
|
fc812aef26 | |
|
|
f26c65c03f | |
|
|
30b963149a | |
|
|
9a36cfe933 | |
|
|
94e5fc00ac | |
|
|
2442a01e48 | |
|
|
bfd407d75b | |
|
|
b6d123ac72 | |
|
|
5ebbbf7499 | |
|
|
8ad7180c2b | |
|
|
f5bcaf22f9 | |
|
|
40d762070f | |
|
|
7fa9311753 | |
|
|
60c74b991e | |
|
|
c4519a8696 | |
|
|
b52ad0c34b | |
|
|
5c2ee259a6 | |
|
|
8329a6a885 | |
|
|
073c54bc1d | |
|
|
f58d1d88c8 | |
|
|
f6963cde37 | |
|
|
0c54bf28b3 | |
|
|
d0cd93de5a | |
|
|
a2d043bc72 | |
|
|
7622a44bbb | |
|
|
12a41da241 | |
|
|
ae7f3a8bc5 | |
|
|
b9b085f1ee | |
|
|
dc318c8e75 | |
|
|
6cd49f0ce4 | |
|
|
85207bec98 | |
|
|
46c436e0df | |
|
|
5d222bdf48 | |
|
|
ceb1aa9bce | |
|
|
26a3b87114 | |
|
|
03d0ce800d | |
|
|
a3f89d686c | |
|
|
68922ebf02 | |
|
|
e629ac3825 | |
|
|
8b4351e4f3 | |
|
|
28473434da | |
|
|
1f47e3c9d6 | |
|
|
4f4c64cfff | |
|
|
9a49c2df20 | |
|
|
9b8b1322b7 | |
|
|
ecb15b6481 | |
|
|
a18c81511c | |
|
|
b3bb1114ba | |
|
|
50cfbfe58b | |
|
|
c81116678a | |
|
|
fa570c2637 | |
|
|
2ffbcbd71f | |
|
|
524ed28973 | |
|
|
508d06b493 | |
|
|
f82ae7e0c8 | |
|
|
24343f66fc | |
|
|
52972506a8 | |
|
|
d128df618e | |
|
|
5f944548a3 | |
|
|
7bae330828 | |
|
|
7ff8cb78e1 | |
|
|
8252f7b068 | |
|
|
19db64c08a | |
|
|
e0352af8b0 | |
|
|
ae54f938cf | |
|
|
b455ce4949 | |
|
|
58537a34c7 | |
|
|
4a811fb0bb | |
|
|
804ad667e0 | |
|
|
eaedb1e0ca | |
|
|
e579a4de13 | |
|
|
df013ac69c | |
|
|
6f96d004a9 | |
|
|
44808eb3f4 | |
|
|
a7911bcbcf | |
|
|
a170ae37ab | |
|
|
841d2cb763 | |
|
|
8d06f87e0f | |
|
|
fdbb98fe65 | |
|
|
c5948d405e | |
|
|
70aff05ef5 | |
|
|
b3b35e147b | |
|
|
765c8ea94f | |
|
|
ac49ba5c6d | |
|
|
3ef4e8424f | |
|
|
c865dfe488 | |
|
|
18e5c97bf3 | |
|
|
680c0e0e8b | |
|
|
38cb980ce4 | |
|
|
0be2674277 | |
|
|
f0cd639137 | |
|
|
314293ced3 | |
|
|
32bbd912a2 | |
|
|
32442830b0 | |
|
|
711d5abc0a | |
|
|
4da16e95f5 | |
|
|
d890781149 | |
|
|
30e4fef7bb | |
|
|
8105cc786a | |
|
|
eb8002ce0b | |
|
|
1aad2f1648 | |
|
|
c3737d3b7a | |
|
|
750f25410c | |
|
|
e12596ad7c | |
|
|
2935d7d112 | |
|
|
46b06b0444 | |
|
|
70e7a1c900 | |
|
|
c5b082ca80 | |
|
|
dfd5b39a17 | |
|
|
312df4c73d | |
|
|
40ac2daca8 | |
|
|
094ab44094 | |
|
|
9eb221e8d2 | |
|
|
5b85a4c469 | |
|
|
7fa1dbc55c | |
|
|
cc93b8a742 | |
|
|
0b07091e79 | |
|
|
0323566878 | |
|
|
82d065c270 | |
|
|
cf01143632 | |
|
|
9bcdc92806 | |
|
|
f5936a6e7f | |
|
|
d175fe86be | |
|
|
ce66a507ef | |
|
|
65d5aacac9 | |
|
|
808ad575fc | |
|
|
cb26df3ca1 | |
|
|
b2ba42049b | |
|
|
f746aebe08 | |
|
|
0eca952c6a | |
|
|
a98e32554c | |
|
|
2f513f7b8f | |
|
|
8eebfd4744 | |
|
|
1ed5dc7e6a | |
|
|
8fc5273a88 | |
|
|
81711a98c9 | |
|
|
766b3906fa | |
|
|
cd63cf2b34 | |
|
|
84ae85f545 | |
|
|
78b6679e63 | |
|
|
ee5ed1f97b | |
|
|
3be0daf115 | |
|
|
4868d69ed8 | |
|
|
1ac0650984 | |
|
|
30d695d702 | |
|
|
459eaa5428 | |
|
|
59aab8ecdc | |
|
|
b17f7a57e5 | |
|
|
957a63f8f4 | |
|
|
c15d75ba91 | |
|
|
3836467481 | |
|
|
f3de29f95f | |
|
|
8f2eddea4a | |
|
|
f8cc9d14d9 | |
|
|
5bd99c53c2 | |
|
|
c653c2fa2b | |
|
|
4e181564b8 | |
|
|
a9f54fdee1 | |
|
|
055d4bab27 | |
|
|
e48316231c | |
|
|
390b66aee8 | |
|
|
9d8d0647be | |
|
|
7b4c7028a0 | |
|
|
4d006f8e73 | |
|
|
536e54062e | |
|
|
dd75c702db | |
|
|
2a55748296 | |
|
|
1400bd80dd | |
|
|
14e3f85cb0 | |
|
|
9fc25b7109 | |
|
|
45bac49ec0 | |
|
|
b242b017c0 | |
|
|
cfd152addf | |
|
|
7618d58a66 | |
|
|
5c2a185ff9 | |
|
|
42566d1e86 | |
|
|
7141e431e2 | |
|
|
1b51926b19 | |
|
|
63c4dd1096 | |
|
|
b6ca1187b1 | |
|
|
89ee5d51ea | |
|
|
5b9acb4813 | |
|
|
0e979a9f67 | |
|
|
ce2cdc112f | |
|
|
1469d8bb3d | |
|
|
f86cd30af4 | |
|
|
5e937d797d | |
|
|
3a1f520dc6 | |
|
|
5e6b6bdd8e | |
|
|
53b96f87a0 | |
|
|
b7a13a0000 | |
|
|
6d5705b655 | |
|
|
8571a27a15 | |
|
|
cdcd200c7d | |
|
|
6232330c81 | |
|
|
418f0c4f52 | |
|
|
5bce60fd29 | |
|
|
beddbe7785 | |
|
|
2e65691737 | |
|
|
95cecc8870 | |
|
|
7a4300116e | |
|
|
51542e336b | |
|
|
7f33206057 | |
|
|
8e1430c1a4 | |
|
|
aafe5f12bc | |
|
|
9df6828255 | |
|
|
06e2ca3100 | |
|
|
fa9facfa0b | |
|
|
0cc2bff0f4 | |
|
|
192a118823 | |
|
|
d2e82b710b | |
|
|
bf79e07d5c | |
|
|
7c129c18c4 | |
|
|
01e0e8e37b | |
|
|
583b409fad | |
|
|
ffb69063b9 | |
|
|
5d0755eea9 | |
|
|
a698cb1635 | |
|
|
43372c05ad | |
|
|
a704620f84 | |
|
|
7fd0a24ca5 | |
|
|
e98d575b3a | |
|
|
d5a9e2e313 | |
|
|
fa27c27831 | |
|
|
f9c0cace70 | |
|
|
3146f64edc | |
|
|
2c3842582f | |
|
|
fbd8615398 | |
|
|
52fdf0bcab | |
|
|
43666dc56c | |
|
|
ef901b5381 | |
|
|
cfeee7bbb7 | |
|
|
1dfab43b8a | |
|
|
744229a02e | |
|
|
63c711f9e2 | |
|
|
82022b86de | |
|
|
f5656c8a2f | |
|
|
31dc1b1198 | |
|
|
3cc7ac7f8b | |
|
|
7ed6fa5579 | |
|
|
8564788b11 | |
|
|
92b1466597 | |
|
|
238862b572 | |
|
|
be654bce50 | |
|
|
d64a695673 | |
|
|
dfbae06afa | |
|
|
384a0c134a | |
|
|
9f1fc9ef78 | |
|
|
fd1ba30bdb | |
|
|
01fff53aaf | |
|
|
4b4c4fab11 | |
|
|
368b385267 | |
|
|
0ab8b292f2 | |
|
|
d19bdd42d5 | |
|
|
0c7d1f0df6 | |
|
|
a762dfff84 | |
|
|
4b64153044 | |
|
|
e90f9e5237 | |
|
|
de39bc7fc1 | |
|
|
f0fc144e8a | |
|
|
431a0bfb93 | |
|
|
ba34e4adc0 | |
|
|
29a03ef03d | |
|
|
122b1ba748 | |
|
|
56b0630847 | |
|
|
6ead932813 | |
|
|
9fc10b304c | |
|
|
4c8898b6f5 | |
|
|
9c5b11e551 | |
|
|
e9be6ef8b3 | |
|
|
29695b649a | |
|
|
8847cdb79f | |
|
|
bfa267120a | |
|
|
8fd21da555 | |
|
|
9e8d04249c | |
|
|
cb5d30e327 | |
|
|
ccc9aca21c | |
|
|
fc82ed3d7e | |
|
|
cba5c15604 | |
|
|
678c2d6834 | |
|
|
3ea04663f2 | |
|
|
a0ed0d800c | |
|
|
45a530e8c7 | |
|
|
6add0b0600 | |
|
|
7f84c428a5 | |
|
|
e85f8edcaa | |
|
|
115e0482db | |
|
|
a1a9053aaa | |
|
|
1a0c11f685 | |
|
|
e1b52be8ea | |
|
|
8790d6b128 | |
|
|
3a77001b42 | |
|
|
8a7991261f | |
|
|
1e02a40ec4 | |
|
|
9570f25cdc | |
|
|
d37af6d959 | |
|
|
802a10cf85 | |
|
|
a973406b2a | |
|
|
43771b0f47 | |
|
|
20c6631e7a | |
|
|
9a4e79e4ef | |
|
|
f1d44c8267 | |
|
|
969d8237ce | |
|
|
f929ebc184 | |
|
|
2c1ff59286 | |
|
|
e573462cb7 | |
|
|
8c1f17f5a6 | |
|
|
a35698fc07 | |
|
|
66514fc597 | |
|
|
2785e2bea6 | |
|
|
e30e30ea51 | |
|
|
505b3b5953 | |
|
|
a28694074e | |
|
|
d6f96a56a2 | |
|
|
68d3ad10d4 | |
|
|
5f16cd74e0 | |
|
|
6664afb851 | |
|
|
6d6515c06d | |
|
|
11495a64f5 | |
|
|
76be404c69 | |
|
|
9fb796194e | |
|
|
518851ce74 | |
|
|
14edd68d77 | |
|
|
968a1ccb40 | |
|
|
c163ed152c | |
|
|
2499d59f28 | |
|
|
176cddc21f | |
|
|
74128f53a5 | |
|
|
491e09c136 | |
|
|
5959539a03 | |
|
|
26c7544829 | |
|
|
c792f5fa0f | |
|
|
f497bf8e23 | |
|
|
eade6bd9a4 | |
|
|
91c97d7302 | |
|
|
27b3c36976 | |
|
|
bfcce06577 | |
|
|
dfee5b999d | |
|
|
9f19835a80 | |
|
|
ad376b24b4 | |
|
|
8cffb4a8ca | |
|
|
a997f25f98 | |
|
|
52e538aa43 | |
|
|
c4908548a1 | |
|
|
2520de56b4 | |
|
|
860d2c0b29 | |
|
|
53a1024c11 | |
|
|
037b465a64 | |
|
|
ac6097aa9a | |
|
|
cb5f0fb3f0 | |
|
|
49f0fb06f4 | |
|
|
c0845eae75 | |
|
|
e31423bc6d | |
|
|
5284b00706 | |
|
|
550c30eae4 | |
|
|
fd11e07e92 | |
|
|
f4b8fea579 | |
|
|
6ffcbbc1d2 | |
|
|
53f779afa2 | |
|
|
643eb92aff | |
|
|
7991028e0a | |
|
|
c0414a563f | |
|
|
7326634cd3 | |
|
|
81f00adae3 | |
|
|
136ef314b5 | |
|
|
c13d5d7dfd | |
|
|
b6f40353ad | |
|
|
dec43ffcee | |
|
|
3dad65a53f | |
|
|
9864cf5a92 | |
|
|
1b9fcc51a1 | |
|
|
80128c5406 | |
|
|
3314dfe365 | |
|
|
d599ca91c6 | |
|
|
5c1bb25237 | |
|
|
e5b90372a6 | |
|
|
5feb3e6815 | |
|
|
755bf1bb08 | |
|
|
0d347643ca | |
|
|
f3968db2e0 | |
|
|
90461a8cdf | |
|
|
d8d3366687 | |
|
|
90619542c8 | |
|
|
d2a212fb80 | |
|
|
aaba03d001 | |
|
|
5b8b51a894 | |
|
|
e3f8a3a94b |
|
|
@ -1,8 +0,0 @@
|
|||
/build/
|
||||
/config/
|
||||
/dist/
|
||||
/*.js
|
||||
/test/unit/coverage/
|
||||
/node_modules/*
|
||||
/dist*
|
||||
/src/main.ts
|
||||
75
.eslintrc.js
|
|
@ -1,75 +0,0 @@
|
|||
// @ts-check
|
||||
const { defineConfig } = require('eslint-define-config')
|
||||
module.exports = defineConfig({
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true
|
||||
},
|
||||
parser: 'vue-eslint-parser',
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser',
|
||||
ecmaVersion: 2020,
|
||||
sourceType: 'module',
|
||||
jsxPragma: 'React',
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
}
|
||||
},
|
||||
extends: [
|
||||
'plugin:vue/vue3-recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'prettier',
|
||||
'plugin:prettier/recommended',
|
||||
'@unocss'
|
||||
],
|
||||
rules: {
|
||||
'vue/no-setup-props-destructure': 'off',
|
||||
'vue/script-setup-uses-vars': 'error',
|
||||
'vue/no-reserved-component-names': 'off',
|
||||
'@typescript-eslint/ban-ts-ignore': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'vue/custom-event-name-casing': 'off',
|
||||
'no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/ban-types': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'space-before-function-paren': 'off',
|
||||
|
||||
'vue/attributes-order': 'off',
|
||||
'vue/one-component-per-file': 'off',
|
||||
'vue/html-closing-bracket-newline': 'off',
|
||||
'vue/max-attributes-per-line': 'off',
|
||||
'vue/multiline-html-element-content-newline': 'off',
|
||||
'vue/singleline-html-element-content-newline': 'off',
|
||||
'vue/attribute-hyphenation': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/require-explicit-emits': 'off',
|
||||
'vue/require-toggle-inside-transition': 'off',
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
void: 'always',
|
||||
normal: 'never',
|
||||
component: 'always'
|
||||
},
|
||||
svg: 'always',
|
||||
math: 'always'
|
||||
}
|
||||
],
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/no-v-html': 'off',
|
||||
'prettier/prettier': 'off', // 芋艿:默认关闭 prettier 的 ESLint 校验,因为我们使用的是 IDE 的 Prettier 插件
|
||||
'@unocss/order': 'off', // 芋艿:禁用 unocss 【css】顺序的提示,因为暂时不需要这么严格,警告也有点繁琐
|
||||
'@unocss/order-attributify': 'off' // 芋艿:禁用 unocss 【属性】顺序的提示,因为暂时不需要这么严格,警告也有点繁琐
|
||||
}
|
||||
})
|
||||
|
|
@ -7,3 +7,4 @@ pnpm-debug
|
|||
auto-*.d.ts
|
||||
.idea
|
||||
.history
|
||||
output/
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 169 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 216 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
|
@ -1,5 +1,7 @@
|
|||
{
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"typescript.tsdk": "./node_modules/typescript/lib",
|
||||
"volar.tsPlugin": true,
|
||||
"volar.tsPluginStatus": false,
|
||||
"npm.packageManager": "pnpm",
|
||||
"editor.tabSize": 2,
|
||||
"prettier.printWidth": 100, // 超过最大值换行
|
||||
|
|
@ -83,54 +85,75 @@
|
|||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.fixAll.stylelint": "explicit"
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"editor.formatOnSave": true,
|
||||
"[vue]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.fixAll.stylelint": "explicit"
|
||||
}
|
||||
},
|
||||
"i18n-ally.localesPaths": ["src/locales"],
|
||||
"i18n-ally.keystyle": "nested",
|
||||
"i18n-ally.sortKeys": true,
|
||||
"i18n-ally.namespace": false,
|
||||
"i18n-ally.namespace": true,
|
||||
"i18n-ally.enabledParsers": ["ts"],
|
||||
"i18n-ally.sourceLanguage": "en",
|
||||
"i18n-ally.displayLanguage": "zh-CN",
|
||||
"i18n-ally.enabledFrameworks": ["vue", "react"],
|
||||
"cSpell.words": [
|
||||
"brotli",
|
||||
"browserslist",
|
||||
"codemirror",
|
||||
"commitlint",
|
||||
"cropperjs",
|
||||
"echart",
|
||||
"echarts",
|
||||
"esnext",
|
||||
"esno",
|
||||
"iconify",
|
||||
"INTLIFY",
|
||||
"lintstagedrc",
|
||||
"logicflow",
|
||||
"nprogress",
|
||||
"pinia",
|
||||
"pnpm",
|
||||
"qrcode",
|
||||
"sider",
|
||||
"sortablejs",
|
||||
"stylelint",
|
||||
"svgs",
|
||||
"unocss",
|
||||
"unplugin",
|
||||
"unref",
|
||||
"videojs",
|
||||
"VITE",
|
||||
"vitejs",
|
||||
"vueuse",
|
||||
"wangeditor",
|
||||
"xingyu",
|
||||
"yudao",
|
||||
"zxcvbn"
|
||||
"unocss",
|
||||
"browserslist",
|
||||
"esnext",
|
||||
"unplugin",
|
||||
"qrcode",
|
||||
"sider",
|
||||
"pinia",
|
||||
"sider",
|
||||
"nprogress",
|
||||
"INTLIFY",
|
||||
"stylelint",
|
||||
"esno",
|
||||
"vitejs",
|
||||
"sortablejs",
|
||||
"codemirror",
|
||||
"iconify",
|
||||
"commitlint",
|
||||
"videojs",
|
||||
"echarts",
|
||||
"wangeditor",
|
||||
"cropperjs",
|
||||
"logicflow",
|
||||
"vueuse",
|
||||
"zxcvbn",
|
||||
"lintstagedrc",
|
||||
"brotli",
|
||||
"sider",
|
||||
"pnpm"
|
||||
],
|
||||
"vetur.format.scriptInitialIndent": true,
|
||||
"vetur.format.styleInitialIndent": true,
|
||||
"vetur.validation.script": false,
|
||||
"MicroPython.executeButton": [
|
||||
{
|
||||
"text": "▶",
|
||||
"tooltip": "运行",
|
||||
"alignment": "left",
|
||||
"command": "extension.executeFile",
|
||||
"priority": 3.5
|
||||
}
|
||||
],
|
||||
"MicroPython.syncButton": [
|
||||
{
|
||||
"text": "$(sync)",
|
||||
"tooltip": "同步",
|
||||
"alignment": "left",
|
||||
"command": "extension.execute",
|
||||
"priority": 4
|
||||
}
|
||||
],
|
||||
// 控制相关文件嵌套展示
|
||||
"explorer.fileNesting.enabled": true,
|
||||
|
|
@ -139,8 +162,7 @@
|
|||
"*.ts": "$(capture).test.ts, $(capture).test.tsx",
|
||||
"*.tsx": "$(capture).test.ts, $(capture).test.tsx",
|
||||
"*.env": "$(capture).env.*",
|
||||
"package.json": "pnpm-lock.yaml,yarn.lock,LICENSE,README*,CHANGELOG*,CNAME,.gitattributes,.eslintrc-auto-import.json,.gitignore,prettier.config.js,stylelint.config.js,commitlint.config.js,.stylelintignore,.prettierignore,.gitpod.yml,.eslintrc.js,.eslintignore"
|
||||
"package.json": "pnpm-lock.yaml,yarn.lock,LICENSE,README*,CHANGELOG*,CNAME,.gitattributes,.gitignore,prettier.config.js,stylelint.config.js,commitlint.config.js,.stylelintignore,.prettierignore,.gitpod.yml,.eslintrc.js,.eslintignore"
|
||||
},
|
||||
"terminal.integrated.scrollback": 10000,
|
||||
"nuxt.isNuxtApp": false
|
||||
"terminal.integrated.scrollback": 10000
|
||||
}
|
||||
|
|
|
|||
23
README.md
|
|
@ -87,7 +87,7 @@
|
|||
|
||||
* 通用模块(必选):系统功能、基础设施
|
||||
* 通用模块(可选):工作流程、支付系统、数据报表、会员中心
|
||||
* 业务系统(按需):ERP 系统、CRM 系统、MES 系统、商城系统、微信公众号、AI 大模型、IoT 物联网
|
||||
* 业务系统(按需):Mall 电子商城、OA 办公自动化、ERP 企业资源计划系统、WMS 仓库管理系统、CRM 客户关系管理、CMS 内容管理系统、MES 执行制造系统、AI 大模型平台、IoT 物联网系统、IM 即时通讯系统、Mobile 手机移动端、Report 数据大屏
|
||||
|
||||
### 系统功能
|
||||
|
||||
|
|
@ -238,6 +238,14 @@
|
|||
|
||||

|
||||
|
||||
### WMS 系统
|
||||
|
||||
演示地址:<https://doc.iocoder.cn/wms-preview/>
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### CRM 系统
|
||||
|
||||
演示地址:<https://doc.iocoder.cn/crm-preview/>
|
||||
|
|
@ -276,6 +284,19 @@
|
|||
|
||||

|
||||
|
||||
### IM 即时通讯
|
||||
|
||||
演示地址(Vue3 + Element Plus):<http://dashboard-vue3.yudao.iocoder.cn>
|
||||
|
||||
使用文档:<https://doc.iocoder.cn/im-preview/>
|
||||
|
||||
|
||||

|
||||
|
||||
| 聊天界面 | 聊天管理 |
|
||||
| --- | --- |
|
||||
|  |  |
|
||||
|
||||
## 🐷 演示图
|
||||
|
||||
### 系统功能
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import { resolve } from 'path'
|
|||
import Vue from '@vitejs/plugin-vue'
|
||||
import VueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import progress from 'vite-plugin-progress'
|
||||
import EslintPlugin from 'vite-plugin-eslint'
|
||||
import PurgeIcons from 'vite-plugin-purge-icons'
|
||||
import EslintPlugin from 'vite-plugin-eslint2'
|
||||
import { ViteEjsPlugin } from 'vite-plugin-ejs'
|
||||
// @ts-ignore
|
||||
import ElementPlus from 'unplugin-element-plus/vite'
|
||||
|
|
@ -29,7 +28,6 @@ export function createVitePlugins() {
|
|||
VueJsx(),
|
||||
UnoCSS(),
|
||||
progress(),
|
||||
PurgeIcons(),
|
||||
ElementPlus({}),
|
||||
AutoImport({
|
||||
include: [
|
||||
|
|
@ -64,7 +62,7 @@ export function createVitePlugins() {
|
|||
dts: 'src/types/auto-components.d.ts',
|
||||
// 自定义组件的解析器
|
||||
resolvers: [ElementPlusResolver()],
|
||||
globs: ["src/components/**/**.{vue, md}", '!src/components/DiyEditor/components/mobile/**']
|
||||
globs: ['src/components/**/**.{vue, md}', '!src/components/DiyEditor/components/mobile/**']
|
||||
}),
|
||||
EslintPlugin({
|
||||
cache: false,
|
||||
|
|
@ -77,7 +75,7 @@ export function createVitePlugins() {
|
|||
}),
|
||||
createSvgIconsPlugin({
|
||||
iconDirs: [pathResolve('src/assets/svgs')],
|
||||
symbolId: 'icon-[dir]-[name]',
|
||||
symbolId: 'icon-[dir]-[name]'
|
||||
}),
|
||||
viteCompression({
|
||||
verbose: true, // 是否在控制台输出压缩结果
|
||||
|
|
|
|||
|
|
@ -2,22 +2,18 @@ const include = [
|
|||
'qs',
|
||||
'url',
|
||||
'vue',
|
||||
'sass',
|
||||
'mitt',
|
||||
'axios',
|
||||
'pinia',
|
||||
'dayjs',
|
||||
'qrcode',
|
||||
'unocss',
|
||||
'vue-router',
|
||||
'vue-types',
|
||||
'vue-i18n',
|
||||
'crypto-js',
|
||||
'cropperjs',
|
||||
'lodash-es',
|
||||
'nprogress',
|
||||
'web-storage-cache',
|
||||
'@iconify/iconify',
|
||||
'@vueuse/core',
|
||||
'@zxcvbn-ts/core',
|
||||
'echarts/core',
|
||||
|
|
@ -91,18 +87,9 @@ const include = [
|
|||
'element-plus/es/components/dropdown-menu/style/css',
|
||||
'element-plus/es/components/dropdown-item/style/css',
|
||||
'element-plus/es/components/skeleton/style/css',
|
||||
'element-plus/es/components/skeleton/style/css',
|
||||
'element-plus/es/components/backtop/style/css',
|
||||
'element-plus/es/components/menu/style/css',
|
||||
'element-plus/es/components/sub-menu/style/css',
|
||||
'element-plus/es/components/menu-item/style/css',
|
||||
'element-plus/es/components/dropdown/style/css',
|
||||
'element-plus/es/components/skeleton-item/style/css',
|
||||
'element-plus/es/components/tree/style/css',
|
||||
'element-plus/es/components/dropdown-menu/style/css',
|
||||
'element-plus/es/components/dropdown-item/style/css',
|
||||
'element-plus/es/components/badge/style/css',
|
||||
'element-plus/es/components/breadcrumb/style/css',
|
||||
'element-plus/es/components/breadcrumb-item/style/css',
|
||||
'element-plus/es/components/image/style/css',
|
||||
'element-plus/es/components/collapse-transition/style/css',
|
||||
'element-plus/es/components/timeline/style/css',
|
||||
|
|
@ -119,6 +106,6 @@ const include = [
|
|||
'element-plus/es/components/progress/style/css'
|
||||
]
|
||||
|
||||
const exclude = ['@iconify/json']
|
||||
const exclude: string[] = []
|
||||
|
||||
export { include, exclude }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
import pluginVue from 'eslint-plugin-vue'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import unocss from '@unocss/eslint-config/flat'
|
||||
import autoImportGlobals from './.eslintrc-auto-import.json' with { type: 'json' }
|
||||
|
||||
export default tseslint.config(
|
||||
// Global ignores (replaces .eslintignore)
|
||||
{
|
||||
ignores: [
|
||||
'build/',
|
||||
'config/',
|
||||
'dist/',
|
||||
'dist*/',
|
||||
'*.js',
|
||||
'*.mjs',
|
||||
'!eslint.config.mjs',
|
||||
'test/unit/coverage/',
|
||||
'node_modules/',
|
||||
'src/main.ts',
|
||||
'src/types/auto-components.d.ts'
|
||||
]
|
||||
},
|
||||
|
||||
// Base TypeScript config
|
||||
...tseslint.configs.recommended,
|
||||
|
||||
// Vue recommended config
|
||||
...pluginVue.configs['flat/recommended'],
|
||||
|
||||
// UnoCSS config
|
||||
unocss,
|
||||
|
||||
// Vue files use vue-eslint-parser with TypeScript parser
|
||||
{
|
||||
files: ['**/*.vue'],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
parser: tseslint.parser
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Main rules config
|
||||
{
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
sourceType: 'module',
|
||||
globals: {
|
||||
...autoImportGlobals.globals
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true
|
||||
}
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
// Vue rules
|
||||
'vue/no-reserved-component-names': 'off',
|
||||
'vue/custom-event-name-casing': 'off',
|
||||
'vue/attributes-order': 'off',
|
||||
'vue/one-component-per-file': 'off',
|
||||
'vue/html-closing-bracket-newline': 'off',
|
||||
'vue/max-attributes-per-line': 'off',
|
||||
'vue/multiline-html-element-content-newline': 'off',
|
||||
'vue/singleline-html-element-content-newline': 'off',
|
||||
'vue/attribute-hyphenation': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/require-explicit-emits': 'off',
|
||||
'vue/require-toggle-inside-transition': 'off',
|
||||
'vue/html-self-closing': [
|
||||
'error',
|
||||
{
|
||||
html: {
|
||||
void: 'always',
|
||||
normal: 'never',
|
||||
component: 'always'
|
||||
},
|
||||
svg: 'always',
|
||||
math: 'always'
|
||||
}
|
||||
],
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/no-v-html': 'off',
|
||||
|
||||
// TypeScript rules
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'off',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'off',
|
||||
'@typescript-eslint/no-wrapper-object-types': 'off',
|
||||
'@typescript-eslint/no-this-alias': 'off',
|
||||
'@typescript-eslint/no-empty-object-type': 'off',
|
||||
'vue/no-ref-as-operand': 'off',
|
||||
'vue/no-mutating-props': 'off',
|
||||
'vue/no-side-effects-in-computed-properties': 'off',
|
||||
'no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
'space-before-function-paren': 'off',
|
||||
|
||||
// UnoCSS rules - 芋艿:禁用 unocss 顺序提示
|
||||
'@unocss/order': 'off',
|
||||
'@unocss/order-attributify': 'off',
|
||||
'unocss/order': 'off',
|
||||
'unocss/order-attributify': 'off'
|
||||
}
|
||||
}
|
||||
)
|
||||
191
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "yudao-ui-admin-vue3",
|
||||
"version": "2026.03-snapshot",
|
||||
"version": "2026.05-snapshot",
|
||||
"description": "基于vue3、vite4、element-plus、typesScript",
|
||||
"author": "xingyu",
|
||||
"private": false,
|
||||
|
|
@ -8,143 +8,138 @@
|
|||
"i": "pnpm install",
|
||||
"dev": "vite --mode env.local",
|
||||
"dev-server": "vite --mode dev",
|
||||
"ts:check": "vue-tsc --noEmit",
|
||||
"build:local": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build",
|
||||
"build:dev": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode dev",
|
||||
"build:test": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode test",
|
||||
"build:stage": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode stage",
|
||||
"build:prod": "node --max_old_space_size=4096 ./node_modules/vite/bin/vite.js build --mode prod",
|
||||
"ts:check": "node --max_old_space_size=8192 ./node_modules/vue-tsc/bin/vue-tsc.js --noEmit",
|
||||
"build:local": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode env.local",
|
||||
"build:dev": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode dev",
|
||||
"build:test": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode test",
|
||||
"build:stage": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode stage",
|
||||
"build:prod": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode prod",
|
||||
"serve:dev": "vite preview --mode dev",
|
||||
"serve:prod": "vite preview --mode prod",
|
||||
"preview": "pnpm build:local && vite preview",
|
||||
"clean": "npx rimraf node_modules",
|
||||
"clean:cache": "npx rimraf node_modules/.cache",
|
||||
"lint:eslint": "eslint --fix --ext .js,.ts,.vue ./src",
|
||||
"lint:eslint": "eslint --fix ./src",
|
||||
"lint:format": "prettier --write --loglevel warn \"src/**/*.{js,ts,json,tsx,css,less,scss,vue,html,md}\"",
|
||||
"lint:style": "stylelint --fix \"./src/**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||
"lint:lint-staged": "lint-staged -c "
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "2.3.2",
|
||||
"@form-create/designer": "^3.2.6",
|
||||
"@form-create/element-ui": "^3.2.11",
|
||||
"@iconify/iconify": "^3.1.1",
|
||||
"@form-create/designer": "^3.4.0",
|
||||
"@form-create/element-ui": "^3.2.38",
|
||||
"@iconify/vue": "^5.0.1",
|
||||
"@microsoft/fetch-event-source": "^2.0.1",
|
||||
"@videojs-player/vue": "^1.0.0",
|
||||
"@vueuse/core": "^10.9.0",
|
||||
"@wangeditor-next/editor": "^5.6.46",
|
||||
"@vueuse/core": "^14.3.0",
|
||||
"@wangeditor-next/editor": "^5.7.0",
|
||||
"@wangeditor-next/editor-for-vue": "^5.1.14",
|
||||
"@wangeditor-next/plugin-mention": "^1.0.16",
|
||||
"@wangeditor-next/plugin-mention": "^2.0.0",
|
||||
"@zxcvbn-ts/core": "^3.0.4",
|
||||
"animate.css": "^4.1.1",
|
||||
"axios": "1.9.0",
|
||||
"axios": "1.16.0",
|
||||
"benz-amr-recorder": "^1.1.5",
|
||||
"bpmn-js-token-simulation": "^0.36.0",
|
||||
"bpmn-js-token-simulation": "^0.39.3",
|
||||
"camunda-bpmn-moddle": "^7.0.1",
|
||||
"cropperjs": "^1.6.1",
|
||||
"cropperjs": "^2.1.1",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"dayjs": "^1.11.20",
|
||||
"dayjs-plugin-lunar": "^1.4.1",
|
||||
"dhtmlx-gantt": "^9.1.1",
|
||||
"diagram-js": "^12.8.0",
|
||||
"driver.js": "^1.3.1",
|
||||
"echarts": "^5.5.0",
|
||||
"diagram-js": "^15.14.0",
|
||||
"driver.js": "^1.4.0",
|
||||
"echarts": "^6.0.0",
|
||||
"echarts-wordcloud": "^2.1.0",
|
||||
"element-plus": "2.11.1",
|
||||
"element-plus": "2.13.7",
|
||||
"fast-xml-parser": "^4.3.2",
|
||||
"highlight.js": "^11.9.0",
|
||||
"highlight.js": "^11.11.1",
|
||||
"jsbarcode": "^3.12.3",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"jsoneditor": "^10.1.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"markdown-it": "^14.1.0",
|
||||
"markmap-common": "^0.16.0",
|
||||
"markmap-lib": "^0.16.1",
|
||||
"markmap-toolbar": "^0.17.0",
|
||||
"markmap-view": "^0.16.0",
|
||||
"min-dash": "^4.1.1",
|
||||
"jsencrypt": "^3.5.4",
|
||||
"jsoneditor": "^10.4.3",
|
||||
"livekit-client": "^2.18.9",
|
||||
"lodash-es": "^4.18.1",
|
||||
"markdown-it": "^14.1.1",
|
||||
"markmap-common": "^0.18.9",
|
||||
"markmap-lib": "^0.18.12",
|
||||
"markmap-toolbar": "^0.18.12",
|
||||
"markmap-view": "^0.18.12",
|
||||
"min-dash": "^5.0.0",
|
||||
"mitt": "^3.0.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"pinia": "^2.1.7",
|
||||
"pinia-plugin-persistedstate": "^3.2.1",
|
||||
"qrcode": "^1.5.3",
|
||||
"qs": "^6.12.0",
|
||||
"snabbdom": "^3.6.2",
|
||||
"sortablejs": "^1.15.3",
|
||||
"pinia": "^3.0.4",
|
||||
"pinia-plugin-persistedstate": "^4.7.1",
|
||||
"qrcode": "^1.5.4",
|
||||
"qs": "^6.15.1",
|
||||
"snabbdom": "^3.6.3",
|
||||
"sortablejs": "^1.15.7",
|
||||
"steady-xml": "^0.1.0",
|
||||
"tyme4ts": "^1.4.6",
|
||||
"url": "^0.11.3",
|
||||
"video.js": "^7.21.5",
|
||||
"vue": "3.5.12",
|
||||
"vue-dompurify-html": "^4.1.4",
|
||||
"vue-i18n": "9.10.2",
|
||||
"vue-router": "4.4.5",
|
||||
"vue-types": "^5.1.1",
|
||||
"url": "^0.11.4",
|
||||
"video.js": "^8.23.8",
|
||||
"vue": "3.5.34",
|
||||
"vue-dompurify-html": "^5.3.0",
|
||||
"vue-i18n": "11.4.0",
|
||||
"vue-router": "5.0.6",
|
||||
"vue-types": "^6.0.0",
|
||||
"vue3-print-nb": "^0.1.4",
|
||||
"vue3-signature": "^0.2.4",
|
||||
"vue3-signature": "^0.4.4",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"web-storage-cache": "^1.1.1",
|
||||
"xml-js": "^1.6.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^19.0.1",
|
||||
"@commitlint/config-conventional": "^19.0.0",
|
||||
"@iconify/json": "^2.2.187",
|
||||
"@intlify/unplugin-vue-i18n": "^2.0.0",
|
||||
"@purge-icons/generated": "^0.9.0",
|
||||
"@types/jsoneditor": "^9.9.5",
|
||||
"@commitlint/cli": "^20.5.3",
|
||||
"@commitlint/config-conventional": "^20.5.3",
|
||||
"@iconify/json": "^2.2.470",
|
||||
"@intlify/unplugin-vue-i18n": "^11.1.2",
|
||||
"@types/jsoneditor": "^9.9.6",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^20.11.21",
|
||||
"@types/node": "^25.6.0",
|
||||
"@types/nprogress": "^0.2.3",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@types/qs": "^6.9.12",
|
||||
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
"@unocss/eslint-config": "^0.57.4",
|
||||
"@unocss/eslint-plugin": "66.1.0-beta.5",
|
||||
"@unocss/transformer-variant-group": "^0.58.5",
|
||||
"@vitejs/plugin-legacy": "^5.3.1",
|
||||
"@vitejs/plugin-vue": "^5.0.4",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"bpmn-js": "^17.9.2",
|
||||
"bpmn-js-properties-panel": "5.23.0",
|
||||
"consola": "^3.2.3",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-define-config": "^2.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-vue": "^9.22.0",
|
||||
"lint-staged": "^15.2.2",
|
||||
"postcss": "^8.4.35",
|
||||
"postcss-html": "^1.6.0",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"@types/qs": "^6.15.0",
|
||||
"@unocss/eslint-config": "^66.6.8",
|
||||
"@unocss/eslint-plugin": "66.6.8",
|
||||
"@unocss/transformer-variant-group": "^66.6.8",
|
||||
"@vitejs/plugin-legacy": "^8.0.1",
|
||||
"@vitejs/plugin-vue": "^6.0.6",
|
||||
"@vitejs/plugin-vue-jsx": "^5.1.5",
|
||||
"autoprefixer": "^10.5.0",
|
||||
"bpmn-js": "^18.16.1",
|
||||
"bpmn-js-properties-panel": "5.54.0",
|
||||
"consola": "^3.4.2",
|
||||
"eslint": "^10.3.0",
|
||||
"eslint-plugin-vue": "^10.9.1",
|
||||
"lint-staged": "^16.4.0",
|
||||
"postcss": "^8.5.14",
|
||||
"postcss-html": "^1.8.1",
|
||||
"postcss-scss": "^4.0.9",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-eslint": "^16.3.0",
|
||||
"rimraf": "^5.0.5",
|
||||
"rollup": "^4.12.0",
|
||||
"sass": "^1.69.5",
|
||||
"stylelint": "^16.2.1",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier-eslint": "^16.4.2",
|
||||
"rimraf": "^6.1.3",
|
||||
"rollup": "^4.60.3",
|
||||
"sass": "^1.99.0",
|
||||
"stylelint": "^17.11.0",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-recommended": "^14.0.0",
|
||||
"stylelint-config-standard": "^36.0.0",
|
||||
"stylelint-order": "^6.0.4",
|
||||
"terser": "^5.28.1",
|
||||
"typescript": "5.3.3",
|
||||
"unocss": "^0.58.5",
|
||||
"unplugin-auto-import": "^0.16.7",
|
||||
"unplugin-element-plus": "^0.8.0",
|
||||
"unplugin-vue-components": "^0.25.2",
|
||||
"vite": "5.1.4",
|
||||
"stylelint-config-recommended": "^18.0.0",
|
||||
"stylelint-config-standard": "^40.0.0",
|
||||
"stylelint-order": "^8.1.1",
|
||||
"terser": "^5.46.2",
|
||||
"typescript": "6.0.3",
|
||||
"typescript-eslint": "^8.59.2",
|
||||
"unocss": "^66.6.8",
|
||||
"unplugin-auto-import": "^21.0.0",
|
||||
"unplugin-element-plus": "^0.11.2",
|
||||
"unplugin-vue-components": "^32.0.0",
|
||||
"vite": "8.0.10",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vite-plugin-ejs": "^1.7.0",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vite-plugin-eslint2": "^5.1.0",
|
||||
"vite-plugin-progress": "^0.0.7",
|
||||
"vite-plugin-purge-icons": "^0.10.0",
|
||||
"vite-plugin-svg-icons-ng": "^1.3.1",
|
||||
"vite-plugin-top-level-await": "^1.4.4",
|
||||
"vue-eslint-parser": "^9.3.2",
|
||||
"vue-tsc": "^1.8.27"
|
||||
"vite-plugin-svg-icons-ng": "^1.9.0",
|
||||
"vite-plugin-top-level-await": "^1.6.0",
|
||||
"vue-eslint-parser": "^10.4.0",
|
||||
"vue-tsc": "^3.2.8"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
@ -157,7 +152,7 @@
|
|||
"homepage": "https://gitee.com/yudaocode/yudao-ui-admin-vue3",
|
||||
"web-types": "./web-types.json",
|
||||
"engines": {
|
||||
"node": ">= 16.0.0",
|
||||
"node": ">= 20.19.0",
|
||||
"pnpm": ">=8.6.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
11037
pnpm-lock.yaml
|
|
@ -0,0 +1,18 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// 用户端能看到的频道素材详情
|
||||
export interface ImChannelMaterialRespVO {
|
||||
id: number
|
||||
channelId: number
|
||||
type: number
|
||||
title: string
|
||||
coverUrl?: string
|
||||
summary?: string
|
||||
content?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
// 获取频道素材详情;用于客户端点击图文卡片渲染详情页
|
||||
export const getChannelMaterial = (id: number) => {
|
||||
return request.get<ImChannelMaterialRespVO>({ url: '/im/channel/material/get', params: { id } })
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// 用户端表情包项(精简版)
|
||||
export interface ImFacePackUserItemVO {
|
||||
id: number
|
||||
url: string
|
||||
name?: string
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
// 用户端表情包 + 嵌套 items
|
||||
export interface ImFacePackUserVO {
|
||||
id: number
|
||||
name: string
|
||||
icon?: string
|
||||
items: ImFacePackUserItemVO[]
|
||||
}
|
||||
|
||||
// 拉取所有启用的系统表情包(含表情列表)
|
||||
export const getFacePackList = () => {
|
||||
return request.get<ImFacePackUserVO[]>({ url: '/im/face-pack/list' })
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// 个人表情
|
||||
export interface ImFaceUserItemVO {
|
||||
id: number
|
||||
url: string
|
||||
name?: string
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
// 添加个人表情请求
|
||||
export interface ImFaceUserItemSaveReqVO {
|
||||
url: string
|
||||
name?: string
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
// 获取我的个人表情列表
|
||||
export const getFaceUserItemList = () => {
|
||||
return request.get<ImFaceUserItemVO[]>({ url: '/im/face-user-item/list' })
|
||||
}
|
||||
|
||||
// 添加个人表情
|
||||
export const createFaceUserItem = (data: ImFaceUserItemSaveReqVO) => {
|
||||
return request.post<number>({ url: '/im/face-user-item/create', data })
|
||||
}
|
||||
|
||||
// 删除个人表情
|
||||
export const deleteFaceUserItem = (id: number) => {
|
||||
return request.delete({ url: '/im/face-user-item/delete', params: { id } })
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// IM 好友 Response VO
|
||||
export interface ImFriendRespVO {
|
||||
id: number // 关系记录编号
|
||||
friendUserId: number // 好友的用户编号
|
||||
silent?: boolean // 是否免打扰
|
||||
displayName?: string // 好友展示备注(仅自己可见)
|
||||
displayNamePinyin?: string // 备注的拼音(小写无空格,前端按首字母分桶 / 拼音搜索)
|
||||
addSource?: number // 添加来源;参见 ImFriendAddSourceEnum
|
||||
pinned?: boolean // 是否置顶联系人
|
||||
blocked?: boolean // 是否拉黑
|
||||
status?: number // 好友状态(0=正常,1=已删除)
|
||||
addTime?: string // 添加好友时间
|
||||
deleteTime?: string // 删除好友时间
|
||||
// 聚合字段(自 AdminUser)
|
||||
nickname?: string // 好友昵称
|
||||
nicknamePinyin?: string // 昵称的拼音(小写无空格,前端按首字母分桶 / 拼音搜索)
|
||||
avatar?: string // 好友头像
|
||||
}
|
||||
|
||||
// IM 好友更新 Request VO
|
||||
export interface ImFriendUpdateReqVO {
|
||||
friendUserId: number // 好友的用户编号
|
||||
silent?: boolean // 是否免打扰
|
||||
displayName?: string // 好友展示备注
|
||||
pinned?: boolean // 是否置顶联系人
|
||||
}
|
||||
|
||||
// 获得当前登录用户的好友列表
|
||||
export const getMyFriendList = () => {
|
||||
return request.get<ImFriendRespVO[]>({ url: '/im/friend/list' })
|
||||
}
|
||||
|
||||
// 获得好友详情
|
||||
export const getFriend = (friendUserId: number | string) => {
|
||||
return request.get<ImFriendRespVO>({ url: '/im/friend/get', params: { friendUserId } })
|
||||
}
|
||||
|
||||
// 删除好友(单向软删除)
|
||||
export const deleteFriend = (friendUserId: number | string, clear: boolean) => {
|
||||
return request.delete<boolean>({
|
||||
url: '/im/friend/delete',
|
||||
params: { friendUserId, clear }
|
||||
})
|
||||
}
|
||||
|
||||
// 更新好友信息(备注 / 免打扰 / 联系人置顶)
|
||||
export const updateFriend = (data: ImFriendUpdateReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/friend/update', data })
|
||||
}
|
||||
|
||||
// 拉黑好友(必须先是好友;单边屏蔽对方私聊消息)
|
||||
export const blockFriend = (friendUserId: number | string) => {
|
||||
return request.put<boolean>({ url: '/im/friend/block', params: { friendUserId } })
|
||||
}
|
||||
|
||||
// 移出黑名单
|
||||
export const unblockFriend = (friendUserId: number | string) => {
|
||||
return request.put<boolean>({ url: '/im/friend/unblock', params: { friendUserId } })
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// IM 好友申请 Response VO
|
||||
export interface ImFriendRequestRespVO {
|
||||
id: number // 申请编号
|
||||
fromUserId: number // 发起方用户编号
|
||||
toUserId: number // 接收方用户编号
|
||||
handleResult: number // 处理结果;0=未处理;1=同意;2=拒绝
|
||||
applyContent?: string // 申请理由
|
||||
handleContent?: string // 处理理由(接收方拒绝时可选填)
|
||||
addSource?: number // 添加来源;参见 ImFriendAddSourceEnum
|
||||
handleTime?: string // 处理时间
|
||||
createTime: string // 申请创建时间
|
||||
// 聚合字段(自 AdminUser)
|
||||
fromNickname?: string // 发起方昵称
|
||||
fromAvatar?: string // 发起方头像
|
||||
toNickname?: string // 接收方昵称
|
||||
toAvatar?: string // 接收方头像
|
||||
}
|
||||
|
||||
// IM 好友申请发起 Request VO
|
||||
export interface ImFriendRequestApplyReqVO {
|
||||
toUserId: number // 接收方用户编号
|
||||
applyContent?: string // 申请理由
|
||||
displayName?: string // 对接收方的备注(仅自己可见)
|
||||
addSource?: number // 添加来源
|
||||
}
|
||||
|
||||
// 发起好友申请
|
||||
export const applyFriendRequest = (data: ImFriendRequestApplyReqVO) => {
|
||||
return request.post<number | null>({ url: '/im/friend-request/apply', data })
|
||||
}
|
||||
|
||||
// 同意好友申请
|
||||
export const agreeFriendRequest = (id: number | string) => {
|
||||
return request.put<boolean>({ url: '/im/friend-request/agree', params: { id } })
|
||||
}
|
||||
|
||||
// 拒绝好友申请
|
||||
export const refuseFriendRequest = (id: number | string, handleContent?: string) => {
|
||||
return request.put<boolean>({
|
||||
url: '/im/friend-request/refuse',
|
||||
params: { id, handleContent }
|
||||
})
|
||||
}
|
||||
|
||||
// 查询「我相关」的好友申请列表(游标分页:传 maxId 加载更多)
|
||||
export const getMyFriendRequestList = (limit: number, maxId?: number) => {
|
||||
const params: Record<string, number> = { limit }
|
||||
if (maxId != null) {
|
||||
params.maxId = maxId
|
||||
}
|
||||
return request.get<ImFriendRequestRespVO[]>({
|
||||
url: '/im/friend-request/list',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 按 id 单查「我相关」的申请记录(带越权过滤;WebSocket 通知到达后用)
|
||||
export const getMyFriendRequest = (id: number) => {
|
||||
return request.get<ImFriendRequestRespVO | null>({
|
||||
url: '/im/friend-request/get',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
import request from '@/config/axios'
|
||||
import type { ImGroupMessageRespVO } from '@/api/im/message/group'
|
||||
|
||||
// 群 Response VO
|
||||
export interface ImGroupRespVO {
|
||||
id: number // 编号
|
||||
name: string // 群名称
|
||||
ownerUserId: number // 群主用户编号
|
||||
avatar?: string // 群头像
|
||||
notice?: string // 群公告
|
||||
banned?: boolean // 是否封禁
|
||||
mutedAll?: boolean // 是否全群禁言
|
||||
joinApproval?: boolean // 进群是否需群主 / 管理员审批
|
||||
bannedTime?: string // 封禁时间
|
||||
status: number // 群状态(0=正常,1=已解散)
|
||||
dissolvedTime?: string // 解散时间
|
||||
createTime?: string // 创建时间
|
||||
pinnedMessages?: ImGroupMessageRespVO[] // 群置顶消息列表(后端关联回填,仅当登录用户是群成员时非空)
|
||||
}
|
||||
|
||||
// 群消息置顶 / 取消置顶 Request VO
|
||||
export interface ImGroupMessagePinReqVO {
|
||||
id: number // 群编号
|
||||
messageId: number // 消息编号
|
||||
}
|
||||
|
||||
// 群创建 Request VO
|
||||
export interface ImGroupCreateReqVO {
|
||||
name: string // 群名称
|
||||
memberUserIds?: number[] // 初始成员用户编号列表(建群同时邀请的好友,不含创建者自己)
|
||||
joinApproval?: boolean // 进群是否需审批;不传默认 false 自由进群
|
||||
}
|
||||
|
||||
// 群更新 Request VO
|
||||
export interface ImGroupUpdateReqVO {
|
||||
id: number // 群编号
|
||||
name?: string // 群名称
|
||||
avatar?: string // 群头像
|
||||
notice?: string // 群公告
|
||||
joinApproval?: boolean // 进群是否需审批
|
||||
}
|
||||
|
||||
// 添加 / 撤销群管理员 Request VO
|
||||
export interface ImGroupAdminReqVO {
|
||||
id: number // 群编号
|
||||
userIds: number[] // 目标用户编号列表
|
||||
}
|
||||
|
||||
// 群主转让 Request VO
|
||||
export interface ImGroupTransferOwnerReqVO {
|
||||
id: number // 群编号
|
||||
newOwnerUserId: number // 新群主用户编号
|
||||
}
|
||||
|
||||
// 全群禁言 / 取消 Request VO
|
||||
export interface ImGroupMuteAllReqVO {
|
||||
id: number // 群编号
|
||||
mutedAll: boolean // 是否全群禁言
|
||||
}
|
||||
|
||||
// 成员禁言 Request VO
|
||||
export interface ImGroupMuteMemberReqVO {
|
||||
id: number // 群编号
|
||||
userId: number // 被禁言的用户编号
|
||||
mutedSeconds: number // 禁言时长(秒),0 表示永久禁言
|
||||
}
|
||||
|
||||
// 取消成员禁言 Request VO
|
||||
export interface ImGroupCancelMuteMemberReqVO {
|
||||
id: number // 群编号
|
||||
userId: number // 被取消禁言的用户编号
|
||||
}
|
||||
|
||||
// 获得当前登录用户的群列表
|
||||
export const getMyGroupList = () => {
|
||||
return request.get<ImGroupRespVO[]>({ url: '/im/group/list' })
|
||||
}
|
||||
|
||||
// 获得群详情
|
||||
export const getGroup = (id: number | string) => {
|
||||
return request.get<ImGroupRespVO>({ url: '/im/group/get', params: { id } })
|
||||
}
|
||||
|
||||
// 创建群
|
||||
export const createGroup = (data: ImGroupCreateReqVO) => {
|
||||
return request.post<ImGroupRespVO>({ url: '/im/group/create', data })
|
||||
}
|
||||
|
||||
// 更新群
|
||||
export const updateGroup = (data: ImGroupUpdateReqVO) => {
|
||||
return request.put<ImGroupRespVO>({ url: '/im/group/update', data })
|
||||
}
|
||||
|
||||
// 解散群
|
||||
export const dissolveGroup = (id: number | string) => {
|
||||
return request.delete<boolean>({ url: '/im/group/dissolve', params: { id } })
|
||||
}
|
||||
|
||||
// 添加群管理员(仅群主可调)
|
||||
export const addGroupAdmin = (data: ImGroupAdminReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/group/add-admin', data })
|
||||
}
|
||||
|
||||
// 撤销群管理员(仅群主可调)
|
||||
export const removeGroupAdmin = (data: ImGroupAdminReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/group/remove-admin', data })
|
||||
}
|
||||
|
||||
// 转让群主(仅老群主可调;旧群主转让后降为普通成员)
|
||||
export const transferGroupOwner = (data: ImGroupTransferOwnerReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/group/transfer-owner', data })
|
||||
}
|
||||
|
||||
// 置顶群消息(仅群主 / 管理员可调)
|
||||
export const pinGroupMessage = (data: ImGroupMessagePinReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/group/pin-message', data })
|
||||
}
|
||||
|
||||
// 取消置顶群消息(仅群主 / 管理员可调)
|
||||
export const unpinGroupMessage = (data: ImGroupMessagePinReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/group/unpin-message', data })
|
||||
}
|
||||
|
||||
// 全群禁言 / 取消(仅群主 / 管理员可调)
|
||||
export const muteAll = (data: ImGroupMuteAllReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/group/mute-all', data })
|
||||
}
|
||||
|
||||
// 禁言成员
|
||||
export const muteMember = (data: ImGroupMuteMemberReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/group/mute-member', data })
|
||||
}
|
||||
|
||||
// 取消成员禁言
|
||||
export const cancelMuteMember = (data: ImGroupCancelMuteMemberReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/group/cancel-mute-member', data })
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// 群成员 Response VO
|
||||
export interface ImGroupMemberRespVO {
|
||||
id: number // 编号
|
||||
groupId: number // 群编号
|
||||
userId: number // 用户编号
|
||||
displayUserName?: string // 组内显示名(群主设置的备注)
|
||||
groupRemark?: string // 群备注(当前用户对群的备注)
|
||||
silent?: boolean // 是否免打扰
|
||||
status?: number // 成员状态(0=在群,1=退群)
|
||||
role?: number // 成员角色,参见 ImGroupMemberRole 枚举
|
||||
joinTime?: string // 入群时间
|
||||
quitTime?: string // 退群时间
|
||||
muteEndTime?: string // 禁言到期时间
|
||||
createTime?: string // 创建时间
|
||||
// 聚合字段(自 AdminUser)
|
||||
nickname?: string // 用户昵称
|
||||
avatar?: string // 用户头像
|
||||
}
|
||||
|
||||
// 群成员邀请 Request VO
|
||||
export interface ImGroupMemberInviteReqVO {
|
||||
groupId: number // 群编号
|
||||
memberUserIds: number[] // 被邀请的用户编号列表
|
||||
}
|
||||
|
||||
// 群成员移除 Request VO
|
||||
export interface ImGroupMemberRemoveReqVO {
|
||||
groupId: number // 群编号
|
||||
memberUserIds: number[] // 被移除的用户编号列表
|
||||
}
|
||||
|
||||
// 群成员更新 Request VO
|
||||
export interface ImGroupMemberUpdateReqVO {
|
||||
groupId: number // 群编号
|
||||
displayUserName?: string // 群内昵称
|
||||
groupRemark?: string // 群备注
|
||||
silent?: boolean // 是否免打扰
|
||||
}
|
||||
|
||||
// 邀请用户加入群
|
||||
export const inviteGroupMember = (data: ImGroupMemberInviteReqVO) => {
|
||||
return request.post<boolean>({ url: '/im/group/invite', data })
|
||||
}
|
||||
|
||||
// 退出群
|
||||
export const quitGroup = (groupId: number | string) => {
|
||||
return request.delete<boolean>({ url: '/im/group/quit', params: { groupId } })
|
||||
}
|
||||
|
||||
// 移除群成员
|
||||
export const removeGroupMember = (data: ImGroupMemberRemoveReqVO) => {
|
||||
return request.delete<boolean>({ url: '/im/group/kicking', data })
|
||||
}
|
||||
|
||||
// 获得群成员详情
|
||||
export const getGroupMember = (groupId: number, userId: number) => {
|
||||
return request.get<ImGroupMemberRespVO>({
|
||||
url: '/im/group-member/get',
|
||||
params: { groupId, userId }
|
||||
})
|
||||
}
|
||||
|
||||
// 获得指定群的成员列表(聚合 AdminUser 昵称 / 头像)
|
||||
export const getGroupMemberList = (groupId: number | string) => {
|
||||
return request.get<ImGroupMemberRespVO[]>({
|
||||
url: '/im/group-member/list',
|
||||
params: { groupId }
|
||||
})
|
||||
}
|
||||
|
||||
// 更新群成员
|
||||
export const updateGroupMember = (data: ImGroupMemberUpdateReqVO) => {
|
||||
return request.put<boolean>({ url: '/im/group-member/update', data })
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// IM 加群申请 Response VO
|
||||
export interface ImGroupRequestRespVO {
|
||||
id: number // 申请编号
|
||||
groupId: number // 群编号
|
||||
userId: number // 申请人 / 被邀请人用户编号
|
||||
inviterUserId?: number // 邀请人;NULL 表示用户主动申请
|
||||
handleResult: number // 处理结果;0=未处理;1=同意;2=拒绝
|
||||
applyContent?: string // 申请理由
|
||||
handleContent?: string // 处理理由(拒绝时可选填)
|
||||
handleUserId?: number // 处理人用户编号
|
||||
addSource?: number // 加入来源;参见 ImGroupAddSourceEnum
|
||||
handleTime?: string // 处理时间
|
||||
createTime: string // 申请创建时间
|
||||
// 聚合字段
|
||||
userNickname?: string // 申请人 / 被邀请人昵称
|
||||
userAvatar?: string // 申请人 / 被邀请人头像
|
||||
inviterNickname?: string // 邀请人昵称
|
||||
inviterAvatar?: string // 邀请人头像
|
||||
groupName?: string // 群名称
|
||||
groupAvatar?: string // 群头像
|
||||
}
|
||||
|
||||
// IM 加群申请发起 Request VO
|
||||
export interface ImGroupRequestApplyReqVO {
|
||||
groupId: number // 群编号
|
||||
applyContent?: string // 申请理由
|
||||
addSource?: number // 加入来源
|
||||
}
|
||||
|
||||
// 申请加群
|
||||
export const applyJoinGroup = (data: ImGroupRequestApplyReqVO) => {
|
||||
return request.post<number | null>({ url: '/im/group-request/apply', data })
|
||||
}
|
||||
|
||||
// 同意加群申请(群主或管理员)
|
||||
export const agreeGroupRequest = (id: number | string) => {
|
||||
return request.put<boolean>({ url: '/im/group-request/agree', params: { id } })
|
||||
}
|
||||
|
||||
// 拒绝加群申请(群主或管理员)
|
||||
export const refuseGroupRequest = (id: number | string, handleContent?: string) => {
|
||||
return request.put<boolean>({
|
||||
url: '/im/group-request/refuse',
|
||||
params: { id, handleContent }
|
||||
})
|
||||
}
|
||||
|
||||
// 查询「我管理的所有群」下的未处理加群申请列表(不分页);前端 store 据此派生横幅红点 + Drawer 列表
|
||||
export const getUnhandledRequestList = () => {
|
||||
return request.get<ImGroupRequestRespVO[]>({
|
||||
url: '/im/group-request/unhandled-list'
|
||||
})
|
||||
}
|
||||
|
||||
// 查询指定群下的全部加群申请(含已处理);仅群主 / 管理员可查
|
||||
export const getGroupRequestListByGroupId = (groupId: number) => {
|
||||
return request.get<ImGroupRequestRespVO[]>({
|
||||
url: '/im/group-request/list-by-group',
|
||||
params: { groupId }
|
||||
})
|
||||
}
|
||||
|
||||
// 按 id 单查申请记录(带越权过滤;WebSocket 通知到达后用)
|
||||
export const getMyGroupRequest = (id: number) => {
|
||||
return request.get<ImGroupRequestRespVO | null>({
|
||||
url: '/im/group-request/get',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerChannelVO {
|
||||
id: number
|
||||
code: string
|
||||
name: string
|
||||
avatar?: string
|
||||
sort: number
|
||||
status: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// 获得频道分页
|
||||
export const getManagerChannelPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/channel/page', params })
|
||||
}
|
||||
|
||||
// 获得频道详情
|
||||
export const getManagerChannel = (id: number) => {
|
||||
return request.get({ url: '/im/manager/channel/get', params: { id } })
|
||||
}
|
||||
|
||||
// 新增频道
|
||||
export const createManagerChannel = (data: ImManagerChannelVO) => {
|
||||
return request.post({ url: '/im/manager/channel/create', data })
|
||||
}
|
||||
|
||||
// 修改频道
|
||||
export const updateManagerChannel = (data: ImManagerChannelVO) => {
|
||||
return request.put({ url: '/im/manager/channel/update', data })
|
||||
}
|
||||
|
||||
// 删除频道
|
||||
export const deleteManagerChannel = (id: number) => {
|
||||
return request.delete({ url: '/im/manager/channel/delete', params: { id } })
|
||||
}
|
||||
|
||||
// 获得启用的频道精简列表(表单选择用)
|
||||
export const getSimpleChannelList = () => {
|
||||
return request.get<ImManagerChannelVO[]>({ url: '/im/manager/channel/simple-list' })
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerChannelMaterialVO {
|
||||
id: number
|
||||
channelId: number
|
||||
channelName?: string
|
||||
type: number
|
||||
title: string
|
||||
coverUrl?: string
|
||||
summary?: string
|
||||
content?: string
|
||||
url?: string
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// 获得素材分页
|
||||
export const getManagerChannelMaterialPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/channel-material/page', params })
|
||||
}
|
||||
|
||||
// 获得指定频道下的素材精简列表
|
||||
export const getSimpleManagerChannelMaterialList = (channelId: number) => {
|
||||
return request.get({
|
||||
url: '/im/manager/channel-material/simple-list',
|
||||
params: { channelId }
|
||||
})
|
||||
}
|
||||
|
||||
// 获得素材详情
|
||||
export const getManagerChannelMaterial = (id: number) => {
|
||||
return request.get({ url: '/im/manager/channel-material/get', params: { id } })
|
||||
}
|
||||
|
||||
// 新增素材
|
||||
export const createManagerChannelMaterial = (data: ImManagerChannelMaterialVO) => {
|
||||
return request.post({ url: '/im/manager/channel-material/create', data })
|
||||
}
|
||||
|
||||
// 修改素材
|
||||
export const updateManagerChannelMaterial = (data: ImManagerChannelMaterialVO) => {
|
||||
return request.put({ url: '/im/manager/channel-material/update', data })
|
||||
}
|
||||
|
||||
// 删除素材
|
||||
export const deleteManagerChannelMaterial = (id: number) => {
|
||||
return request.delete({ url: '/im/manager/channel-material/delete', params: { id } })
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerChannelMessageVO {
|
||||
id: number
|
||||
channelId: number
|
||||
channelName?: string
|
||||
materialId: number
|
||||
materialTitle?: string
|
||||
materialCoverUrl?: string
|
||||
type: number
|
||||
content?: string
|
||||
receiverUserIds?: number[]
|
||||
sendTime?: Date
|
||||
}
|
||||
|
||||
export interface ImManagerChannelMessageSendReqVO {
|
||||
materialId: number
|
||||
receiverUserIds?: number[]
|
||||
}
|
||||
|
||||
// 立即推送频道消息
|
||||
export const sendManagerChannelMessage = (data: ImManagerChannelMessageSendReqVO) => {
|
||||
return request.post({ url: '/im/manager/channel-message/send', data })
|
||||
}
|
||||
|
||||
// 删除频道消息
|
||||
export const deleteManagerChannelMessage = (id: number) => {
|
||||
return request.delete({ url: '/im/manager/channel-message/delete', params: { id } })
|
||||
}
|
||||
|
||||
// 获得频道消息分页
|
||||
export const getManagerChannelMessagePage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/channel-message/page', params })
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerFacePackItemVO {
|
||||
id: number
|
||||
packId: number
|
||||
url: string
|
||||
name?: string
|
||||
width: number
|
||||
height: number
|
||||
sort: number
|
||||
status: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// 获得表情分页
|
||||
export const getManagerFacePackItemPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/face-pack-item/page', params })
|
||||
}
|
||||
|
||||
// 获得表情详情
|
||||
export const getManagerFacePackItem = (id: number) => {
|
||||
return request.get({ url: '/im/manager/face-pack-item/get', params: { id } })
|
||||
}
|
||||
|
||||
// 新增表情
|
||||
export const createManagerFacePackItem = (data: ImManagerFacePackItemVO) => {
|
||||
return request.post({ url: '/im/manager/face-pack-item/create', data })
|
||||
}
|
||||
|
||||
// 修改表情
|
||||
export const updateManagerFacePackItem = (data: ImManagerFacePackItemVO) => {
|
||||
return request.put({ url: '/im/manager/face-pack-item/update', data })
|
||||
}
|
||||
|
||||
// 删除表情
|
||||
export const deleteManagerFacePackItem = (id: number) => {
|
||||
return request.delete({ url: '/im/manager/face-pack-item/delete', params: { id } })
|
||||
}
|
||||
|
||||
// 批量删除表情
|
||||
export const deleteManagerFacePackItemList = (ids: number[]) => {
|
||||
return request.delete({
|
||||
url: '/im/manager/face-pack-item/delete-list',
|
||||
params: { ids: ids.join(',') }
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerFacePackVO {
|
||||
id: number
|
||||
name: string
|
||||
icon?: string
|
||||
sort: number
|
||||
status: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// 获得表情包分页
|
||||
export const getManagerFacePackPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/face-pack/page', params })
|
||||
}
|
||||
|
||||
// 获得表情包详情
|
||||
export const getManagerFacePack = (id: number) => {
|
||||
return request.get({ url: '/im/manager/face-pack/get', params: { id } })
|
||||
}
|
||||
|
||||
// 新增表情包
|
||||
export const createManagerFacePack = (data: ImManagerFacePackVO) => {
|
||||
return request.post({ url: '/im/manager/face-pack/create', data })
|
||||
}
|
||||
|
||||
// 修改表情包
|
||||
export const updateManagerFacePack = (data: ImManagerFacePackVO) => {
|
||||
return request.put({ url: '/im/manager/face-pack/update', data })
|
||||
}
|
||||
|
||||
// 删除表情包
|
||||
export const deleteManagerFacePack = (id: number) => {
|
||||
return request.delete({ url: '/im/manager/face-pack/delete', params: { id } })
|
||||
}
|
||||
|
||||
// 批量删除表情包
|
||||
export const deleteManagerFacePackList = (ids: number[]) => {
|
||||
return request.delete({
|
||||
url: '/im/manager/face-pack/delete-list',
|
||||
params: { ids: ids.join(',') }
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerFaceUserItemVO {
|
||||
id: number
|
||||
userId: number
|
||||
userNickname?: string
|
||||
url: string
|
||||
name?: string
|
||||
width?: number
|
||||
height?: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// 获得用户表情分页
|
||||
export const getManagerFaceUserItemPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/face-user-item/page', params })
|
||||
}
|
||||
|
||||
// 删除用户表情
|
||||
export const deleteManagerFaceUserItem = (id: number) => {
|
||||
return request.delete({ url: '/im/manager/face-user-item/delete', params: { id } })
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerFriendVO {
|
||||
id: number
|
||||
userId: number
|
||||
userNickname?: string
|
||||
friendUserId: number
|
||||
friendNickname?: string
|
||||
displayName?: string
|
||||
addSource?: number
|
||||
silent: boolean
|
||||
pinned: boolean
|
||||
blocked: boolean
|
||||
status: number
|
||||
addTime?: Date
|
||||
deleteTime?: Date
|
||||
createTime: Date
|
||||
}
|
||||
|
||||
// 获得好友关系分页
|
||||
export const getManagerFriendPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/friend/page', params })
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerFriendRequestVO {
|
||||
id: number
|
||||
fromUserId: number
|
||||
fromNickname?: string
|
||||
toUserId: number
|
||||
toNickname?: string
|
||||
applyContent?: string
|
||||
displayName?: string
|
||||
addSource?: number
|
||||
handleResult: number
|
||||
handleContent?: string
|
||||
handleTime?: Date
|
||||
createTime: Date
|
||||
}
|
||||
|
||||
// 获得好友申请分页
|
||||
export const getManagerFriendRequestPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/friend-request/page', params })
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerGroupVO {
|
||||
id: number
|
||||
name: string
|
||||
avatar?: string
|
||||
notice?: string
|
||||
ownerUserId: number
|
||||
ownerNickname?: string
|
||||
memberCount?: number
|
||||
status: number
|
||||
banned: boolean
|
||||
mutedAll?: boolean // 是否全群禁言
|
||||
bannedReason?: string
|
||||
bannedTime?: Date
|
||||
dissolvedTime?: Date
|
||||
createTime: Date
|
||||
}
|
||||
|
||||
export interface ImManagerGroupMemberVO {
|
||||
userId: number
|
||||
nickname?: string
|
||||
avatar?: string
|
||||
displayUserName?: string
|
||||
groupRemark?: string
|
||||
silent?: boolean
|
||||
status: number
|
||||
role?: number // 成员角色,参见 ImGroupMemberRole 枚举
|
||||
joinTime?: Date
|
||||
quitTime?: Date
|
||||
muteEndTime?: Date // 禁言到期时间
|
||||
}
|
||||
|
||||
// 获得群分页
|
||||
export const getManagerGroupPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/group/page', params })
|
||||
}
|
||||
|
||||
// 获得群详情
|
||||
export const getManagerGroup = (id: number) => {
|
||||
return request.get({ url: '/im/manager/group/get', params: { id } })
|
||||
}
|
||||
|
||||
// 封禁群
|
||||
export const banManagerGroup = (data: { id: number; reason: string }) => {
|
||||
return request.put({ url: '/im/manager/group/ban', data })
|
||||
}
|
||||
|
||||
// 解封群
|
||||
export const unbanManagerGroup = (id: number) => {
|
||||
return request.put({ url: '/im/manager/group/unban', params: { id } })
|
||||
}
|
||||
|
||||
// 解散群
|
||||
export const dissolveManagerGroup = (id: number) => {
|
||||
return request.delete({ url: '/im/manager/group/dissolve', params: { id } })
|
||||
}
|
||||
|
||||
// 获得群成员列表(含已退群成员,由前端按需过滤)
|
||||
export const getManagerGroupMemberList = (groupId: number) => {
|
||||
return request.get({ url: '/im/manager/group/member/list', params: { groupId } })
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerGroupRequestVO {
|
||||
id: number
|
||||
groupId: number
|
||||
groupName?: string
|
||||
userId: number
|
||||
userNickname?: string
|
||||
inviterUserId?: number
|
||||
inviterNickname?: string
|
||||
applyContent?: string
|
||||
addSource?: number
|
||||
handleResult: number
|
||||
handleUserId?: number
|
||||
handleNickname?: string
|
||||
handleContent?: string
|
||||
handleTime?: Date
|
||||
createTime: Date
|
||||
}
|
||||
|
||||
// 获得加群申请分页
|
||||
export const getManagerGroupRequestPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/group-request/page', params })
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerGroupMessageVO {
|
||||
id: number
|
||||
clientMessageId?: string
|
||||
groupId: number
|
||||
groupName?: string
|
||||
senderId: number
|
||||
senderNickname?: string
|
||||
type: number
|
||||
content: string
|
||||
status: number
|
||||
atUserIds?: number[]
|
||||
// 与 atUserIds 同长度;后端对找不到 / 已删除的成员返回 null,UI 用 `?.[idx] || userId` 回退到 userId 渲染
|
||||
atUserNicknames?: (string | null)[]
|
||||
receiptStatus?: number
|
||||
sendTime: Date
|
||||
createTime: Date
|
||||
}
|
||||
|
||||
// 获得群聊消息分页
|
||||
export const getManagerGroupMessagePage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/message/group/page', params })
|
||||
}
|
||||
|
||||
// 获得群聊消息详情
|
||||
export const getManagerGroupMessage = (id: number) => {
|
||||
return request.get({ url: '/im/manager/message/group/get', params: { id } })
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerPrivateMessageVO {
|
||||
id: number
|
||||
clientMessageId?: string
|
||||
senderId: number
|
||||
senderNickname?: string
|
||||
receiverId: number
|
||||
receiverNickname?: string
|
||||
type: number
|
||||
content: string
|
||||
status: number
|
||||
sendTime: Date
|
||||
createTime: Date
|
||||
}
|
||||
|
||||
// 获得私聊消息分页
|
||||
export const getManagerPrivateMessagePage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/message/private/page', params })
|
||||
}
|
||||
|
||||
// 获得私聊消息详情
|
||||
export const getManagerPrivateMessage = (id: number) => {
|
||||
return request.get({ url: '/im/manager/message/private/get', params: { id } })
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerRtcCallVO {
|
||||
id: number
|
||||
room: string
|
||||
conversationType: number
|
||||
mediaType: number
|
||||
inviterUserId: number
|
||||
inviterNickname?: string
|
||||
groupId?: number
|
||||
groupName?: string
|
||||
status: number
|
||||
endReason?: number
|
||||
startTime: Date
|
||||
acceptTime?: Date
|
||||
endTime?: Date
|
||||
createTime: Date
|
||||
}
|
||||
|
||||
export interface ImManagerRtcParticipantVO {
|
||||
id: number
|
||||
callId: number
|
||||
userId: number
|
||||
userNickname?: string
|
||||
role: number
|
||||
status: number
|
||||
inviteTime: Date
|
||||
acceptTime?: Date
|
||||
leaveTime?: Date
|
||||
}
|
||||
|
||||
// 获得通话记录分页
|
||||
export const getManagerRtcCallPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/rtc/page', params })
|
||||
}
|
||||
|
||||
// 获得通话参与者列表
|
||||
export const getManagerRtcCallParticipantList = (id: number) => {
|
||||
return request.get({ url: '/im/manager/rtc/participant-list', params: { id } })
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImManagerSensitiveWordVO {
|
||||
id: number
|
||||
word: string
|
||||
status: number
|
||||
creator?: string
|
||||
creatorName?: string
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// 获得敏感词分页
|
||||
export const getManagerSensitiveWordPage = (params: PageParam) => {
|
||||
return request.get({ url: '/im/manager/sensitive-word/page', params })
|
||||
}
|
||||
|
||||
// 获得敏感词详情
|
||||
export const getManagerSensitiveWord = (id: number) => {
|
||||
return request.get({ url: '/im/manager/sensitive-word/get', params: { id } })
|
||||
}
|
||||
|
||||
// 新增敏感词
|
||||
export const createManagerSensitiveWord = (data: ImManagerSensitiveWordVO) => {
|
||||
return request.post({ url: '/im/manager/sensitive-word/create', data })
|
||||
}
|
||||
|
||||
// 修改敏感词
|
||||
export const updateManagerSensitiveWord = (data: ImManagerSensitiveWordVO) => {
|
||||
return request.put({ url: '/im/manager/sensitive-word/update', data })
|
||||
}
|
||||
|
||||
// 删除敏感词
|
||||
export const deleteManagerSensitiveWord = (id: number) => {
|
||||
return request.delete({ url: '/im/manager/sensitive-word/delete', params: { id } })
|
||||
}
|
||||
|
||||
// 批量删除敏感词
|
||||
export const deleteManagerSensitiveWordList = (ids: number[]) => {
|
||||
return request.delete({
|
||||
url: '/im/manager/sensitive-word/delete-list',
|
||||
params: { ids: ids.join(',') }
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImStatisticsOverviewVO {
|
||||
totalUser: number
|
||||
newUserToday: number
|
||||
totalGroup: number
|
||||
newGroupToday: number
|
||||
activeUserDaily: number
|
||||
activeUserWeekly: number
|
||||
activeUserMonthly: number
|
||||
privateMessageToday: number
|
||||
groupMessageToday: number
|
||||
privateMessageYesterday: number
|
||||
groupMessageYesterday: number
|
||||
}
|
||||
|
||||
export interface ImStatisticsTrendVO {
|
||||
dates: string[]
|
||||
series: Record<string, number[]>
|
||||
}
|
||||
|
||||
export interface ImStatisticsMessageTypeVO {
|
||||
type: number // 参见 ImMessageTypeEnum 枚举类,由前端按 DICT_TYPE.IM_MESSAGE_TYPE 翻译
|
||||
value: number
|
||||
}
|
||||
|
||||
export interface ImStatisticsGroupSizeVO {
|
||||
range: string
|
||||
count: number
|
||||
}
|
||||
|
||||
export interface ImStatisticsTopSenderVO {
|
||||
userId: number
|
||||
nickname: string
|
||||
messageCount: number
|
||||
}
|
||||
|
||||
// 获得 KPI 概览
|
||||
export const getStatisticsOverview = (): Promise<ImStatisticsOverviewVO> => {
|
||||
return request.get<ImStatisticsOverviewVO>({ url: '/im/manager/statistics/overview' })
|
||||
}
|
||||
|
||||
// 获得消息趋势(私聊 + 群聊双线)
|
||||
export const getMessageTrend = (days: number): Promise<ImStatisticsTrendVO> => {
|
||||
return request.get<ImStatisticsTrendVO>({ url: '/im/manager/statistics/message-trend', params: { days } })
|
||||
}
|
||||
|
||||
// 获得用户趋势(新增注册 + 日活双线)
|
||||
export const getUserTrend = (days: number): Promise<ImStatisticsTrendVO> => {
|
||||
return request.get<ImStatisticsTrendVO>({ url: '/im/manager/statistics/user-trend', params: { days } })
|
||||
}
|
||||
|
||||
// 获得消息类型分布(最近 30 天)
|
||||
export const getMessageTypeDistribution = (): Promise<ImStatisticsMessageTypeVO[]> => {
|
||||
return request.get<ImStatisticsMessageTypeVO[]>({
|
||||
url: '/im/manager/statistics/message-type-distribution'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得群规模分布
|
||||
export const getGroupSizeDistribution = (): Promise<ImStatisticsGroupSizeVO[]> => {
|
||||
return request.get<ImStatisticsGroupSizeVO[]>({
|
||||
url: '/im/manager/statistics/group-size-distribution'
|
||||
})
|
||||
}
|
||||
|
||||
// 获得消息 TOP 发送者(最近 30 天)
|
||||
export const getTopSenders = (): Promise<ImStatisticsTopSenderVO[]> => {
|
||||
return request.get<ImStatisticsTopSenderVO[]>({ url: '/im/manager/statistics/top-senders' })
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
export interface ImChannelMessageRespVO {
|
||||
id: number
|
||||
clientMessageId?: string
|
||||
channelId: number
|
||||
materialId: number
|
||||
type: number
|
||||
content: string
|
||||
/** 当前用户已读态;pull 时按 Redis 游标计算填充,多端同步使用 */
|
||||
status?: number
|
||||
sendTime: string
|
||||
}
|
||||
|
||||
// 拉取当前用户应收的频道消息(离线增量);按 minId 游标分页
|
||||
export const pullChannelMessages = (params: { minId: number; size?: number }, signal?: AbortSignal) => {
|
||||
return request.get<ImChannelMessageRespVO[]>({
|
||||
url: '/im/channel/message/pull',
|
||||
params,
|
||||
signal
|
||||
})
|
||||
}
|
||||
|
||||
// 上报频道消息已读位置;切到频道会话或拉到新消息后调
|
||||
export const readChannelMessages = (channelId: number, messageId: number) => {
|
||||
return request.put({
|
||||
url: '/im/channel/message/read',
|
||||
params: { channelId, messageId }
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// 群聊消息 Response VO
|
||||
export interface ImGroupMessageRespVO {
|
||||
id: number // 消息编号
|
||||
clientMessageId: string // 客户端消息编号
|
||||
senderId: number // 发送人编号
|
||||
groupId: number // 群编号
|
||||
type: number // 消息类型
|
||||
content: string // 消息内容(JSON 格式)
|
||||
status: number // 消息状态
|
||||
sendTime: string // 发送时间
|
||||
atUserIds?: number[] // @ 目标用户编号列表
|
||||
receiverUserIds?: number[] // 定向接收用户编号列表
|
||||
receiptStatus?: number // 回执状态
|
||||
readCount?: number // 已读人数(回执消息、且发送人为当前用户时有值)
|
||||
}
|
||||
|
||||
// 群聊消息发送 Request VO
|
||||
export interface ImGroupMessageSendReqVO {
|
||||
clientMessageId: string // 客户端消息编号
|
||||
groupId: number // 群编号
|
||||
type: number // 消息类型
|
||||
content: string // 消息内容(JSON 格式)
|
||||
atUserIds?: number[] // @ 目标用户编号列表
|
||||
receipt?: boolean // 是否需要回执
|
||||
}
|
||||
|
||||
// 群聊历史消息列表 Request VO
|
||||
export interface ImGroupMessageListReqVO {
|
||||
groupId: number | string // 群编号
|
||||
maxId?: number | string // 起始消息编号(不含),为空则从最新消息开始
|
||||
limit: number // 拉取数量(1 ~ 200)
|
||||
}
|
||||
|
||||
// 发送群聊消息
|
||||
export const sendGroupMessage = (data: ImGroupMessageSendReqVO) => {
|
||||
return request.post<ImGroupMessageRespVO>({ url: '/im/message/group/send', data })
|
||||
}
|
||||
|
||||
// 拉取群聊消息(增量)
|
||||
export const pullGroupMessages = (
|
||||
params: { minId: number | string; size: number },
|
||||
signal?: AbortSignal
|
||||
) => {
|
||||
return request.get<ImGroupMessageRespVO[]>({ url: '/im/message/group/pull', params, signal })
|
||||
}
|
||||
|
||||
// 查询群聊历史消息
|
||||
export const getGroupMessageList = (params: ImGroupMessageListReqVO) => {
|
||||
return request.get<ImGroupMessageRespVO[]>({ url: '/im/message/group/list', params })
|
||||
}
|
||||
|
||||
// 标记群聊消息已读
|
||||
export const readGroupMessages = (groupId: number | string, messageId: number | string) => {
|
||||
return request.put<boolean>({
|
||||
url: '/im/message/group/read',
|
||||
params: { groupId, messageId }
|
||||
})
|
||||
}
|
||||
|
||||
// 撤回群聊消息
|
||||
export const recallGroupMessage = (id: number | string) => {
|
||||
return request.delete<ImGroupMessageRespVO>({
|
||||
url: '/im/message/group/recall',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
// 获取群消息已读用户列表
|
||||
export const getGroupReadUsers = (params: {
|
||||
groupId: number | string
|
||||
messageId: number | string
|
||||
}) => {
|
||||
return request.get<number[]>({ url: '/im/message/group/get-read-user-ids', params })
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// 私聊消息 Response VO
|
||||
export interface ImPrivateMessageRespVO {
|
||||
id: number // 消息编号
|
||||
clientMessageId: string // 客户端消息编号
|
||||
senderId: number // 发送人编号
|
||||
receiverId: number // 接收人编号
|
||||
type: number // 消息类型
|
||||
content: string // 消息内容(JSON 格式)
|
||||
status: number // 消息状态
|
||||
sendTime: string // 发送时间
|
||||
}
|
||||
|
||||
// 私聊消息发送 Request VO
|
||||
export interface ImPrivateMessageSendReqVO {
|
||||
clientMessageId: string // 客户端消息编号
|
||||
receiverId: number // 接收人编号
|
||||
type: number // 消息类型
|
||||
content: string // 消息内容(JSON 格式)
|
||||
}
|
||||
|
||||
// 私聊历史消息列表 Request VO
|
||||
export interface ImPrivateMessageListReqVO {
|
||||
receiverId: number | string // 接收人编号(对方)
|
||||
maxId?: number | string // 起始消息编号(不含),为空则从最新消息开始
|
||||
limit: number // 拉取数量(1 ~ 200)
|
||||
}
|
||||
|
||||
// 发送私聊消息
|
||||
export const sendPrivateMessage = (data: ImPrivateMessageSendReqVO) => {
|
||||
return request.post<ImPrivateMessageRespVO>({ url: '/im/message/private/send', data })
|
||||
}
|
||||
|
||||
// 拉取私聊消息(增量)
|
||||
export const pullPrivateMessages = (
|
||||
params: { minId: number | string; size: number },
|
||||
signal?: AbortSignal
|
||||
) => {
|
||||
return request.get<ImPrivateMessageRespVO[]>({ url: '/im/message/private/pull', params, signal })
|
||||
}
|
||||
|
||||
// 查询私聊历史消息
|
||||
export const getPrivateMessageList = (params: ImPrivateMessageListReqVO) => {
|
||||
return request.get<ImPrivateMessageRespVO[]>({ url: '/im/message/private/list', params })
|
||||
}
|
||||
|
||||
// 标记私聊消息已读
|
||||
export const readPrivateMessages = (receiverId: number | string, messageId: number | string) => {
|
||||
return request.put<boolean>({
|
||||
url: '/im/message/private/read',
|
||||
params: { receiverId, messageId }
|
||||
})
|
||||
}
|
||||
|
||||
// 查询对方已读到我发的最大消息 id(多端 / 离线后用于补齐已读状态)
|
||||
export const getPrivateMaxReadMessageId = (peerId: number | string, signal?: AbortSignal) => {
|
||||
return request.get<number | null>({
|
||||
url: '/im/message/private/max-read-message-id',
|
||||
params: { peerId },
|
||||
signal
|
||||
})
|
||||
}
|
||||
|
||||
// 撤回私聊消息
|
||||
export const recallPrivateMessage = (id: number | string) => {
|
||||
return request.delete<ImPrivateMessageRespVO>({
|
||||
url: '/im/message/private/recall',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// 创建新通话请求 VO
|
||||
export interface ImRtcCallCreateReqVO {
|
||||
conversationType: number
|
||||
mediaType: number
|
||||
groupId?: number
|
||||
inviteeIds: number[] // 被邀请的用户编号集合;私聊必传 1 个对端,群聊必传至少 1 人
|
||||
}
|
||||
|
||||
// 通话中追加邀请请求 VO;仅群通话可用
|
||||
export interface ImRtcCallInviteReqVO {
|
||||
room: string
|
||||
inviteeIds: number[]
|
||||
}
|
||||
|
||||
// 通话会话 VO;create / join / accept / refreshToken 共用
|
||||
export interface ImRtcCallRespVO {
|
||||
room: string // 业务通话编号(同时作为 LiveKit 房间名)
|
||||
livekitUrl: string
|
||||
token?: string // ENDED 状态时为 null(无需 connect LiveKit)
|
||||
conversationType: number
|
||||
mediaType: number
|
||||
status: number
|
||||
endReason?: number // 结束原因;仅 status=ENDED 时有值
|
||||
inviterId: number
|
||||
groupId?: number
|
||||
inviteeIds?: number[]
|
||||
joinedUserIds?: number[]
|
||||
}
|
||||
|
||||
// 群活跃通话查询响应;不含 token
|
||||
export interface ImRtcGroupCallRespVO {
|
||||
room: string
|
||||
groupId: number
|
||||
mediaType: number
|
||||
inviterId: number
|
||||
joinedUserIds?: number[]
|
||||
inviteeIds?: number[]
|
||||
}
|
||||
|
||||
// 创建新通话;私聊或群聊根据 conversationType 区分
|
||||
export const createCall = (data: ImRtcCallCreateReqVO) => {
|
||||
return request.post<ImRtcCallRespVO>({ url: '/im/rtc/create', data })
|
||||
}
|
||||
|
||||
// 通话中追加邀请;仅群通话可用
|
||||
export const inviteCall = (data: ImRtcCallInviteReqVO) => {
|
||||
return request.post<boolean>({ url: '/im/rtc/invite', data })
|
||||
}
|
||||
|
||||
// 加入已有群通话;用于胶囊条「加入」按钮
|
||||
export const joinCall = (room: string) => {
|
||||
return request.post<ImRtcCallRespVO>({ url: '/im/rtc/join', params: { room } })
|
||||
}
|
||||
|
||||
// 接听通话
|
||||
export const acceptCall = (room: string) => {
|
||||
return request.post<ImRtcCallRespVO>({ url: '/im/rtc/accept', params: { room } })
|
||||
}
|
||||
|
||||
// 拒绝通话
|
||||
export const rejectCall = (room: string) => {
|
||||
return request.post<boolean>({ url: '/im/rtc/reject', params: { room } })
|
||||
}
|
||||
|
||||
// 取消邀请;主叫接通前调用
|
||||
export const cancelCall = (room: string) => {
|
||||
return request.post<boolean>({ url: '/im/rtc/cancel', params: { room } })
|
||||
}
|
||||
|
||||
// 离开通话;接通后调用
|
||||
export const leaveCall = (room: string) => {
|
||||
return request.post<boolean>({ url: '/im/rtc/leave', params: { room } })
|
||||
}
|
||||
|
||||
// 振铃超时检查;RUNNING 端 timer 兜底,触发后端立即扫描该 room 的超时 INVITING(接口静默)
|
||||
export const noAnswerCallCheck = (room: string) => {
|
||||
return request.post<boolean>({ url: '/im/rtc/no-answer-call-check', params: { room } })
|
||||
}
|
||||
|
||||
// 查询当前进行中的通话;目前仅群聊场景(胶囊条),返回 null 表示无活跃通话
|
||||
export const getActiveCall = (groupId: number) => {
|
||||
return request.get<ImRtcGroupCallRespVO | null>({
|
||||
url: '/im/rtc/get-active-call',
|
||||
params: { groupId }
|
||||
})
|
||||
}
|
||||
|
|
@ -10,6 +10,9 @@ export interface AlertConfig {
|
|||
sceneRuleIds: string // 关联的场景联动规则编号数组
|
||||
receiveUserIds: string // 接收的用户编号数组
|
||||
receiveTypes: string // 接收的类型数组
|
||||
smsTemplateCode?: string // 短信模板编号
|
||||
mailTemplateCode?: string // 邮件模板编号
|
||||
notifyTemplateCode?: string // 站内信模板编号
|
||||
}
|
||||
|
||||
// IoT 告警配置 API
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ export interface DataSinkVO {
|
|||
| TcpConfig
|
||||
| WebSocketConfig
|
||||
| MqttConfig
|
||||
| DatabaseConfig
|
||||
| RocketMQConfig
|
||||
| KafkaMQConfig
|
||||
| RabbitMQConfig
|
||||
|
|
@ -73,6 +74,14 @@ export interface MqttConfig extends Config {
|
|||
topic: string
|
||||
}
|
||||
|
||||
/** Database 配置 */
|
||||
export interface DatabaseConfig extends Config {
|
||||
jdbcUrl: string
|
||||
username: string
|
||||
password: string
|
||||
tableName: string
|
||||
}
|
||||
|
||||
/** RocketMQ 配置 */
|
||||
export interface RocketMQConfig extends Config {
|
||||
nameServer: string
|
||||
|
|
|
|||
|
|
@ -215,8 +215,8 @@ export const ThingModelFormRules = {
|
|||
identifier: [
|
||||
{ required: true, message: '标识符不能为空', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^[a-zA-Z0-9_]{1,50}$/,
|
||||
message: '支持大小写字母、数字和下划线,不超过 50 个字符',
|
||||
pattern: /^[a-zA-Z][a-zA-Z0-9_]{0,31}$/,
|
||||
message: '支持大小写字母、数字和下划线,必须以字母开头,不超过 32 个字符',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ export interface UserVO {
|
|||
loginIp: string
|
||||
mark: string
|
||||
mobile: string
|
||||
email: string | undefined
|
||||
name: string | undefined
|
||||
nickname: string | undefined
|
||||
registerIp: string
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export interface ProAndonConfigVO {
|
|||
reason: string // 呼叫原因
|
||||
level: number // 级别
|
||||
handlerRoleId: number // 处置人角色编号
|
||||
handlerRoleName: string // 处置人角色名称
|
||||
handlerUserId: number // 处置人编号
|
||||
handlerUserNickname: string // 处置人昵称
|
||||
remark: string // 备注
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export interface WmMiscIssueVO {
|
|||
id: number
|
||||
code: string
|
||||
name: string
|
||||
type: string
|
||||
type: number
|
||||
sourceDocType: string
|
||||
sourceDocId: number
|
||||
sourceDocCode: string
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export interface DeptVO {
|
|||
phone: string
|
||||
email: string
|
||||
createTime: Date
|
||||
children?: DeptVO[]
|
||||
}
|
||||
|
||||
// 查询部门(精简)列表
|
||||
|
|
|
|||
|
|
@ -19,6 +19,16 @@ export interface MailSendReqVO {
|
|||
templateParams: Map<String, Object>
|
||||
}
|
||||
|
||||
export interface MailTemplateSimpleVO {
|
||||
id: number
|
||||
name: string
|
||||
code: string
|
||||
}
|
||||
|
||||
// 查询邮件模版精简列表
|
||||
export const getSimpleMailTemplateList = async () => {
|
||||
return await request.get({ url: '/system/mail-template/simple-list' })
|
||||
}
|
||||
// 查询邮件模版列表
|
||||
export const getMailTemplatePage = async (params: PageParam) => {
|
||||
return await request.get({ url: '/system/mail-template/page', params })
|
||||
|
|
|
|||
|
|
@ -18,6 +18,17 @@ export interface NotifySendReqVO {
|
|||
templateParams: Map<String, Object>
|
||||
}
|
||||
|
||||
export interface NotifyTemplateSimpleVO {
|
||||
id: number
|
||||
name: string
|
||||
code: string
|
||||
}
|
||||
|
||||
// 查询站内信模板精简列表
|
||||
export const getSimpleNotifyTemplateList = async () => {
|
||||
return await request.get({ url: '/system/notify-template/simple-list' })
|
||||
}
|
||||
|
||||
// 查询站内信模板列表
|
||||
export const getNotifyTemplatePage = async (params: PageParam) => {
|
||||
return await request.get({ url: '/system/notify-template/page', params })
|
||||
|
|
@ -45,7 +56,10 @@ export const deleteNotifyTemplate = async (id: number) => {
|
|||
|
||||
// 批量删除站内信模板
|
||||
export const deleteNotifyTemplateList = async (ids: number[]) => {
|
||||
return await request.delete({ url: '/system/notify-template/delete-list', params: { ids: ids.join(',') } })
|
||||
return await request.delete({
|
||||
url: '/system/notify-template/delete-list',
|
||||
params: { ids: ids.join(',') }
|
||||
})
|
||||
}
|
||||
|
||||
// 发送站内信
|
||||
|
|
|
|||
|
|
@ -21,6 +21,16 @@ export interface SendSmsReqVO {
|
|||
templateParams: Map<String, Object>
|
||||
}
|
||||
|
||||
export interface SmsTemplateSimpleVO {
|
||||
id: number
|
||||
name: string
|
||||
code: string
|
||||
}
|
||||
|
||||
// 查询短信模板精简列表
|
||||
export const getSimpleSmsTemplateList = () => {
|
||||
return request.get({ url: '/system/sms-template/simple-list' })
|
||||
}
|
||||
// 查询短信模板列表
|
||||
export const getSmsTemplatePage = (params: PageParam) => {
|
||||
return request.get({ url: '/system/sms-template/page', params })
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export interface UserVO {
|
|||
username: string
|
||||
nickname: string
|
||||
deptId: number
|
||||
deptName?: string
|
||||
postIds: string[]
|
||||
email: string
|
||||
mobile: string
|
||||
|
|
@ -17,11 +18,34 @@ export interface UserVO {
|
|||
createTime: Date
|
||||
}
|
||||
|
||||
// 获取用户精简信息列表
|
||||
export const getSimpleUserList = (): Promise<UserVO[]> => {
|
||||
return request.get({ url: '/system/user/simple-list' })
|
||||
}
|
||||
|
||||
// 按用户编号查询用户精简信息(点头像弹名片)
|
||||
export const getSimpleUser = (id: number | string) => {
|
||||
return request.get<UserVO>({ url: '/system/user/get-simple', params: { id } })
|
||||
}
|
||||
|
||||
// 按昵称模糊搜索用户(加好友)
|
||||
export const getSimpleUserListByNickname = (nickname: string) => {
|
||||
return request.get<UserVO[]>({
|
||||
url: '/system/user/list-by-nickname',
|
||||
params: { nickname }
|
||||
})
|
||||
}
|
||||
|
||||
// 查询用户管理列表
|
||||
export const getUserPage = (params: PageParam) => {
|
||||
return request.get({ url: '/system/user/page', params })
|
||||
}
|
||||
|
||||
// 查询用户管理列表
|
||||
export const getUserList = (ids: number[]) => {
|
||||
return request.get({ url: '/system/user/list', params: { ids: ids.join(',') } })
|
||||
}
|
||||
|
||||
// 查询用户详情
|
||||
export const getUser = (id: number) => {
|
||||
return request.get({ url: '/system/user/get?id=' + id })
|
||||
|
|
@ -74,8 +98,3 @@ export const updateUserStatus = (id: number, status: number) => {
|
|||
}
|
||||
return request.put({ url: '/system/user/update-status', data: data })
|
||||
}
|
||||
|
||||
// 获取用户精简信息列表
|
||||
export const getSimpleUserList = (): Promise<UserVO[]> => {
|
||||
return request.get({ url: '/system/user/simple-list' })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// WMS 首页统计查询参数
|
||||
export interface WmsHomeStatisticsReqVO {
|
||||
warehouseId?: number
|
||||
goodsLimit?: number
|
||||
warehouseLimit?: number
|
||||
}
|
||||
|
||||
// WMS 首页单据状态统计 VO
|
||||
export interface WmsHomeOrderStatusVO {
|
||||
status: number
|
||||
count: number
|
||||
}
|
||||
|
||||
// WMS 首页单据汇总统计 VO
|
||||
export interface WmsHomeOrderSummaryVO {
|
||||
type: number
|
||||
total: number
|
||||
statuses: WmsHomeOrderStatusVO[]
|
||||
}
|
||||
|
||||
// WMS 首页单据趋势 VO
|
||||
export interface WmsHomeOrderTrendVO {
|
||||
time: string | number
|
||||
receiptCount: number
|
||||
shipmentCount: number
|
||||
movementCount: number
|
||||
checkCount: number
|
||||
}
|
||||
|
||||
// WMS 首页商品库存排行 VO
|
||||
export interface WmsHomeInventoryItemRankVO {
|
||||
id: number
|
||||
name: string
|
||||
quantity: number
|
||||
}
|
||||
|
||||
// WMS 首页仓库库存排行 VO
|
||||
export interface WmsHomeInventoryWarehouseRankVO {
|
||||
id: number
|
||||
name: string
|
||||
quantity: number
|
||||
}
|
||||
|
||||
// WMS 首页库存汇总统计 VO
|
||||
export interface WmsHomeInventorySummaryVO {
|
||||
totalQuantity: number
|
||||
goodsShareList: WmsHomeInventoryItemRankVO[]
|
||||
warehouseDistributionList: WmsHomeInventoryWarehouseRankVO[]
|
||||
}
|
||||
|
||||
// WMS 首页统计 API
|
||||
export const WmsHomeStatisticsApi = {
|
||||
// 获得首页单据汇总统计
|
||||
getOrderSummary: async (params?: WmsHomeStatisticsReqVO): Promise<WmsHomeOrderSummaryVO[]> => {
|
||||
return await request.get({ url: `/wms/home-statistics/order-summary`, params })
|
||||
},
|
||||
|
||||
// 获得首页单据趋势
|
||||
getOrderTrend: async (
|
||||
days?: number,
|
||||
params?: WmsHomeStatisticsReqVO
|
||||
): Promise<WmsHomeOrderTrendVO[]> => {
|
||||
return await request.get({
|
||||
url: `/wms/home-statistics/order-trend`,
|
||||
params: { ...params, days }
|
||||
})
|
||||
},
|
||||
|
||||
// 获得首页库存汇总统计
|
||||
getInventorySummary: async (
|
||||
params?: WmsHomeStatisticsReqVO
|
||||
): Promise<WmsHomeInventorySummaryVO> => {
|
||||
return await request.get({ url: `/wms/home-statistics/inventory-summary`, params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// WMS 库存记录 VO
|
||||
export interface InventoryHistoryVO {
|
||||
id?: number
|
||||
itemId?: number
|
||||
itemCode?: string
|
||||
itemName?: string
|
||||
unit?: string
|
||||
skuId?: number
|
||||
skuCode?: string
|
||||
skuName?: string
|
||||
warehouseId?: number
|
||||
warehouseName?: string
|
||||
quantity?: number
|
||||
beforeQuantity?: number
|
||||
afterQuantity?: number
|
||||
price?: number
|
||||
totalPrice?: number
|
||||
remark?: string
|
||||
orderId?: number
|
||||
orderNo?: string
|
||||
orderType?: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// WMS 库存记录 API
|
||||
export const InventoryHistoryApi = {
|
||||
// 查询库存记录分页
|
||||
getInventoryHistoryPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/inventory-history/page', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// WMS 库存统计 VO
|
||||
export interface InventoryVO {
|
||||
id?: number
|
||||
itemId?: number
|
||||
itemCode?: string
|
||||
itemName?: string
|
||||
unit?: string
|
||||
skuId?: number
|
||||
skuCode?: string
|
||||
skuName?: string
|
||||
warehouseId?: number
|
||||
warehouseName?: string
|
||||
quantity?: number
|
||||
remark?: string
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// WMS 库存统计列表 Request VO
|
||||
export interface InventoryListReqVO {
|
||||
warehouseId: number
|
||||
}
|
||||
|
||||
// WMS 库存统计 API
|
||||
export const InventoryApi = {
|
||||
// 查询库存统计分页
|
||||
getInventoryPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/inventory/page', params })
|
||||
},
|
||||
|
||||
// 查询库存统计列表
|
||||
getInventoryList: async (params: InventoryListReqVO) => {
|
||||
return await request.get({ url: '/wms/inventory/list', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// WMS 商品品牌 VO
|
||||
export interface ItemBrandVO {
|
||||
id?: number
|
||||
code?: string
|
||||
name?: string
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// WMS 商品品牌 API
|
||||
export const ItemBrandApi = {
|
||||
// 查询商品品牌分页
|
||||
getItemBrandPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/item-brand/page', params })
|
||||
},
|
||||
|
||||
// 查询商品品牌精简列表
|
||||
getItemBrandSimpleList: async () => {
|
||||
return await request.get({ url: '/wms/item-brand/simple-list' })
|
||||
},
|
||||
|
||||
// 查询商品品牌详情
|
||||
getItemBrand: async (id: number) => {
|
||||
return await request.get({ url: '/wms/item-brand/get?id=' + id })
|
||||
},
|
||||
|
||||
// 新增商品品牌
|
||||
createItemBrand: async (data: ItemBrandVO) => {
|
||||
return await request.post({ url: '/wms/item-brand/create', data })
|
||||
},
|
||||
|
||||
// 修改商品品牌
|
||||
updateItemBrand: async (data: ItemBrandVO) => {
|
||||
return await request.put({ url: '/wms/item-brand/update', data })
|
||||
},
|
||||
|
||||
// 删除商品品牌
|
||||
deleteItemBrand: async (id: number) => {
|
||||
return await request.delete({ url: '/wms/item-brand/delete?id=' + id })
|
||||
},
|
||||
|
||||
// 导出商品品牌
|
||||
exportItemBrand: async (params) => {
|
||||
return await request.download({ url: '/wms/item-brand/export-excel', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// WMS 商品分类 VO
|
||||
export interface ItemCategoryVO {
|
||||
id?: number
|
||||
parentId?: number
|
||||
code?: string
|
||||
name?: string
|
||||
sort?: number
|
||||
status?: number
|
||||
createTime?: Date
|
||||
children?: ItemCategoryVO[]
|
||||
}
|
||||
|
||||
// WMS 商品分类 API
|
||||
export const ItemCategoryApi = {
|
||||
// 查询商品分类列表
|
||||
getItemCategoryList: async (params?: any) => {
|
||||
return await request.get({ url: '/wms/item-category/list', params })
|
||||
},
|
||||
|
||||
// 查询商品分类精简列表
|
||||
getItemCategorySimpleList: async () => {
|
||||
return await request.get({ url: '/wms/item-category/simple-list' })
|
||||
},
|
||||
|
||||
// 查询商品分类详情
|
||||
getItemCategory: async (id: number) => {
|
||||
return await request.get({ url: '/wms/item-category/get?id=' + id })
|
||||
},
|
||||
|
||||
// 新增商品分类
|
||||
createItemCategory: async (data: ItemCategoryVO) => {
|
||||
return await request.post({ url: '/wms/item-category/create', data })
|
||||
},
|
||||
|
||||
// 修改商品分类
|
||||
updateItemCategory: async (data: ItemCategoryVO) => {
|
||||
return await request.put({ url: '/wms/item-category/update', data })
|
||||
},
|
||||
|
||||
// 删除商品分类
|
||||
deleteItemCategory: async (id: number) => {
|
||||
return await request.delete({ url: '/wms/item-category/delete?id=' + id })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import request from '@/config/axios'
|
||||
import { ItemSkuVO } from './sku'
|
||||
|
||||
// WMS 商品 VO
|
||||
export interface ItemVO {
|
||||
id?: number
|
||||
code?: string
|
||||
name?: string
|
||||
categoryId?: number
|
||||
categoryName?: string
|
||||
unit?: string
|
||||
brandId?: number
|
||||
brandName?: string
|
||||
remark?: string
|
||||
skus?: ItemSkuVO[]
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// WMS 商品 API
|
||||
export const ItemApi = {
|
||||
// 查询商品分页
|
||||
getItemPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/item/page', params })
|
||||
},
|
||||
|
||||
// 查询商品精简列表
|
||||
getItemSimpleList: async (params?: any) => {
|
||||
return await request.get({ url: '/wms/item/simple-list', params })
|
||||
},
|
||||
|
||||
// 查询商品详情
|
||||
getItem: async (id: number) => {
|
||||
return await request.get({ url: '/wms/item/get?id=' + id })
|
||||
},
|
||||
|
||||
// 新增商品
|
||||
createItem: async (data: ItemVO) => {
|
||||
return await request.post({ url: '/wms/item/create', data })
|
||||
},
|
||||
|
||||
// 修改商品
|
||||
updateItem: async (data: ItemVO) => {
|
||||
return await request.put({ url: '/wms/item/update', data })
|
||||
},
|
||||
|
||||
// 删除商品
|
||||
deleteItem: async (id: number) => {
|
||||
return await request.delete({ url: '/wms/item/delete?id=' + id })
|
||||
},
|
||||
|
||||
// 导出商品
|
||||
exportItem: async (params: any) => {
|
||||
return await request.download({ url: '/wms/item/export-excel', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// WMS 商品 SKU VO
|
||||
export interface ItemSkuVO {
|
||||
id?: number
|
||||
name?: string
|
||||
itemId?: number
|
||||
itemCode?: string
|
||||
itemName?: string
|
||||
categoryId?: number
|
||||
categoryName?: string
|
||||
unit?: string
|
||||
brandId?: number
|
||||
brandName?: string
|
||||
barCode?: string
|
||||
code?: string
|
||||
length?: number
|
||||
width?: number
|
||||
height?: number
|
||||
grossWeight?: number
|
||||
netWeight?: number
|
||||
costPrice?: number
|
||||
sellingPrice?: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// WMS 商品 SKU API
|
||||
export const ItemSkuApi = {
|
||||
// 按 SKU 维度分页(支持商品 / 品牌 / 分类多表联查筛选)
|
||||
getItemSkuPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/item-sku/page', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// WMS 往来企业 VO
|
||||
export interface MerchantVO {
|
||||
id?: number
|
||||
code?: string
|
||||
name?: string
|
||||
type?: number
|
||||
level?: string
|
||||
bankName?: string
|
||||
bankAccount?: string
|
||||
address?: string
|
||||
mobile?: string
|
||||
telephone?: string
|
||||
contact?: string
|
||||
email?: string
|
||||
remark?: string
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
export interface MerchantSimpleListReqVO {
|
||||
types?: number[]
|
||||
}
|
||||
|
||||
// WMS 往来企业 API
|
||||
export const MerchantApi = {
|
||||
// 查询往来企业分页
|
||||
getMerchantPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/merchant/page', params })
|
||||
},
|
||||
|
||||
// 查询往来企业精简列表
|
||||
getMerchantSimpleList: async (params?: MerchantSimpleListReqVO) => {
|
||||
return await request.get({ url: '/wms/merchant/simple-list', params })
|
||||
},
|
||||
|
||||
// 查询往来企业详情
|
||||
getMerchant: async (id: number) => {
|
||||
return await request.get({ url: '/wms/merchant/get?id=' + id })
|
||||
},
|
||||
|
||||
// 新增往来企业
|
||||
createMerchant: async (data: MerchantVO) => {
|
||||
return await request.post({ url: '/wms/merchant/create', data })
|
||||
},
|
||||
|
||||
// 修改往来企业
|
||||
updateMerchant: async (data: MerchantVO) => {
|
||||
return await request.put({ url: '/wms/merchant/update', data })
|
||||
},
|
||||
|
||||
// 删除往来企业
|
||||
deleteMerchant: async (id: number) => {
|
||||
return await request.delete({ url: '/wms/merchant/delete?id=' + id })
|
||||
},
|
||||
|
||||
// 导出往来企业
|
||||
exportMerchant: async (params: any) => {
|
||||
return await request.download({ url: '/wms/merchant/export-excel', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
import request from '@/config/axios'
|
||||
|
||||
// WMS 仓库 VO
|
||||
export interface WarehouseVO {
|
||||
id?: number
|
||||
code?: string
|
||||
name?: string
|
||||
remark?: string
|
||||
sort?: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
||||
// WMS 仓库 API
|
||||
export const WarehouseApi = {
|
||||
// 查询仓库分页
|
||||
getWarehousePage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/warehouse/page', params })
|
||||
},
|
||||
|
||||
// 查询仓库精简列表
|
||||
getWarehouseSimpleList: async () => {
|
||||
return await request.get({ url: '/wms/warehouse/simple-list' })
|
||||
},
|
||||
|
||||
// 查询仓库详情
|
||||
getWarehouse: async (id: number) => {
|
||||
return await request.get({ url: '/wms/warehouse/get?id=' + id })
|
||||
},
|
||||
|
||||
// 新增仓库
|
||||
createWarehouse: async (data: WarehouseVO) => {
|
||||
return await request.post({ url: '/wms/warehouse/create', data })
|
||||
},
|
||||
|
||||
// 修改仓库
|
||||
updateWarehouse: async (data: WarehouseVO) => {
|
||||
return await request.put({ url: '/wms/warehouse/update', data })
|
||||
},
|
||||
|
||||
// 删除仓库
|
||||
deleteWarehouse: async (id: number) => {
|
||||
return await request.delete({ url: '/wms/warehouse/delete?id=' + id })
|
||||
},
|
||||
|
||||
// 导出仓库
|
||||
exportWarehouse: async (params) => {
|
||||
return await request.download({ url: '/wms/warehouse/export-excel', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// WMS 盘库单明细 VO
|
||||
export interface CheckOrderDetailVO {
|
||||
id?: number
|
||||
orderId?: number
|
||||
itemId?: number
|
||||
itemCode?: string
|
||||
itemName?: string
|
||||
unit?: string
|
||||
skuId?: number
|
||||
skuCode?: string
|
||||
skuName?: string
|
||||
inventoryId?: number
|
||||
warehouseId?: number
|
||||
warehouseName?: string
|
||||
receiptTime?: Date
|
||||
quantity?: number
|
||||
checkQuantity?: number
|
||||
availableQuantity?: number
|
||||
price?: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import request from '@/config/axios'
|
||||
import { CheckOrderDetailVO } from './detail'
|
||||
|
||||
// WMS 盘库单 VO
|
||||
export interface CheckOrderVO {
|
||||
id?: number
|
||||
no?: string
|
||||
orderTime?: string
|
||||
status?: number
|
||||
remark?: string
|
||||
warehouseId?: number
|
||||
warehouseName?: string
|
||||
totalQuantity?: number
|
||||
totalPrice?: number
|
||||
actualPrice?: number
|
||||
details?: CheckOrderDetailVO[]
|
||||
createTime?: Date
|
||||
creator?: string
|
||||
creatorName?: string
|
||||
updateTime?: Date
|
||||
updater?: string
|
||||
updaterName?: string
|
||||
}
|
||||
|
||||
// WMS 盘库单 API
|
||||
export const CheckOrderApi = {
|
||||
// 查询盘库单分页
|
||||
getCheckOrderPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/check-order/page', params })
|
||||
},
|
||||
|
||||
// 查询盘库单详情
|
||||
getCheckOrder: async (id: number) => {
|
||||
return await request.get({ url: '/wms/check-order/get?id=' + id })
|
||||
},
|
||||
|
||||
// 查询盘库单明细
|
||||
getCheckOrderDetailListByOrderId: async (orderId: number) => {
|
||||
return await request.get({
|
||||
url: '/wms/check-order-detail/list-by-order-id?orderId=' + orderId
|
||||
})
|
||||
},
|
||||
|
||||
// 新增盘库单
|
||||
createCheckOrder: async (data: CheckOrderVO) => {
|
||||
return await request.post({ url: '/wms/check-order/create', data })
|
||||
},
|
||||
|
||||
// 修改盘库单
|
||||
updateCheckOrder: async (data: CheckOrderVO) => {
|
||||
return await request.put({ url: '/wms/check-order/update', data })
|
||||
},
|
||||
|
||||
// 完成盘库
|
||||
completeCheckOrder: async (id: number) => {
|
||||
return await request.put({ url: '/wms/check-order/complete?id=' + id })
|
||||
},
|
||||
|
||||
// 作废盘库单
|
||||
cancelCheckOrder: async (id: number) => {
|
||||
return await request.put({ url: '/wms/check-order/cancel?id=' + id })
|
||||
},
|
||||
|
||||
// 删除盘库单
|
||||
deleteCheckOrder: async (id: number) => {
|
||||
return await request.delete({ url: '/wms/check-order/delete?id=' + id })
|
||||
},
|
||||
|
||||
// 导出盘库单
|
||||
exportCheckOrder: async (params: any) => {
|
||||
return await request.download({ url: '/wms/check-order/export-excel', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// WMS 移库单明细 VO
|
||||
export interface MovementOrderDetailVO {
|
||||
id?: number
|
||||
orderId?: number
|
||||
itemId?: number
|
||||
itemCode?: string
|
||||
itemName?: string
|
||||
unit?: string
|
||||
skuId?: number
|
||||
skuCode?: string
|
||||
skuName?: string
|
||||
sourceWarehouseId?: number
|
||||
sourceWarehouseName?: string
|
||||
targetWarehouseId?: number
|
||||
targetWarehouseName?: string
|
||||
quantity?: number
|
||||
availableQuantity?: number
|
||||
price?: number
|
||||
totalPrice?: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
import request from '@/config/axios'
|
||||
import { MovementOrderDetailVO } from './detail'
|
||||
|
||||
// WMS 移库单 VO
|
||||
export interface MovementOrderVO {
|
||||
id?: number
|
||||
no?: string
|
||||
orderTime?: string
|
||||
status?: number
|
||||
remark?: string
|
||||
sourceWarehouseId?: number
|
||||
sourceWarehouseName?: string
|
||||
targetWarehouseId?: number
|
||||
targetWarehouseName?: string
|
||||
totalQuantity?: number
|
||||
totalPrice?: number
|
||||
details?: MovementOrderDetailVO[]
|
||||
createTime?: Date
|
||||
creator?: string
|
||||
creatorName?: string
|
||||
updateTime?: Date
|
||||
updater?: string
|
||||
updaterName?: string
|
||||
}
|
||||
|
||||
// WMS 移库单 API
|
||||
export const MovementOrderApi = {
|
||||
// 查询移库单分页
|
||||
getMovementOrderPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/movement-order/page', params })
|
||||
},
|
||||
|
||||
// 查询移库单详情
|
||||
getMovementOrder: async (id: number) => {
|
||||
return await request.get({ url: '/wms/movement-order/get?id=' + id })
|
||||
},
|
||||
|
||||
// 查询移库单明细
|
||||
getMovementOrderDetailListByOrderId: async (orderId: number) => {
|
||||
return await request.get({
|
||||
url: '/wms/movement-order-detail/list-by-order-id?orderId=' + orderId
|
||||
})
|
||||
},
|
||||
|
||||
// 新增移库单
|
||||
createMovementOrder: async (data: MovementOrderVO) => {
|
||||
return await request.post({ url: '/wms/movement-order/create', data })
|
||||
},
|
||||
|
||||
// 修改移库单
|
||||
updateMovementOrder: async (data: MovementOrderVO) => {
|
||||
return await request.put({ url: '/wms/movement-order/update', data })
|
||||
},
|
||||
|
||||
// 完成移库
|
||||
completeMovementOrder: async (id: number) => {
|
||||
return await request.put({ url: '/wms/movement-order/complete?id=' + id })
|
||||
},
|
||||
|
||||
// 作废移库单
|
||||
cancelMovementOrder: async (id: number) => {
|
||||
return await request.put({ url: '/wms/movement-order/cancel?id=' + id })
|
||||
},
|
||||
|
||||
// 删除移库单
|
||||
deleteMovementOrder: async (id: number) => {
|
||||
return await request.delete({ url: '/wms/movement-order/delete?id=' + id })
|
||||
},
|
||||
|
||||
// 导出移库单
|
||||
exportMovementOrder: async (params: any) => {
|
||||
return await request.download({ url: '/wms/movement-order/export-excel', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// WMS 入库单明细 VO
|
||||
export interface ReceiptOrderDetailVO {
|
||||
id?: number
|
||||
orderId?: number
|
||||
itemId?: number
|
||||
itemCode?: string
|
||||
itemName?: string
|
||||
unit?: string
|
||||
skuId?: number
|
||||
skuCode?: string
|
||||
skuName?: string
|
||||
warehouseId?: number
|
||||
warehouseName?: string
|
||||
quantity?: number
|
||||
price?: number
|
||||
totalPrice?: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import request from '@/config/axios'
|
||||
import { ReceiptOrderDetailVO } from './detail'
|
||||
|
||||
// WMS 入库单 VO
|
||||
export interface ReceiptOrderVO {
|
||||
id?: number
|
||||
no?: string
|
||||
type?: number
|
||||
orderTime?: string
|
||||
status?: number
|
||||
bizOrderNo?: string
|
||||
merchantId?: number
|
||||
merchantName?: string
|
||||
remark?: string
|
||||
warehouseId?: number
|
||||
warehouseName?: string
|
||||
totalQuantity?: number
|
||||
totalPrice?: number
|
||||
details?: ReceiptOrderDetailVO[]
|
||||
createTime?: Date
|
||||
creator?: string
|
||||
creatorName?: string
|
||||
updateTime?: Date
|
||||
updater?: string
|
||||
updaterName?: string
|
||||
}
|
||||
|
||||
// WMS 入库单 API
|
||||
export const ReceiptOrderApi = {
|
||||
// 查询入库单分页
|
||||
getReceiptOrderPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/receipt-order/page', params })
|
||||
},
|
||||
|
||||
// 查询入库单详情
|
||||
getReceiptOrder: async (id: number) => {
|
||||
return await request.get({ url: '/wms/receipt-order/get?id=' + id })
|
||||
},
|
||||
|
||||
// 查询入库单明细
|
||||
getReceiptOrderDetailListByOrderId: async (orderId: number) => {
|
||||
return await request.get({
|
||||
url: '/wms/receipt-order-detail/list-by-order-id?orderId=' + orderId
|
||||
})
|
||||
},
|
||||
|
||||
// 新增入库单
|
||||
createReceiptOrder: async (data: ReceiptOrderVO) => {
|
||||
return await request.post({ url: '/wms/receipt-order/create', data })
|
||||
},
|
||||
|
||||
// 修改入库单
|
||||
updateReceiptOrder: async (data: ReceiptOrderVO) => {
|
||||
return await request.put({ url: '/wms/receipt-order/update', data })
|
||||
},
|
||||
|
||||
// 完成入库
|
||||
completeReceiptOrder: async (id: number) => {
|
||||
return await request.put({ url: '/wms/receipt-order/complete?id=' + id })
|
||||
},
|
||||
|
||||
// 作废入库单
|
||||
cancelReceiptOrder: async (id: number) => {
|
||||
return await request.put({ url: '/wms/receipt-order/cancel?id=' + id })
|
||||
},
|
||||
|
||||
// 删除入库单
|
||||
deleteReceiptOrder: async (id: number) => {
|
||||
return await request.delete({ url: '/wms/receipt-order/delete?id=' + id })
|
||||
},
|
||||
|
||||
// 导出入库单
|
||||
exportReceiptOrder: async (params: any) => {
|
||||
return await request.download({ url: '/wms/receipt-order/export-excel', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// WMS 出库单明细 VO
|
||||
export interface ShipmentOrderDetailVO {
|
||||
id?: number
|
||||
orderId?: number
|
||||
itemId?: number
|
||||
itemCode?: string
|
||||
itemName?: string
|
||||
unit?: string
|
||||
skuId?: number
|
||||
skuCode?: string
|
||||
skuName?: string
|
||||
warehouseId?: number
|
||||
warehouseName?: string
|
||||
quantity?: number
|
||||
availableQuantity?: number
|
||||
price?: number
|
||||
totalPrice?: number
|
||||
createTime?: Date
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import request from '@/config/axios'
|
||||
import { ShipmentOrderDetailVO } from './detail'
|
||||
|
||||
// WMS 出库单 VO
|
||||
export interface ShipmentOrderVO {
|
||||
id?: number
|
||||
no?: string
|
||||
type?: number
|
||||
orderTime?: string
|
||||
status?: number
|
||||
bizOrderNo?: string
|
||||
merchantId?: number
|
||||
merchantName?: string
|
||||
remark?: string
|
||||
warehouseId?: number
|
||||
warehouseName?: string
|
||||
totalQuantity?: number
|
||||
totalPrice?: number
|
||||
details?: ShipmentOrderDetailVO[]
|
||||
createTime?: Date
|
||||
creator?: string
|
||||
creatorName?: string
|
||||
updateTime?: Date
|
||||
updater?: string
|
||||
updaterName?: string
|
||||
}
|
||||
|
||||
// WMS 出库单 API
|
||||
export const ShipmentOrderApi = {
|
||||
// 查询出库单分页
|
||||
getShipmentOrderPage: async (params: any) => {
|
||||
return await request.get({ url: '/wms/shipment-order/page', params })
|
||||
},
|
||||
|
||||
// 查询出库单详情
|
||||
getShipmentOrder: async (id: number) => {
|
||||
return await request.get({ url: '/wms/shipment-order/get?id=' + id })
|
||||
},
|
||||
|
||||
// 查询出库单明细
|
||||
getShipmentOrderDetailListByOrderId: async (orderId: number) => {
|
||||
return await request.get({
|
||||
url: '/wms/shipment-order-detail/list-by-order-id?orderId=' + orderId
|
||||
})
|
||||
},
|
||||
|
||||
// 新增出库单
|
||||
createShipmentOrder: async (data: ShipmentOrderVO) => {
|
||||
return await request.post({ url: '/wms/shipment-order/create', data })
|
||||
},
|
||||
|
||||
// 修改出库单
|
||||
updateShipmentOrder: async (data: ShipmentOrderVO) => {
|
||||
return await request.put({ url: '/wms/shipment-order/update', data })
|
||||
},
|
||||
|
||||
// 完成出库
|
||||
completeShipmentOrder: async (id: number) => {
|
||||
return await request.put({ url: '/wms/shipment-order/complete?id=' + id })
|
||||
},
|
||||
|
||||
// 作废出库单
|
||||
cancelShipmentOrder: async (id: number) => {
|
||||
return await request.put({ url: '/wms/shipment-order/cancel?id=' + id })
|
||||
},
|
||||
|
||||
// 删除出库单
|
||||
deleteShipmentOrder: async (id: number) => {
|
||||
return await request.delete({ url: '/wms/shipment-order/delete?id=' + id })
|
||||
},
|
||||
|
||||
// 导出出库单
|
||||
exportShipmentOrder: async (params: any) => {
|
||||
return await request.download({ url: '/wms/shipment-order/export-excel', params })
|
||||
}
|
||||
}
|
||||
|
|
@ -162,13 +162,24 @@ function handleReady(cropperInstance: Cropper) {
|
|||
}
|
||||
|
||||
function handlerToolbar(event: string, arg?: number) {
|
||||
if (event === 'scaleX') {
|
||||
scaleX = arg = scaleX === -1 ? 1 : -1
|
||||
if (!cropper.value) return
|
||||
const cropperImage = cropper.value.getCropperImage()
|
||||
const cropperSelection = cropper.value.getCropperSelection()
|
||||
|
||||
if (event === 'reset') {
|
||||
cropperImage?.$resetTransform()
|
||||
cropperSelection?.$reset()
|
||||
} else if (event === 'rotate') {
|
||||
cropperImage?.$rotate(`${arg}deg`)
|
||||
} else if (event === 'scaleX') {
|
||||
scaleX = scaleX === -1 ? 1 : -1
|
||||
cropperImage?.$scale(scaleX, 1)
|
||||
} else if (event === 'scaleY') {
|
||||
scaleY = scaleY === -1 ? 1 : -1
|
||||
cropperImage?.$scale(1, scaleY)
|
||||
} else if (event === 'zoom') {
|
||||
cropperImage?.$zoom(arg!)
|
||||
}
|
||||
if (event === 'scaleY') {
|
||||
scaleY = arg = scaleY === -1 ? 1 : -1
|
||||
}
|
||||
cropper?.value?.[event]?.(arg)
|
||||
}
|
||||
|
||||
async function handleOk() {
|
||||
|
|
@ -208,7 +219,8 @@ $prefix-cls: #{$namespace}-cropper-am;
|
|||
&-cropper {
|
||||
height: 300px;
|
||||
background: #eee;
|
||||
background-image: linear-gradient(
|
||||
background-image:
|
||||
linear-gradient(
|
||||
45deg,
|
||||
rgb(0 0 0 / 25%) 25%,
|
||||
transparent 0,
|
||||
|
|
|
|||
|
|
@ -1,50 +1,17 @@
|
|||
<template>
|
||||
<div :class="getClass" :style="getWrapperStyle">
|
||||
<img
|
||||
v-show="isReady"
|
||||
ref="imgElRef"
|
||||
:alt="alt"
|
||||
:crossorigin="crossorigin"
|
||||
:src="src"
|
||||
:style="getImageStyle"
|
||||
/>
|
||||
<div ref="containerRef" :class="getClass" :style="getWrapperStyle">
|
||||
<img v-show="false" ref="imgElRef" :alt="alt" :crossorigin="crossorigin" :src="src" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties, PropType } from 'vue'
|
||||
import Cropper from 'cropperjs'
|
||||
import 'cropperjs/dist/cropper.css'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
|
||||
defineOptions({ name: 'Cropper' })
|
||||
|
||||
type Options = Cropper.Options
|
||||
|
||||
const defaultOptions: Options = {
|
||||
aspectRatio: 1,
|
||||
zoomable: true,
|
||||
zoomOnTouch: true,
|
||||
zoomOnWheel: true,
|
||||
cropBoxMovable: true,
|
||||
cropBoxResizable: true,
|
||||
toggleDragModeOnDblclick: true,
|
||||
autoCrop: true,
|
||||
background: true,
|
||||
highlight: true,
|
||||
center: true,
|
||||
responsive: true,
|
||||
restore: true,
|
||||
checkCrossOrigin: true,
|
||||
checkOrientation: true,
|
||||
scalable: true,
|
||||
modal: true,
|
||||
guides: true,
|
||||
movable: true,
|
||||
rotatable: true
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
src: propTypes.string.def(''),
|
||||
alt: propTypes.string.def(''),
|
||||
|
|
@ -56,35 +23,21 @@ const props = defineProps({
|
|||
default: undefined
|
||||
},
|
||||
imageStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
|
||||
options: { type: Object as PropType<Options>, default: () => ({}) }
|
||||
options: { type: Object as PropType<Record<string, any>>, default: () => ({}) }
|
||||
})
|
||||
|
||||
const emit = defineEmits(['cropend', 'ready', 'cropendError'])
|
||||
const attrs = useAttrs()
|
||||
const imgElRef = ref<ElRef<HTMLImageElement>>()
|
||||
const cropper = ref<Nullable<Cropper>>()
|
||||
const isReady = ref(false)
|
||||
const imgElRef = ref<HTMLImageElement>()
|
||||
const containerRef = ref<HTMLElement>()
|
||||
const cropper = ref<Cropper>()
|
||||
|
||||
const { getPrefixCls } = useDesign()
|
||||
const prefixCls = getPrefixCls('cropper-image')
|
||||
const debounceRealTimeCroppered = useDebounceFn(realTimeCroppered, 80)
|
||||
|
||||
const getImageStyle = computed((): CSSProperties => {
|
||||
return {
|
||||
height: props.height,
|
||||
maxWidth: '100%',
|
||||
...props.imageStyle
|
||||
}
|
||||
})
|
||||
|
||||
const getClass = computed(() => {
|
||||
return [
|
||||
prefixCls,
|
||||
attrs.class,
|
||||
{
|
||||
[`${prefixCls}--circled`]: props.circled
|
||||
}
|
||||
]
|
||||
return [prefixCls, attrs.class]
|
||||
})
|
||||
const getWrapperStyle = computed((): CSSProperties => {
|
||||
return { height: `${props.height}`.replace(/px/, '') + 'px' }
|
||||
|
|
@ -98,27 +51,39 @@ onUnmounted(() => {
|
|||
|
||||
async function init() {
|
||||
const imgEl = unref(imgElRef)
|
||||
if (!imgEl) {
|
||||
return
|
||||
}
|
||||
const containerEl = unref(containerRef)
|
||||
if (!imgEl || !containerEl) return
|
||||
|
||||
cropper.value = new Cropper(imgEl, {
|
||||
...defaultOptions,
|
||||
ready: () => {
|
||||
isReady.value = true
|
||||
realTimeCroppered()
|
||||
emit('ready', cropper.value)
|
||||
},
|
||||
crop() {
|
||||
debounceRealTimeCroppered()
|
||||
},
|
||||
zoom() {
|
||||
debounceRealTimeCroppered()
|
||||
},
|
||||
cropmove() {
|
||||
debounceRealTimeCroppered()
|
||||
},
|
||||
container: containerEl,
|
||||
...props.options
|
||||
})
|
||||
|
||||
// Wait for custom elements to be ready, then configure
|
||||
await nextTick()
|
||||
const cropperSelection = cropper.value.getCropperSelection()
|
||||
const cropperImage = cropper.value.getCropperImage()
|
||||
|
||||
if (cropperSelection) {
|
||||
cropperSelection.initialCoverage = 0.5
|
||||
cropperSelection.aspectRatio = 1
|
||||
cropperSelection.movable = true
|
||||
cropperSelection.resizable = true
|
||||
cropperSelection.addEventListener('change', () => {
|
||||
debounceRealTimeCroppered()
|
||||
})
|
||||
}
|
||||
|
||||
if (cropperImage) {
|
||||
cropperImage.addEventListener('transform', () => {
|
||||
debounceRealTimeCroppered()
|
||||
})
|
||||
// Emit ready once image loads
|
||||
cropperImage.addEventListener('load', () => {
|
||||
emit('ready', cropper.value)
|
||||
realTimeCroppered()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Real-time display preview
|
||||
|
|
@ -127,17 +92,27 @@ function realTimeCroppered() {
|
|||
}
|
||||
|
||||
// event: return base64 and width and height information after cropping
|
||||
function croppered() {
|
||||
if (!cropper.value) {
|
||||
return
|
||||
async function croppered() {
|
||||
if (!cropper.value) return
|
||||
|
||||
const selection = cropper.value.getCropperSelection()
|
||||
if (!selection) return
|
||||
|
||||
const imgInfo = {
|
||||
x: selection.x,
|
||||
y: selection.y,
|
||||
width: selection.width,
|
||||
height: selection.height
|
||||
}
|
||||
|
||||
try {
|
||||
let canvas = await selection.$toCanvas()
|
||||
if (props.circled) {
|
||||
canvas = getRoundedCanvas(canvas)
|
||||
}
|
||||
let imgInfo = cropper.value.getData()
|
||||
const canvas = props.circled ? getRoundedCanvas() : cropper.value.getCroppedCanvas()
|
||||
canvas.toBlob((blob) => {
|
||||
if (!blob) {
|
||||
return
|
||||
}
|
||||
let fileReader: FileReader = new FileReader()
|
||||
if (!blob) return
|
||||
const fileReader = new FileReader()
|
||||
fileReader.readAsDataURL(blob)
|
||||
fileReader.onloadend = (e) => {
|
||||
emit('cropend', {
|
||||
|
|
@ -149,11 +124,13 @@ function croppered() {
|
|||
emit('cropendError')
|
||||
}
|
||||
}, 'image/png')
|
||||
} catch {
|
||||
// Selection may not be ready yet
|
||||
}
|
||||
}
|
||||
|
||||
// Get a circular picture canvas
|
||||
function getRoundedCanvas() {
|
||||
const sourceCanvas = cropper.value!.getCroppedCanvas()
|
||||
function getRoundedCanvas(sourceCanvas: HTMLCanvasElement) {
|
||||
const canvas = document.createElement('canvas')
|
||||
const context = canvas.getContext('2d')!
|
||||
const width = sourceCanvas.width
|
||||
|
|
@ -169,15 +146,3 @@ function getRoundedCanvas() {
|
|||
return canvas
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
$prefix-cls: #{$namespace}-cropper-image;
|
||||
|
||||
.#{$prefix-cls} {
|
||||
&--circled {
|
||||
.cropper-view-box,
|
||||
.cropper-face {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type Cropper from 'cropperjs'
|
|||
|
||||
export interface CropendResult {
|
||||
imgBase64: string
|
||||
imgInfo: Cropper.Data
|
||||
imgInfo: { x: number; y: number; width: number; height: number }
|
||||
}
|
||||
|
||||
export type { Cropper }
|
||||
|
|
|
|||
|
|
@ -116,7 +116,8 @@ const toggleClick = () => {
|
|||
:row="{
|
||||
label: item.label
|
||||
}"
|
||||
>{{ item.label }}
|
||||
>
|
||||
{{ item.label }}
|
||||
</slot>
|
||||
</template>
|
||||
|
||||
|
|
@ -130,9 +131,7 @@ const toggleClick = () => {
|
|||
<DictTag :type="item.dictType" :value="data[item.field] + ''" />
|
||||
</slot>
|
||||
<slot v-else :name="item.field" :row="data">
|
||||
{{
|
||||
item.mappedField ? data[item.mappedField] : data[item.field]
|
||||
}}
|
||||
{{ item.mappedField ? data[item.mappedField] : data[item.field] }}
|
||||
</slot>
|
||||
</template>
|
||||
</ElDescriptionsItem>
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@ $toolbar-position: -55px;
|
|||
width: 80px;
|
||||
height: 25px;
|
||||
font-size: 12px;
|
||||
color: #6a6a6a;
|
||||
line-height: 25px;
|
||||
color: #6a6a6a;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
box-shadow:
|
||||
|
|
|
|||
|
|
@ -94,9 +94,9 @@ const handleCloneComponent = (component: DiyComponent<any>) => {
|
|||
<style scoped lang="scss">
|
||||
.editor-left {
|
||||
z-index: 1;
|
||||
flex-shrink: 0;
|
||||
user-select: none;
|
||||
box-shadow: 8px 0 8px -8px rgb(0 0 0 / 12%);
|
||||
user-select: none;
|
||||
flex-shrink: 0;
|
||||
|
||||
:deep(.el-collapse) {
|
||||
border-top: none;
|
||||
|
|
|
|||
|
|
@ -22,8 +22,9 @@
|
|||
<div
|
||||
v-if="property.indicator === 'number'"
|
||||
class="absolute bottom-10px right-10px rounded-xl bg-black p-x-8px p-y-2px text-10px text-white opacity-40"
|
||||
>{{ currentIndex }} / {{ property.items.length }}</div
|
||||
>
|
||||
{{ currentIndex }} / {{ property.items.length }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
|
|
|
|||
|
|
@ -55,12 +55,12 @@ const handleToggleFab = () => {
|
|||
/* 模态背景 */
|
||||
.modal-bg {
|
||||
position: absolute;
|
||||
left: calc(50% - 375px / 2);
|
||||
top: 0;
|
||||
left: calc(50% - 375px / 2);
|
||||
z-index: 11;
|
||||
width: 375px;
|
||||
height: 100%;
|
||||
background-color: rgba(#000000, 0.4);
|
||||
background-color: rgb(0 0 0 / 40%);
|
||||
}
|
||||
|
||||
.fab-icon {
|
||||
|
|
|
|||
|
|
@ -192,39 +192,39 @@ const handleAppLinkChange = (appLink: AppLink) => {
|
|||
<style scoped lang="scss">
|
||||
.hot-zone {
|
||||
position: absolute;
|
||||
background: var(--el-color-primary-light-7);
|
||||
opacity: 0.8;
|
||||
border: 1px solid var(--el-color-primary);
|
||||
color: var(--el-color-primary);
|
||||
font-size: 16px;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
color: var(--el-color-primary);
|
||||
cursor: move;
|
||||
background: var(--el-color-primary-light-7);
|
||||
border: 1px solid var(--el-color-primary);
|
||||
opacity: 0.8;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: move;
|
||||
z-index: 10;
|
||||
|
||||
/* 控制点 */
|
||||
.ctrl-dot {
|
||||
position: absolute;
|
||||
z-index: 11;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
border: inherit;
|
||||
background-color: #fff;
|
||||
z-index: 11;
|
||||
border: inherit;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.delete {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
display: none;
|
||||
padding: 2px 2px 6px 6px;
|
||||
background-color: var(--el-color-primary);
|
||||
border-radius: 0 0 0 80%;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
text-align: right;
|
||||
cursor: pointer;
|
||||
background-color: var(--el-color-primary);
|
||||
border-radius: 0 0 0 80%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
|
|
|||
|
|
@ -28,15 +28,15 @@ const props = defineProps<{ property: HotZoneProperty }>()
|
|||
<style scoped lang="scss">
|
||||
.hot-zone {
|
||||
position: absolute;
|
||||
background: var(--el-color-primary-light-7);
|
||||
opacity: 0.8;
|
||||
border: 1px solid var(--el-color-primary);
|
||||
color: var(--el-color-primary);
|
||||
font-size: 14px;
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
font-size: 14px;
|
||||
color: var(--el-color-primary);
|
||||
cursor: move;
|
||||
background: var(--el-color-primary-light-7);
|
||||
border: 1px solid var(--el-color-primary);
|
||||
opacity: 0.8;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: move;
|
||||
z-index: 10;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -42,22 +42,22 @@ const handleOpenEditDialog = () => {
|
|||
<style scoped lang="scss">
|
||||
.hot-zone {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
font-size: 12px;
|
||||
color: #fff;
|
||||
cursor: move;
|
||||
background: #409effbf;
|
||||
border: 1px solid var(--el-color-primary);
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: move;
|
||||
|
||||
/* 控制点 */
|
||||
.ctrl-dot {
|
||||
position: absolute;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -103,13 +103,16 @@ watch(
|
|||
.el-carousel__indicator {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
|
||||
.el-carousel__button {
|
||||
--el-carousel-indicator-height: 6px;
|
||||
--el-carousel-indicator-width: 6px;
|
||||
--el-carousel-indicator-out-color: #ff6000;
|
||||
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.el-carousel__indicator.is-active {
|
||||
.el-carousel__button {
|
||||
--el-carousel-indicator-width: 12px;
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@ defineOptions({ name: 'NavigationBarCellProperty' })
|
|||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: NavigationBarCellProperty[]
|
||||
isMp: boolean
|
||||
modelValue?: NavigationBarCellProperty[]
|
||||
isMp?: boolean
|
||||
}>(),
|
||||
{
|
||||
modelValue: () => [],
|
||||
|
|
|
|||
|
|
@ -67,10 +67,10 @@ const getSearchProp = computed(() => (cell: NavigationBarCellProperty) => {
|
|||
.navigation-bar {
|
||||
display: flex;
|
||||
height: 50px;
|
||||
padding: 0 6px;
|
||||
background: #fff;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 6px;
|
||||
|
||||
/* 左边 */
|
||||
.left {
|
||||
|
|
|
|||
|
|
@ -77,7 +77,8 @@
|
|||
v-if="property.fields.marketPrice.show && spu.marketPrice"
|
||||
class="ml-4px text-10px line-through"
|
||||
:style="{ color: property.fields.marketPrice.color }"
|
||||
>¥{{ fenToYuan(spu.marketPrice) }}
|
||||
>
|
||||
¥{{ fenToYuan(spu.marketPrice) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-12px">
|
||||
|
|
|
|||
|
|
@ -74,8 +74,9 @@
|
|||
v-if="property.fields.marketPrice.show && spu.marketPrice"
|
||||
class="ml-4px text-10px line-through"
|
||||
:style="{ color: property.fields.marketPrice.color }"
|
||||
>¥{{ fenToYuan(spu.marketPrice) }}</span
|
||||
>
|
||||
¥{{ fenToYuan(spu.marketPrice) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-12px">
|
||||
<!-- 销量 -->
|
||||
|
|
|
|||
|
|
@ -74,8 +74,9 @@
|
|||
v-if="property.fields.marketPrice.show && spu.marketPrice"
|
||||
class="ml-4px text-10px line-through"
|
||||
:style="{ color: property.fields.marketPrice.color }"
|
||||
>¥{{ fenToYuan(spu.marketPrice) }}</span
|
||||
>
|
||||
¥{{ fenToYuan(spu.marketPrice) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-12px">
|
||||
<!-- 销量 -->
|
||||
|
|
|
|||
|
|
@ -583,12 +583,12 @@ $toolbar-height: 42px;
|
|||
gap: 8px;
|
||||
|
||||
:deep(.el-tag) {
|
||||
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.1);
|
||||
border: none;
|
||||
box-shadow: 0 2px 8px 0 rgb(0 0 0 / 10%);
|
||||
|
||||
.el-tag__content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ const { getPrefixCls } = useDesign()
|
|||
const prefixCls = getPrefixCls('form')
|
||||
|
||||
export default defineComponent({
|
||||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
name: 'Form',
|
||||
props: {
|
||||
// 生成Form的布局结构数组
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
<!-- 数据字典 Select 选择器 -->
|
||||
<template>
|
||||
<el-select v-if="selectType === 'select'" class="w-1/1" v-bind="attrs">
|
||||
<el-select
|
||||
v-if="selectType === 'select'"
|
||||
v-model="selectedValue"
|
||||
class="w-1/1"
|
||||
v-bind="attrs"
|
||||
@change="handleChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(dict, index) in getDictOptions"
|
||||
:key="index"
|
||||
|
|
@ -8,12 +14,24 @@
|
|||
:value="dict.value"
|
||||
/>
|
||||
</el-select>
|
||||
<el-radio-group v-if="selectType === 'radio'" class="w-1/1" v-bind="attrs">
|
||||
<el-radio-group
|
||||
v-if="selectType === 'radio'"
|
||||
v-model="selectedValue"
|
||||
class="w-1/1"
|
||||
v-bind="attrs"
|
||||
@change="handleChange"
|
||||
>
|
||||
<el-radio v-for="(dict, index) in getDictOptions" :key="index" :value="dict.value">
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
<el-checkbox-group v-if="selectType === 'checkbox'" class="w-1/1" v-bind="attrs">
|
||||
<el-checkbox-group
|
||||
v-if="selectType === 'checkbox'"
|
||||
v-model="selectedValue"
|
||||
class="w-1/1"
|
||||
v-bind="attrs"
|
||||
@change="handleChange"
|
||||
>
|
||||
<el-checkbox
|
||||
v-for="(dict, index) in getDictOptions"
|
||||
:key="index"
|
||||
|
|
@ -33,6 +51,7 @@ const attrs = useAttrs()
|
|||
// 接受父组件参数
|
||||
interface Props {
|
||||
dictType: string // 字典类型
|
||||
modelValue?: any // 选中值,由 form-create 默认 modelValue 绑定
|
||||
valueType?: 'str' | 'int' | 'bool' // 字典值类型
|
||||
selectType?: 'select' | 'radio' | 'checkbox' // 选择器类型,下拉框 select、多选框 checkbox、单选框 radio
|
||||
formCreateInject?: any
|
||||
|
|
@ -43,6 +62,20 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
selectType: 'select'
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: any): void
|
||||
}>()
|
||||
|
||||
const selectedValue = ref<any>()
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
selectedValue.value = newValue
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// 获得字典配置
|
||||
const getDictOptions = computed(() => {
|
||||
switch (props.valueType) {
|
||||
|
|
@ -56,4 +89,8 @@ const getDictOptions = computed(() => {
|
|||
return []
|
||||
}
|
||||
})
|
||||
|
||||
const handleChange = (value: any) => {
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ const displayUrl = computed(() => props.url || props.modelValue || '') // 显示
|
|||
const showPreview = computed(() => {
|
||||
return displayUrl.value && isUrl(displayUrl.value)
|
||||
}) // 是否显示预览
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
@ -64,9 +63,9 @@ const showPreview = computed(() => {
|
|||
}
|
||||
|
||||
.iframe-preview {
|
||||
overflow: hidden;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.iframe-content {
|
||||
|
|
@ -76,11 +75,11 @@ const showPreview = computed(() => {
|
|||
|
||||
.iframe-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 200px;
|
||||
background-color: #fafafa;
|
||||
border: 1px dashed #dcdfe6;
|
||||
border-radius: 4px;
|
||||
background-color: #fafafa;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import request from '@/config/axios'
|
|||
import { isEmpty } from '@/utils/is'
|
||||
import { ApiSelectProps } from '@/components/FormCreate/src/type'
|
||||
import { jsonParse } from '@/utils'
|
||||
import { useUserStoreWithOut } from '@/store/modules/user'
|
||||
import { getCurrentUserId } from '@/utils/auth'
|
||||
|
||||
export const useApiSelect = (option: ApiSelectProps) => {
|
||||
return defineComponent({
|
||||
|
|
@ -99,9 +99,7 @@ export const useApiSelect = (option: ApiSelectProps) => {
|
|||
}
|
||||
|
||||
// 获取当前用户 ID
|
||||
const userStore = useUserStoreWithOut()
|
||||
const user = userStore.getUser
|
||||
const currentUserId = user?.id
|
||||
const currentUserId = getCurrentUserId()
|
||||
if (currentUserId) {
|
||||
// 根据多选/单选模式设置默认值
|
||||
const defaultValue = props.multiple ? [currentUserId] : currentUserId
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ export const useUploadImgRule = () => {
|
|||
{
|
||||
type: 'switch',
|
||||
field: 'disabled',
|
||||
title: '是否显示删除按钮',
|
||||
value: true
|
||||
title: '是否禁用',
|
||||
value: false
|
||||
},
|
||||
{
|
||||
type: 'switch',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { propTypes } from '@/utils/propTypes'
|
||||
import Iconify from '@purge-icons/generated'
|
||||
import { Icon as IconifyIcon } from '@iconify/vue'
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
|
||||
defineOptions({ name: 'Icon' })
|
||||
|
|
@ -20,57 +20,16 @@ const props = defineProps({
|
|||
svgClass: propTypes.string.def('')
|
||||
})
|
||||
|
||||
const elRef = ref<ElRef>(null)
|
||||
|
||||
const isLocal = computed(() => props.icon?.startsWith('svg-icon:'))
|
||||
|
||||
const symbolId = computed(() => {
|
||||
return unref(isLocal) ? `#icon-${props.icon.split('svg-icon:')[1]}` : props.icon
|
||||
})
|
||||
|
||||
const getIconifyStyle = computed(() => {
|
||||
const { color, size } = props
|
||||
return {
|
||||
fontSize: `${size}px`,
|
||||
height: '1em',
|
||||
color
|
||||
}
|
||||
})
|
||||
|
||||
const getSvgClass = computed(() => {
|
||||
const { svgClass } = props
|
||||
return `iconify ${svgClass}`
|
||||
})
|
||||
|
||||
const updateIcon = async (icon: string) => {
|
||||
if (unref(isLocal)) return
|
||||
|
||||
const el = unref(elRef)
|
||||
if (!el) return
|
||||
|
||||
await nextTick()
|
||||
|
||||
if (!icon) return
|
||||
|
||||
const svg = Iconify.renderSVG(icon, {})
|
||||
if (svg) {
|
||||
el.textContent = ''
|
||||
el.appendChild(svg)
|
||||
} else {
|
||||
const span = document.createElement('span')
|
||||
span.className = 'iconify'
|
||||
span.dataset.icon = icon
|
||||
el.textContent = ''
|
||||
el.appendChild(span)
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.icon,
|
||||
(icon: string) => {
|
||||
updateIcon(icon)
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -79,8 +38,11 @@ watch(
|
|||
<use :xlink:href="symbolId" />
|
||||
</svg>
|
||||
|
||||
<span v-else ref="elRef" :class="$attrs.class" :style="getIconifyStyle">
|
||||
<span :class="getSvgClass" :data-icon="symbolId"></span>
|
||||
</span>
|
||||
<IconifyIcon
|
||||
v-else
|
||||
:icon="symbolId"
|
||||
:class="getSvgClass"
|
||||
:style="{ fontSize: `${size}px`, color }"
|
||||
/>
|
||||
</ElIcon>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ defineProps({
|
|||
title: propTypes.string.def(''),
|
||||
schema: {
|
||||
type: Array as PropType<Array<string | TipSchema>>,
|
||||
required: true,
|
||||
default: () => []
|
||||
},
|
||||
showIndex: propTypes.bool.def(true),
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ const { modelValue, color } = useVModels(props, emit)
|
|||
<style scoped lang="scss">
|
||||
:deep(.el-input-group__append) {
|
||||
padding: 0;
|
||||
|
||||
.el-color-picker__trigger {
|
||||
padding: 0;
|
||||
border-left: none;
|
||||
|
|
|
|||
|
|
@ -225,15 +225,16 @@ const eachCube = (callback: (x: number, y: number, cube: Cube) => void) => {
|
|||
<style lang="scss" scoped>
|
||||
.cube-table {
|
||||
position: relative;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
|
||||
.cube {
|
||||
border: 1px solid var(--el-border-color);
|
||||
text-align: center;
|
||||
color: var(--el-text-color-secondary);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid var(--el-border-color);
|
||||
box-sizing: border-box;
|
||||
|
||||
&.active {
|
||||
background: var(--el-color-primary-light-9);
|
||||
}
|
||||
|
|
@ -242,28 +243,28 @@ const eachCube = (callback: (x: number, y: number, cube: Cube) => void) => {
|
|||
.hot-area {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
color: var(--el-color-primary);
|
||||
cursor: pointer;
|
||||
background: var(--el-color-primary-light-8);
|
||||
border: 1px solid var(--el-color-primary);
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--el-color-primary);
|
||||
background: var(--el-color-primary-light-8);
|
||||
color: var(--el-color-primary);
|
||||
box-sizing: border-box;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
cursor: pointer;
|
||||
|
||||
.btn-delete {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-color: #fff;
|
||||
border-radius: 50%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||