Compare commits
218
Commits
wfc-modules-user
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0b794afeb | ||
|
|
0ac1ec9ca1 | ||
|
|
e4b00931c1 | ||
|
|
842be01104 | ||
|
|
75e03f93ac | ||
|
|
89e696abc8 | ||
|
|
d137f49ca0 | ||
|
|
5da91e48c8 | ||
|
|
de5fc010f7 | ||
|
|
5f22ef60a9 | ||
|
|
de7445cd99 | ||
|
|
abda1ebe54 | ||
|
|
c96e307060 | ||
|
|
e8c98e77d3 | ||
|
|
d0cca3bbfb | ||
|
|
c9b4e430e9 | ||
|
|
bc89546ec6 | ||
|
|
83a8fb9a98 | ||
|
|
c518ebd921 | ||
|
|
ed3e583f71 | ||
|
|
6a694d479a | ||
|
|
c56ac9ec62 | ||
|
|
d894349479 | ||
|
|
324ed9d114 | ||
|
|
07ebbf45b1 | ||
|
|
d8f283da3f | ||
|
|
c23a76069d | ||
|
|
87d2e1adeb | ||
|
|
dcd0c706fa | ||
|
|
b6fed795b2 | ||
|
|
84e23675ab | ||
|
|
4422a2bab2 | ||
|
|
db72e6cec0 | ||
|
|
59d54185f5 | ||
|
|
b27aebed73 | ||
|
|
42d10809e7 | ||
|
|
9690b9e1f8 | ||
|
|
8ce4c19962 | ||
|
|
2508613b35 | ||
|
|
21969b9a33 | ||
|
|
04c076272a | ||
|
|
a342cfc64e | ||
|
|
946ae91d99 | ||
|
|
ccccfd347c | ||
|
|
23949528a7 | ||
|
|
11e1e4bcea | ||
|
|
21f372c9b5 | ||
|
|
69b28f3a66 | ||
|
|
c17b16ac33 | ||
|
|
b0aa5ec475 | ||
|
|
0ff91fb085 | ||
|
|
9550d9e3ce | ||
|
|
172357487c | ||
|
|
8189b8152f | ||
|
|
5a2f8ecb17 | ||
|
|
f6a7ca1883 | ||
|
|
1c3bff4f6f | ||
|
|
8a15e933ac | ||
|
|
292a7c0ab0 | ||
|
|
089ce77974 | ||
|
|
c38b67ff57 | ||
|
|
6ce34dd63c | ||
|
|
1457c3d39d | ||
|
|
de9e6fea12 | ||
|
|
39a43ab75d | ||
|
|
654362b2d9 | ||
|
|
9c17330555 | ||
|
|
d586e54c51 | ||
|
|
eed336cb00 | ||
|
|
5c3734945f | ||
|
|
2110a60a6b | ||
|
|
1b3b2d7497 | ||
|
|
59f77adcb3 | ||
|
|
7432c02ddf | ||
|
|
8b6e4b27e6 | ||
|
|
c707a338c6 | ||
|
|
425c4cf38d | ||
|
|
10e21ea516 | ||
|
|
ec83482e99 | ||
|
|
02c0ae6ff7 | ||
|
|
1f55660ed8 | ||
|
|
be3c39dbe5 | ||
|
|
fa866cff38 | ||
|
|
345e6f7177 | ||
|
|
d9dacf63fa | ||
|
|
051b5bda56 | ||
|
|
12472f5a2e | ||
|
|
b4f48789df | ||
|
|
d8c665b8ae | ||
|
|
4ef332f5e9 | ||
|
|
298d5ef363 | ||
|
|
4987e76843 | ||
|
|
5561d924ab | ||
|
|
8729c2d1f7 | ||
|
|
0864a040d9 | ||
|
|
41fbdafc54 | ||
|
|
2ac813ec8f | ||
|
|
fd1a6edc85 | ||
|
|
631fd1d5ad | ||
|
|
f9ecdfcb71 | ||
|
|
3b08706ca9 | ||
|
|
e3032bb850 | ||
|
|
28ab9dceeb | ||
|
|
e6a5d91b5e | ||
|
|
f13dcac7db | ||
|
|
35eed2393e | ||
|
|
4f35b17b03 | ||
|
|
410b6c40cb | ||
|
|
bf149afbbb | ||
|
|
f587e4f673 | ||
|
|
c1ad6b4e9d | ||
|
|
56748228bf | ||
|
|
37989c71ec | ||
|
|
fd0d541fdf | ||
|
|
7f60eafc6d | ||
|
|
a428b973df | ||
|
|
6532f2a776 | ||
|
|
acf802e6c0 | ||
|
|
02255d5be3 | ||
|
|
72343da432 | ||
|
|
b6961c9cfd | ||
|
|
eb883385e8 | ||
|
|
32aa82a599 | ||
|
|
d94c35ed49 | ||
|
|
e74db62c27 | ||
|
|
06dcb2f36b | ||
|
|
ada516208f | ||
|
|
a2e1194d44 | ||
|
|
ba535e442f | ||
|
|
dd390a8a0f | ||
|
|
66b705ab17 | ||
|
|
196ff4bcdc | ||
|
|
1c2fa63615 | ||
|
|
f2e03e70ea | ||
|
|
13c910e2e5 | ||
|
|
7d12ae5011 | ||
|
|
8546cfc615 | ||
|
|
2775348585 | ||
|
|
5387933de7 | ||
|
|
5eeaa824ff | ||
|
|
5b4f4b4ae1 | ||
|
|
a974a042b0 | ||
|
|
8171c2b975 | ||
|
|
a8f3e247c6 | ||
|
|
489d4c8603 | ||
|
|
219584525f | ||
|
|
e6aa12bcac | ||
|
|
080f6b9964 | ||
|
|
7fbaf0d67f | ||
|
|
37fee941d2 | ||
|
|
06629f6bb2 | ||
|
|
77a40d12e6 | ||
|
|
a72217a5ea | ||
|
|
d07189e936 | ||
|
|
ed721374fe | ||
|
|
e6cd74498b | ||
|
|
0b20cec9bd | ||
|
|
a9a6fd9b88 | ||
|
|
c0c912f08b | ||
|
|
5fad65960c | ||
|
|
134a417eb1 | ||
|
|
28200f4931 | ||
|
|
4708df2a6f | ||
|
|
48a69c8b4b | ||
|
|
8e69a7ed7e | ||
|
|
4c709fdb95 | ||
|
|
462dd40e92 | ||
|
|
168e4bf1b8 | ||
|
|
b9026be4b1 | ||
|
|
a2a92ed4da | ||
|
|
0977880d05 | ||
|
|
bbc4f8669b | ||
|
|
fd49c64c76 | ||
|
|
6dee934e9a | ||
|
|
8b2edce4e1 | ||
|
|
61c62f48b0 | ||
|
|
1267648ebc | ||
|
|
4b292b8a74 | ||
|
|
3e2d8faf5e | ||
|
|
0a1f0d94d8 | ||
|
|
6860c035c6 | ||
|
|
fc40451b50 | ||
|
|
0f94a5b80d | ||
|
|
3e2bc5ab9d | ||
|
|
52ad7dbe05 | ||
|
|
b503b85472 | ||
|
|
f65cb5058e | ||
|
|
de19d9f400 | ||
|
|
8ac4d3f9df | ||
|
|
1000f591ef | ||
|
|
59c80cd7a7 | ||
|
|
3bb0b9d85c | ||
|
|
caa97e7783 | ||
|
|
4ff8bcd475 | ||
|
|
2707dc3643 | ||
|
|
19fd64daa0 | ||
|
|
756f42a92f | ||
|
|
f98fdf7e27 | ||
|
|
0939032e9b | ||
|
|
609edf74bc | ||
|
|
c581ad8718 | ||
|
|
a8df414a2b | ||
|
|
5118479630 | ||
|
|
42fad1ca96 | ||
|
|
7649d22630 | ||
|
|
e0d991da15 | ||
|
|
57e33781d1 | ||
|
|
55d50ef8a5 | ||
|
|
d2f25695d8 | ||
|
|
b2b32fb3d4 | ||
|
|
0d25f1fa0e | ||
|
|
c6b0c60392 | ||
|
|
13ee5a3849 | ||
|
|
1627feb9a4 | ||
|
|
212cf9d4c0 | ||
|
|
b82f71b763 | ||
|
|
074f9282dd | ||
|
|
a1dbcd1f00 |
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
VITE_BASE_URL=/
|
VITE_BASE_URL=/
|
||||||
|
|
||||||
VITE_APP_TITLE="WANFi Platform"
|
VITE_APP_TITLE="Platform"
|
||||||
|
|
||||||
# the prefix of the icon name
|
# the prefix of the icon name
|
||||||
VITE_ICON_PREFIX=icon
|
VITE_ICON_PREFIX=icon
|
||||||
@@ -35,5 +35,3 @@ VITE_SERVICE_EXPIRED_TOKEN_CODES=403
|
|||||||
|
|
||||||
VITE_SERVICE_SERVER_ERROR_CODE=500
|
VITE_SERVICE_SERVER_ERROR_CODE=500
|
||||||
|
|
||||||
# when the route mode is static, the defined super role
|
|
||||||
VITE_STATIC_SUPER_ROLE=R_SUPER
|
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
VITE_ROUTER_HISTORY_MODE=hash
|
VITE_ROUTER_HISTORY_MODE=hash
|
||||||
|
|
||||||
# frontend service base url, prod environment
|
# frontend service base url, prod environment
|
||||||
VITE_BASE_URL=/u
|
VITE_BASE_URL=/sys
|
||||||
|
|
||||||
# backend service base url, prod environment
|
# backend service base url, prod environment
|
||||||
VITE_SERVICE_BASE_URL=/u-api
|
VITE_SERVICE_BASE_URL=/sys-api
|
||||||
|
|
||||||
# other backend service base url, prod environment
|
# other backend service base url, prod environment
|
||||||
VITE_OTHER_SERVICE_BASE_URL= `{
|
VITE_OTHER_SERVICE_BASE_URL= `{
|
||||||
|
|||||||
@@ -34,3 +34,4 @@ yarn.lock
|
|||||||
|
|
||||||
.VSCodeCounter
|
.VSCodeCounter
|
||||||
**/.vitepress/cache
|
**/.vitepress/cache
|
||||||
|
src/typings/components.d.ts
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"useTabs": false,
|
||||||
|
"singleQuote": true,
|
||||||
|
"semi": true,
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"jsxBracketSameLine": false,
|
||||||
|
"arrowParens": "avoid"
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" href="/favicon.svg" />
|
<link rel="icon" href="/favicon.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<script src="/langs/zh-cn.js"></script>
|
||||||
|
<script src="/langs/en-us.js"></script>
|
||||||
<title>%VITE_APP_TITLE%</title>
|
<title>%VITE_APP_TITLE%</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
+6
-2
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "vue-antd",
|
"name": "wanfi-system",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
"typecheck": "vue-tsc --noEmit --skipLibCheck"
|
"typecheck": "vue-tsc --noEmit --skipLibCheck"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ant-design/icons-vue": "^7.0.1",
|
||||||
"@better-scroll/core": "2.5.1",
|
"@better-scroll/core": "2.5.1",
|
||||||
"@iconify/vue": "4.1.2",
|
"@iconify/vue": "4.1.2",
|
||||||
"@sa/axios": "workspace:*",
|
"@sa/axios": "workspace:*",
|
||||||
@@ -23,16 +24,19 @@
|
|||||||
"clipboard": "2.0.11",
|
"clipboard": "2.0.11",
|
||||||
"dayjs": "1.11.11",
|
"dayjs": "1.11.11",
|
||||||
"echarts": "5.5.0",
|
"echarts": "5.5.0",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
"nprogress": "0.2.0",
|
"nprogress": "0.2.0",
|
||||||
"pinia": "2.1.7",
|
"pinia": "2.1.7",
|
||||||
"vue": "3.4.27",
|
"vue": "3.4.27",
|
||||||
"vue-draggable-plus": "0.5.0",
|
"vue-draggable-plus": "0.5.0",
|
||||||
"vue-i18n": "9.13.1",
|
"vue-i18n": "9.13.1",
|
||||||
"vue-router": "4.3.2"
|
"vue-router": "4.3.2",
|
||||||
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@elegant-router/vue": "0.3.7",
|
"@elegant-router/vue": "0.3.7",
|
||||||
|
"@types/file-saver": "^2.0.7",
|
||||||
"@iconify/json": "2.2.217",
|
"@iconify/json": "2.2.217",
|
||||||
"@sa/uno-preset": "workspace:*",
|
"@sa/uno-preset": "workspace:*",
|
||||||
"@soybeanjs/eslint-config": "1.3.6",
|
"@soybeanjs/eslint-config": "1.3.6",
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ function createCommonRequest<ResponseData = any>(
|
|||||||
|
|
||||||
instance.interceptors.response.use(
|
instance.interceptors.response.use(
|
||||||
async response => {
|
async response => {
|
||||||
if (opts.isBackendSuccess(response)) {
|
if (opts.isBackendSuccess(response) || response.config?.responseType === "blob") {
|
||||||
return Promise.resolve(response);
|
return Promise.resolve(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,6 @@ export function createRequest<ResponseData = any, State = Record<string, unknown
|
|||||||
const response: AxiosResponse<ResponseData> = await instance(config);
|
const response: AxiosResponse<ResponseData> = await instance(config);
|
||||||
|
|
||||||
const responseType = response.config?.responseType || 'json';
|
const responseType = response.config?.responseType || 'json';
|
||||||
|
|
||||||
if (responseType === 'json') {
|
if (responseType === 'json') {
|
||||||
return opts.transformBackendResponse(response);
|
return opts.transformBackendResponse(response);
|
||||||
}
|
}
|
||||||
@@ -154,7 +153,6 @@ export function createFlatRequest<ResponseData = any, State = Record<string, unk
|
|||||||
const response: AxiosResponse<ResponseData> = await instance(config);
|
const response: AxiosResponse<ResponseData> = await instance(config);
|
||||||
|
|
||||||
const responseType = response.config?.responseType || 'json';
|
const responseType = response.config?.responseType || 'json';
|
||||||
|
|
||||||
if (responseType === 'json') {
|
if (responseType === 'json') {
|
||||||
const data = opts.transformBackendResponse(response);
|
const data = opts.transformBackendResponse(response);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export function createRetryOptions(config?: Partial<CreateAxiosDefaults>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createAxiosConfig(config?: Partial<CreateAxiosDefaults>) {
|
export function createAxiosConfig(config?: Partial<CreateAxiosDefaults>) {
|
||||||
const TEN_SECONDS = 10 * 1000;
|
const TEN_SECONDS = 30 * 1000;
|
||||||
|
|
||||||
const axiosConfig: CreateAxiosDefaults = {
|
const axiosConfig: CreateAxiosDefaults = {
|
||||||
timeout: TEN_SECONDS,
|
timeout: TEN_SECONDS,
|
||||||
|
|||||||
@@ -59,17 +59,16 @@ export type TableConfig<A extends ApiFn, T, C> = {
|
|||||||
immediate?: boolean;
|
immediate?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function useHookTable<A extends ApiFn, T, C>(config: TableConfig<A, T, C>) {
|
export default function useHookTable(config: any) {
|
||||||
const { loading, startLoading, endLoading } = useLoading();
|
const { loading, startLoading, endLoading } = useLoading();
|
||||||
const { bool: empty, setBool: setEmpty } = useBoolean();
|
const { bool: empty, setBool: setEmpty } = useBoolean();
|
||||||
|
|
||||||
const { apiFn, apiParams, transformer, immediate = true, getColumnChecks, getColumns } = config;
|
const { apiFn, apiParams, transformer, immediate = true, getColumnChecks, getColumns } = config;
|
||||||
|
|
||||||
const searchParams: NonNullable<Parameters<A>[0]> = reactive({ ...apiParams });
|
const searchParams: any = reactive({ ...apiParams });
|
||||||
|
const allColumns = ref(config.columns()) as Ref<any>;
|
||||||
|
|
||||||
const allColumns = ref(config.columns()) as Ref<C[]>;
|
const data: Ref<any> = ref([]);
|
||||||
|
|
||||||
const data: Ref<T[]> = ref([]);
|
|
||||||
|
|
||||||
const columnChecks: Ref<TableColumnCheck[]> = ref(getColumnChecks(config.columns()));
|
const columnChecks: Ref<TableColumnCheck[]> = ref(getColumnChecks(config.columns()));
|
||||||
|
|
||||||
@@ -82,7 +81,7 @@ export default function useHookTable<A extends ApiFn, T, C>(config: TableConfig<
|
|||||||
|
|
||||||
const defaultChecks = getColumnChecks(allColumns.value);
|
const defaultChecks = getColumnChecks(allColumns.value);
|
||||||
|
|
||||||
columnChecks.value = defaultChecks.map(col => ({
|
columnChecks.value = defaultChecks.map((col:any) => ({
|
||||||
...col,
|
...col,
|
||||||
checked: checkMap.get(col.key) ?? col.checked
|
checked: checkMap.get(col.key) ?? col.checked
|
||||||
}));
|
}));
|
||||||
@@ -92,10 +91,9 @@ export default function useHookTable<A extends ApiFn, T, C>(config: TableConfig<
|
|||||||
startLoading();
|
startLoading();
|
||||||
|
|
||||||
const formattedParams = formatSearchParams(searchParams);
|
const formattedParams = formatSearchParams(searchParams);
|
||||||
|
|
||||||
const response = await apiFn(formattedParams);
|
const response = await apiFn(formattedParams);
|
||||||
|
|
||||||
const transformed = transformer(response as Awaited<ReturnType<A>>);
|
const transformed = transformer(response as Awaited<any>);
|
||||||
|
|
||||||
data.value = transformed.rows;
|
data.value = transformed.rows;
|
||||||
|
|
||||||
@@ -123,7 +121,7 @@ export default function useHookTable<A extends ApiFn, T, C>(config: TableConfig<
|
|||||||
*
|
*
|
||||||
* @param params
|
* @param params
|
||||||
*/
|
*/
|
||||||
function updateSearchParams(params: Partial<Parameters<A>[0]>) {
|
function updateSearchParams(params: any) {
|
||||||
Object.assign(searchParams, params);
|
Object.assign(searchParams, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+91
@@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@ant-design/icons-vue':
|
||||||
|
specifier: ^7.0.1
|
||||||
|
version: 7.0.1(vue@3.4.27(typescript@5.4.5))
|
||||||
'@better-scroll/core':
|
'@better-scroll/core':
|
||||||
specifier: 2.5.1
|
specifier: 2.5.1
|
||||||
version: 2.5.1
|
version: 2.5.1
|
||||||
@@ -41,6 +44,9 @@ importers:
|
|||||||
echarts:
|
echarts:
|
||||||
specifier: 5.5.0
|
specifier: 5.5.0
|
||||||
version: 5.5.0
|
version: 5.5.0
|
||||||
|
file-saver:
|
||||||
|
specifier: ^2.0.5
|
||||||
|
version: 2.0.5
|
||||||
lodash-es:
|
lodash-es:
|
||||||
specifier: 4.17.21
|
specifier: 4.17.21
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
@@ -62,6 +68,9 @@ importers:
|
|||||||
vue-router:
|
vue-router:
|
||||||
specifier: 4.3.2
|
specifier: 4.3.2
|
||||||
version: 4.3.2(vue@3.4.27(typescript@5.4.5))
|
version: 4.3.2(vue@3.4.27(typescript@5.4.5))
|
||||||
|
xlsx:
|
||||||
|
specifier: ^0.18.5
|
||||||
|
version: 0.18.5
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@elegant-router/vue':
|
'@elegant-router/vue':
|
||||||
specifier: 0.3.7
|
specifier: 0.3.7
|
||||||
@@ -75,6 +84,9 @@ importers:
|
|||||||
'@soybeanjs/eslint-config':
|
'@soybeanjs/eslint-config':
|
||||||
specifier: 1.3.6
|
specifier: 1.3.6
|
||||||
version: 1.3.6(@types/eslint@8.56.10)(@unocss/eslint-config@0.60.4(eslint@9.4.0)(typescript@5.4.5))(eslint-plugin-vue@9.26.0(eslint@9.4.0))(eslint@9.4.0)(typescript@5.4.5)(vue-eslint-parser@9.4.3(eslint@9.4.0))
|
version: 1.3.6(@types/eslint@8.56.10)(@unocss/eslint-config@0.60.4(eslint@9.4.0)(typescript@5.4.5))(eslint-plugin-vue@9.26.0(eslint@9.4.0))(eslint@9.4.0)(typescript@5.4.5)(vue-eslint-parser@9.4.3(eslint@9.4.0))
|
||||||
|
'@types/file-saver':
|
||||||
|
specifier: ^2.0.7
|
||||||
|
version: 2.0.7
|
||||||
'@types/lodash-es':
|
'@types/lodash-es':
|
||||||
specifier: 4.17.12
|
specifier: 4.17.12
|
||||||
version: 4.17.12
|
version: 4.17.12
|
||||||
@@ -910,6 +922,9 @@ packages:
|
|||||||
'@types/estree@1.0.5':
|
'@types/estree@1.0.5':
|
||||||
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
||||||
|
|
||||||
|
'@types/file-saver@2.0.7':
|
||||||
|
resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==}
|
||||||
|
|
||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
@@ -1251,6 +1266,10 @@ packages:
|
|||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
adler-32@1.3.1:
|
||||||
|
resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
ajv@6.12.6:
|
ajv@6.12.6:
|
||||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||||
|
|
||||||
@@ -1462,6 +1481,10 @@ packages:
|
|||||||
caniuse-lite@1.0.30001629:
|
caniuse-lite@1.0.30001629:
|
||||||
resolution: {integrity: sha512-c3dl911slnQhmxUIT4HhYzT7wnBK/XYpGnYLOj4nJBaRiw52Ibe7YxlDaAeRECvA786zCuExhxIUJ2K7nHMrBw==}
|
resolution: {integrity: sha512-c3dl911slnQhmxUIT4HhYzT7wnBK/XYpGnYLOj4nJBaRiw52Ibe7YxlDaAeRECvA786zCuExhxIUJ2K7nHMrBw==}
|
||||||
|
|
||||||
|
cfb@1.2.2:
|
||||||
|
resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
chai@4.4.1:
|
chai@4.4.1:
|
||||||
resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==}
|
resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -1523,6 +1546,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
|
resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
|
codepage@1.15.0:
|
||||||
|
resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
collection-visit@1.0.0:
|
collection-visit@1.0.0:
|
||||||
resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==}
|
resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -1601,6 +1628,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
|
crc-32@1.2.2:
|
||||||
|
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
cross-spawn@7.0.3:
|
cross-spawn@7.0.3:
|
||||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@@ -2121,6 +2153,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
||||||
engines: {node: '>=16.0.0'}
|
engines: {node: '>=16.0.0'}
|
||||||
|
|
||||||
|
file-saver@2.0.5:
|
||||||
|
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
|
||||||
|
|
||||||
fill-range@4.0.0:
|
fill-range@4.0.0:
|
||||||
resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==}
|
resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -2172,6 +2207,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
|
frac@1.1.2:
|
||||||
|
resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
fragment-cache@0.2.1:
|
fragment-cache@0.2.1:
|
||||||
resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==}
|
resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -3533,6 +3572,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==}
|
resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
ssf@0.11.2:
|
||||||
|
resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
stable@0.1.8:
|
stable@0.1.8:
|
||||||
resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
|
resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
|
||||||
deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
|
deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility'
|
||||||
@@ -4060,10 +4103,18 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
wmf@1.0.2:
|
||||||
|
resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
word-wrap@1.2.5:
|
word-wrap@1.2.5:
|
||||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
word@0.3.0:
|
||||||
|
resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
|
||||||
wrap-ansi@7.0.0:
|
wrap-ansi@7.0.0:
|
||||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -4079,6 +4130,11 @@ packages:
|
|||||||
wrappy@1.0.2:
|
wrappy@1.0.2:
|
||||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||||
|
|
||||||
|
xlsx@0.18.5:
|
||||||
|
resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
|
||||||
|
engines: {node: '>=0.8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
xml-name-validator@4.0.0:
|
xml-name-validator@4.0.0:
|
||||||
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
|
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -4734,6 +4790,8 @@ snapshots:
|
|||||||
|
|
||||||
'@types/estree@1.0.5': {}
|
'@types/estree@1.0.5': {}
|
||||||
|
|
||||||
|
'@types/file-saver@2.0.7': {}
|
||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/json5@0.0.29': {}
|
'@types/json5@0.0.29': {}
|
||||||
@@ -5230,6 +5288,8 @@ snapshots:
|
|||||||
|
|
||||||
acorn@8.11.3: {}
|
acorn@8.11.3: {}
|
||||||
|
|
||||||
|
adler-32@1.3.1: {}
|
||||||
|
|
||||||
ajv@6.12.6:
|
ajv@6.12.6:
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-deep-equal: 3.1.3
|
fast-deep-equal: 3.1.3
|
||||||
@@ -5478,6 +5538,11 @@ snapshots:
|
|||||||
|
|
||||||
caniuse-lite@1.0.30001629: {}
|
caniuse-lite@1.0.30001629: {}
|
||||||
|
|
||||||
|
cfb@1.2.2:
|
||||||
|
dependencies:
|
||||||
|
adler-32: 1.3.1
|
||||||
|
crc-32: 1.2.2
|
||||||
|
|
||||||
chai@4.4.1:
|
chai@4.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
assertion-error: 1.1.0
|
assertion-error: 1.1.0
|
||||||
@@ -5563,6 +5628,8 @@ snapshots:
|
|||||||
|
|
||||||
clone@2.1.2: {}
|
clone@2.1.2: {}
|
||||||
|
|
||||||
|
codepage@1.15.0: {}
|
||||||
|
|
||||||
collection-visit@1.0.0:
|
collection-visit@1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
map-visit: 1.0.0
|
map-visit: 1.0.0
|
||||||
@@ -5623,6 +5690,8 @@ snapshots:
|
|||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
vary: 1.1.2
|
vary: 1.1.2
|
||||||
|
|
||||||
|
crc-32@1.2.2: {}
|
||||||
|
|
||||||
cross-spawn@7.0.3:
|
cross-spawn@7.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key: 3.1.1
|
path-key: 3.1.1
|
||||||
@@ -6370,6 +6439,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flat-cache: 4.0.1
|
flat-cache: 4.0.1
|
||||||
|
|
||||||
|
file-saver@2.0.5: {}
|
||||||
|
|
||||||
fill-range@4.0.0:
|
fill-range@4.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
extend-shallow: 2.0.1
|
extend-shallow: 2.0.1
|
||||||
@@ -6423,6 +6494,8 @@ snapshots:
|
|||||||
combined-stream: 1.0.8
|
combined-stream: 1.0.8
|
||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
|
|
||||||
|
frac@1.1.2: {}
|
||||||
|
|
||||||
fragment-cache@0.2.1:
|
fragment-cache@0.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
map-cache: 0.2.2
|
map-cache: 0.2.2
|
||||||
@@ -7839,6 +7912,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
extend-shallow: 3.0.2
|
extend-shallow: 3.0.2
|
||||||
|
|
||||||
|
ssf@0.11.2:
|
||||||
|
dependencies:
|
||||||
|
frac: 1.1.2
|
||||||
|
|
||||||
stable@0.1.8: {}
|
stable@0.1.8: {}
|
||||||
|
|
||||||
stackback@0.0.2: {}
|
stackback@0.0.2: {}
|
||||||
@@ -8445,8 +8522,12 @@ snapshots:
|
|||||||
siginfo: 2.0.0
|
siginfo: 2.0.0
|
||||||
stackback: 0.0.2
|
stackback: 0.0.2
|
||||||
|
|
||||||
|
wmf@1.0.2: {}
|
||||||
|
|
||||||
word-wrap@1.2.5: {}
|
word-wrap@1.2.5: {}
|
||||||
|
|
||||||
|
word@0.3.0: {}
|
||||||
|
|
||||||
wrap-ansi@7.0.0:
|
wrap-ansi@7.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
@@ -8467,6 +8548,16 @@ snapshots:
|
|||||||
|
|
||||||
wrappy@1.0.2: {}
|
wrappy@1.0.2: {}
|
||||||
|
|
||||||
|
xlsx@0.18.5:
|
||||||
|
dependencies:
|
||||||
|
adler-32: 1.3.1
|
||||||
|
cfb: 1.2.2
|
||||||
|
codepage: 1.15.0
|
||||||
|
crc-32: 1.2.2
|
||||||
|
ssf: 0.11.2
|
||||||
|
wmf: 1.0.2
|
||||||
|
word: 0.3.0
|
||||||
|
|
||||||
xml-name-validator@4.0.0: {}
|
xml-name-validator@4.0.0: {}
|
||||||
|
|
||||||
y18n@5.0.8: {}
|
y18n@5.0.8: {}
|
||||||
|
|||||||
+10
-1
@@ -1 +1,10 @@
|
|||||||
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="#646cff"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="#646cff"/></svg>
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1742355837219" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2674" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
|
||||||
|
<path d="M512 794.666667m-58.666667 0a58.666667 58.666667 0 1 0 117.333334 0 58.666667 58.666667 0 1 0-117.333334 0Z" p-id="2675" fill="#646cff" >
|
||||||
|
</path>
|
||||||
|
<path d="M512 170.666667A622.56 622.56 0 0 0 46.24 379.413333a5.333333 5.333333 0 0 0 0.533333 7.626667l48.266667 42.346667a5.333333 5.333333 0 0 0 7.466667-0.48 548.533333 548.533333 0 0 1 818.986666 0 5.333333 5.333333 0 0 0 7.466667 0.48l48-42.346667a5.333333 5.333333 0 0 0 0.48-7.626667A622.186667 622.186667 0 0 0 512 170.666667z" p-id="2676" fill="#646cff" >
|
||||||
|
</path>
|
||||||
|
<path d="M512 371.946667A421.6 421.6 0 0 0 197.76 512a5.333333 5.333333 0 0 0 0.48 7.68l48 42.24a5.333333 5.333333 0 0 0 7.466667-0.48 347.2 347.2 0 0 1 516.16 0 5.333333 5.333333 0 0 0 7.466666 0.48l48-42.24a5.333333 5.333333 0 0 0 0.48-7.68A421.6 421.6 0 0 0 512 371.946667z" p-id="2677" fill="#646cff" >
|
||||||
|
</path>
|
||||||
|
<path d="M512 555.733333a238.293333 238.293333 0 0 0-176 77.44 5.333333 5.333333 0 0 0 0.48 7.68l48 42.186667a5.333333 5.333333 0 0 0 7.466667-0.426667 163.893333 163.893333 0 0 1 240 0 5.333333 5.333333 0 0 0 7.466666 0.426667l48-42.186667a5.333333 5.333333 0 0 0 0.48-7.68A238.293333 238.293333 0 0 0 512 555.733333z" p-id="2678" fill="#646cff" >
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="#646cff"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="#646cff"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
const enUS = {
|
||||||
|
system: {
|
||||||
|
title: 'MacroHub'
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const zhCN = {
|
||||||
|
system: {
|
||||||
|
title: 'MacroHub'
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -13,6 +13,7 @@ const appStore = useAppStore();
|
|||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
|
|
||||||
const antdLocale = computed(() => {
|
const antdLocale = computed(() => {
|
||||||
|
appStore.changeLocale(appStore.locale);
|
||||||
return antdLocales[appStore.locale];
|
return antdLocales[appStore.locale];
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1 +1,10 @@
|
|||||||
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="currentColor"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="currentColor"/></svg>
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1742355837219" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2674" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
|
||||||
|
<path d="M512 794.666667m-58.666667 0a58.666667 58.666667 0 1 0 117.333334 0 58.666667 58.666667 0 1 0-117.333334 0Z" p-id="2675" fill="currentColor" >
|
||||||
|
</path>
|
||||||
|
<path d="M512 170.666667A622.56 622.56 0 0 0 46.24 379.413333a5.333333 5.333333 0 0 0 0.533333 7.626667l48.266667 42.346667a5.333333 5.333333 0 0 0 7.466667-0.48 548.533333 548.533333 0 0 1 818.986666 0 5.333333 5.333333 0 0 0 7.466667 0.48l48-42.346667a5.333333 5.333333 0 0 0 0.48-7.626667A622.186667 622.186667 0 0 0 512 170.666667z" p-id="2676" fill="currentColor" >
|
||||||
|
</path>
|
||||||
|
<path d="M512 371.946667A421.6 421.6 0 0 0 197.76 512a5.333333 5.333333 0 0 0 0.48 7.68l48 42.24a5.333333 5.333333 0 0 0 7.466667-0.48 347.2 347.2 0 0 1 516.16 0 5.333333 5.333333 0 0 0 7.466666 0.48l48-42.24a5.333333 5.333333 0 0 0 0.48-7.68A421.6 421.6 0 0 0 512 371.946667z" p-id="2677" fill="currentColor" >
|
||||||
|
</path>
|
||||||
|
<path d="M512 555.733333a238.293333 238.293333 0 0 0-176 77.44 5.333333 5.333333 0 0 0 0.48 7.68l48 42.186667a5.333333 5.333333 0 0 0 7.466667-0.426667 163.893333 163.893333 0 0 1 240 0 5.333333 5.333333 0 0 0 7.466666 0.426667l48-42.186667a5.333333 5.333333 0 0 0 0.48-7.68A238.293333 238.293333 0 0 0 512 555.733333z" p-id="2678" fill="currentColor" >
|
||||||
|
</path>
|
||||||
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="currentColor"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="currentColor"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,150 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, watch, onBeforeMount } from 'vue';
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:value']);
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '*',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**指定列表初始数据 */
|
||||||
|
const optionsSpecific = Array.from({ length: 31 }, (_, i) => {
|
||||||
|
let idx = i + 1;
|
||||||
|
return {
|
||||||
|
label: `${idx}`,
|
||||||
|
value: `${idx}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**数据 */
|
||||||
|
let data = reactive({
|
||||||
|
type: '1',
|
||||||
|
/**间隔 */
|
||||||
|
increment: 2,
|
||||||
|
incrementStart: 1,
|
||||||
|
/**周期 */
|
||||||
|
rangeStart: 1,
|
||||||
|
rangeEnd: 2,
|
||||||
|
/**指定 */
|
||||||
|
specific: ['1'],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**监听数据,将数值格式化 */
|
||||||
|
watch(data, () => {
|
||||||
|
let reultValue = '*';
|
||||||
|
let val = data.type;
|
||||||
|
// 每一
|
||||||
|
if (val === '1') {
|
||||||
|
reultValue = '*';
|
||||||
|
}
|
||||||
|
// 间隔
|
||||||
|
if (val === '2') {
|
||||||
|
let start = data.incrementStart;
|
||||||
|
let increment = data.increment;
|
||||||
|
reultValue = `${start ?? 0}/${increment ?? 0}`;
|
||||||
|
}
|
||||||
|
// 周期
|
||||||
|
if (val === '3') {
|
||||||
|
let start = data.rangeStart;
|
||||||
|
let end = data.rangeEnd;
|
||||||
|
reultValue = `${start ?? 0}-${end ?? 0}`;
|
||||||
|
}
|
||||||
|
// 指定
|
||||||
|
if (val === '4') {
|
||||||
|
reultValue = data.specific.sort((a, b) => +a - +b).join(',');
|
||||||
|
}
|
||||||
|
emit('update:value', reultValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**挂载前初始属性 */
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const val = props.value;
|
||||||
|
if (val === '*') {
|
||||||
|
data.type = '1';
|
||||||
|
}
|
||||||
|
if (val.includes('/')) {
|
||||||
|
const arr = val.split('/');
|
||||||
|
data.incrementStart = Number(arr[0]);
|
||||||
|
data.increment = Number(arr[1]);
|
||||||
|
data.type = '2';
|
||||||
|
}
|
||||||
|
if (val.includes('-')) {
|
||||||
|
const arr = val.split('-');
|
||||||
|
data.rangeStart = Number(arr[0]);
|
||||||
|
data.rangeEnd = Number(arr[1]);
|
||||||
|
data.type = '3';
|
||||||
|
}
|
||||||
|
if (val.includes(',')) {
|
||||||
|
data.specific = val.split(',').sort((a, b) => +a - +b);
|
||||||
|
data.type = '4';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-radio-group size="small" v-model:value="data.type">
|
||||||
|
<a-space direction="vertical" :size="18">
|
||||||
|
<a-radio value="1">
|
||||||
|
{{ t('components.CronModal.day1') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="2">
|
||||||
|
{{ t('components.CronModal.day21') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.increment"
|
||||||
|
:min="1"
|
||||||
|
:max="31"
|
||||||
|
placeholder="1-31"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.day22') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.incrementStart"
|
||||||
|
:min="1"
|
||||||
|
:max="31"
|
||||||
|
placeholder="1-31"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.day23') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="3">
|
||||||
|
{{ t('components.CronModal.day31') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeStart"
|
||||||
|
:min="1"
|
||||||
|
:max="31"
|
||||||
|
placeholder="1-31"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.day32') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeEnd"
|
||||||
|
:min="1"
|
||||||
|
:max="31"
|
||||||
|
placeholder="1-31"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.day33') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="4">
|
||||||
|
{{ t('components.CronModal.day4') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-select
|
||||||
|
v-model:value="data.specific"
|
||||||
|
size="small"
|
||||||
|
mode="multiple"
|
||||||
|
style="width: 100%"
|
||||||
|
:placeholder="t('components.CronModal.day4')"
|
||||||
|
:options="optionsSpecific"
|
||||||
|
></a-select>
|
||||||
|
<a-radio value="5">
|
||||||
|
{{ t('components.CronModal.day5') }}
|
||||||
|
</a-radio>
|
||||||
|
</a-space>
|
||||||
|
</a-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, watch, onBeforeMount } from 'vue';
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:value']);
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '*',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**指定列表初始数据 */
|
||||||
|
const optionsSpecific = Array.from({ length: 24 }, (_, i) => ({
|
||||||
|
label: `${i}`.padStart(2, '0'),
|
||||||
|
value: `${i}`,
|
||||||
|
}));
|
||||||
|
|
||||||
|
/**数据 */
|
||||||
|
let data = reactive({
|
||||||
|
type: '1',
|
||||||
|
/**间隔 */
|
||||||
|
increment: 2,
|
||||||
|
incrementStart: 0,
|
||||||
|
/**周期 */
|
||||||
|
rangeStart: 0,
|
||||||
|
rangeEnd: 2,
|
||||||
|
/**指定 */
|
||||||
|
specific: ['0'],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**监听数据,将数值格式化 */
|
||||||
|
watch(data, () => {
|
||||||
|
let reultValue = '*';
|
||||||
|
let val = data.type;
|
||||||
|
// 每一
|
||||||
|
if (val === '1') {
|
||||||
|
reultValue = '*';
|
||||||
|
}
|
||||||
|
// 间隔
|
||||||
|
if (val === '2') {
|
||||||
|
let start = data.incrementStart;
|
||||||
|
let increment = data.increment;
|
||||||
|
reultValue = `${start ?? 0}/${increment ?? 0}`;
|
||||||
|
}
|
||||||
|
// 周期
|
||||||
|
if (val === '3') {
|
||||||
|
let start = data.rangeStart;
|
||||||
|
let end = data.rangeEnd;
|
||||||
|
reultValue = `${start ?? 0}-${end ?? 0}`;
|
||||||
|
}
|
||||||
|
// 指定
|
||||||
|
if (val === '4') {
|
||||||
|
reultValue = data.specific.sort((a, b) => +a - +b).join(',');
|
||||||
|
}
|
||||||
|
emit('update:value', reultValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**挂载前初始属性 */
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const val = props.value;
|
||||||
|
if (val === '*') {
|
||||||
|
data.type = '1';
|
||||||
|
}
|
||||||
|
if (val.includes('/')) {
|
||||||
|
const arr = val.split('/');
|
||||||
|
data.incrementStart = Number(arr[0]);
|
||||||
|
data.increment = Number(arr[1]);
|
||||||
|
data.type = '2';
|
||||||
|
}
|
||||||
|
if (val.includes('-')) {
|
||||||
|
const arr = val.split('-');
|
||||||
|
data.rangeStart = Number(arr[0]);
|
||||||
|
data.rangeEnd = Number(arr[1]);
|
||||||
|
data.type = '3';
|
||||||
|
}
|
||||||
|
if (val.includes(',')) {
|
||||||
|
data.specific = val.split(',').sort((a, b) => +a - +b);
|
||||||
|
data.type = '4';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-radio-group size="small" v-model:value="data.type">
|
||||||
|
<a-space direction="vertical" :size="18">
|
||||||
|
<a-radio value="1">
|
||||||
|
{{ t('components.CronModal.hour1') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="2">
|
||||||
|
{{ t('components.CronModal.hour21') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.increment"
|
||||||
|
:min="0"
|
||||||
|
:max="23"
|
||||||
|
placeholder="0-23"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.hour22') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.incrementStart"
|
||||||
|
:min="0"
|
||||||
|
:max="23"
|
||||||
|
placeholder="0-23"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.hour23') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="3">
|
||||||
|
{{ t('components.CronModal.hour31') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeStart"
|
||||||
|
:min="0"
|
||||||
|
:max="23"
|
||||||
|
placeholder="1-23"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.hour32') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeEnd"
|
||||||
|
:min="0"
|
||||||
|
:max="23"
|
||||||
|
placeholder="0-23"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.hour33') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="4">
|
||||||
|
{{ t('components.CronModal.hour4') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-select
|
||||||
|
v-model:value="data.specific"
|
||||||
|
size="small"
|
||||||
|
mode="multiple"
|
||||||
|
style="width: 100%"
|
||||||
|
:placeholder="t('components.CronModal.hour4')"
|
||||||
|
:options="optionsSpecific"
|
||||||
|
></a-select>
|
||||||
|
</a-space>
|
||||||
|
</a-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, watch, onBeforeMount } from 'vue';
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:value']);
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '*',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**指定列表初始数据 */
|
||||||
|
const optionsSpecific = Array.from({ length: 60 }, (_, i) => {
|
||||||
|
return {
|
||||||
|
label: `${i}`.padStart(2, '0'),
|
||||||
|
value: `${i}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**数据 */
|
||||||
|
let data = reactive({
|
||||||
|
type: '1',
|
||||||
|
/**间隔 */
|
||||||
|
increment: 1,
|
||||||
|
incrementStart: 0,
|
||||||
|
/**周期 */
|
||||||
|
rangeStart: 1,
|
||||||
|
rangeEnd: 2,
|
||||||
|
/**指定 */
|
||||||
|
specific: ['0'],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**监听数据,将数值格式化 */
|
||||||
|
watch(data, () => {
|
||||||
|
let reultValue = '*';
|
||||||
|
let val = data.type;
|
||||||
|
// 每一
|
||||||
|
if (val === '1') {
|
||||||
|
reultValue = '*';
|
||||||
|
}
|
||||||
|
// 间隔
|
||||||
|
if (val === '2') {
|
||||||
|
let start = data.incrementStart;
|
||||||
|
let increment = data.increment;
|
||||||
|
reultValue = `${start ?? 0}/${increment ?? 0}`;
|
||||||
|
}
|
||||||
|
// 周期
|
||||||
|
if (val === '3') {
|
||||||
|
let start = data.rangeStart;
|
||||||
|
let end = data.rangeEnd;
|
||||||
|
reultValue = `${start ?? 0}-${end ?? 0}`;
|
||||||
|
}
|
||||||
|
// 指定
|
||||||
|
if (val === '4') {
|
||||||
|
reultValue = data.specific.sort((a, b) => +a - +b).join(',');
|
||||||
|
}
|
||||||
|
emit('update:value', reultValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**挂载前初始属性 */
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const val = props.value;
|
||||||
|
if (val === '*') {
|
||||||
|
data.type = '1';
|
||||||
|
}
|
||||||
|
if (val.includes('/')) {
|
||||||
|
const arr = val.split('/');
|
||||||
|
data.incrementStart = Number(arr[0]);
|
||||||
|
data.increment = Number(arr[1]);
|
||||||
|
data.type = '2';
|
||||||
|
}
|
||||||
|
if (val.includes('-')) {
|
||||||
|
const arr = val.split('-');
|
||||||
|
data.rangeStart = Number(arr[0]);
|
||||||
|
data.rangeEnd = Number(arr[1]);
|
||||||
|
data.type = '3';
|
||||||
|
}
|
||||||
|
if (val.includes(',')) {
|
||||||
|
data.specific = val.split(',').sort((a, b) => +a - +b);
|
||||||
|
data.type = '4';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-radio-group size="small" v-model:value="data.type">
|
||||||
|
<a-space direction="vertical" :size="18">
|
||||||
|
<a-radio value="1">
|
||||||
|
{{ t('components.CronModal.minute1') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="2">
|
||||||
|
{{ t('components.CronModal.minute21') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.increment"
|
||||||
|
:min="0"
|
||||||
|
:max="59"
|
||||||
|
placeholder="0-59"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.minute22') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.incrementStart"
|
||||||
|
:min="0"
|
||||||
|
:max="59"
|
||||||
|
placeholder="0-59"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.minute23') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="3">
|
||||||
|
{{ t('components.CronModal.minute31') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeStart"
|
||||||
|
:min="0"
|
||||||
|
:max="59"
|
||||||
|
placeholder="0-59"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.minute32') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeEnd"
|
||||||
|
:min="0"
|
||||||
|
:max="59"
|
||||||
|
placeholder="0-59"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.minute33') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="4">
|
||||||
|
{{ t('components.CronModal.minute4') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-select
|
||||||
|
v-model:value="data.specific"
|
||||||
|
size="small"
|
||||||
|
mode="multiple"
|
||||||
|
style="width: 100%"
|
||||||
|
:placeholder="t('components.CronModal.minute4')"
|
||||||
|
:options="optionsSpecific"
|
||||||
|
></a-select>
|
||||||
|
</a-space>
|
||||||
|
</a-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, watch, onBeforeMount } from 'vue';
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:value']);
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '*',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**指定列表初始数据 */
|
||||||
|
const optionsSpecific = Array.from({ length: 12 }, (_, i) => {
|
||||||
|
let idx = i + 1;
|
||||||
|
return {
|
||||||
|
label: `${idx}`,
|
||||||
|
value: `${idx}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**构建数据 */
|
||||||
|
let data = reactive({
|
||||||
|
/**类型 */
|
||||||
|
type: '1',
|
||||||
|
/**间隔 */
|
||||||
|
increment: 1,
|
||||||
|
incrementStart: 1,
|
||||||
|
/**周期 */
|
||||||
|
rangeStart: 1,
|
||||||
|
rangeEnd: 2,
|
||||||
|
/**指定秒 */
|
||||||
|
specific: ['1'],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**监听数据,将数值格式化 */
|
||||||
|
watch(data, () => {
|
||||||
|
let reultValue = '*';
|
||||||
|
let val = data.type;
|
||||||
|
// 每一
|
||||||
|
if (val === '1') {
|
||||||
|
reultValue = '*';
|
||||||
|
}
|
||||||
|
// 间隔
|
||||||
|
if (val === '2') {
|
||||||
|
let start = data.incrementStart;
|
||||||
|
let increment = data.increment;
|
||||||
|
reultValue = `${start ?? 0}/${increment ?? 0}`;
|
||||||
|
}
|
||||||
|
// 周期
|
||||||
|
if (val === '3') {
|
||||||
|
let start = data.rangeStart;
|
||||||
|
let end = data.rangeEnd;
|
||||||
|
reultValue = `${start ?? 0}-${end ?? 0}`;
|
||||||
|
}
|
||||||
|
// 指定
|
||||||
|
if (val === '4') {
|
||||||
|
reultValue = data.specific.sort((a, b) => +a - +b).join(',');
|
||||||
|
}
|
||||||
|
emit('update:value', reultValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**挂载前初始属性 */
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const val = props.value;
|
||||||
|
if (val === '*') {
|
||||||
|
data.type = '1';
|
||||||
|
}
|
||||||
|
if (val.includes('/')) {
|
||||||
|
const arr = val.split('/');
|
||||||
|
data.incrementStart = Number(arr[0]);
|
||||||
|
data.increment = Number(arr[1]);
|
||||||
|
data.type = '2';
|
||||||
|
}
|
||||||
|
if (val.includes('-')) {
|
||||||
|
const arr = val.split('-');
|
||||||
|
data.rangeStart = Number(arr[0]);
|
||||||
|
data.rangeEnd = Number(arr[1]);
|
||||||
|
data.type = '3';
|
||||||
|
}
|
||||||
|
if (val.includes(',')) {
|
||||||
|
data.specific = val.split(',').sort((a, b) => +a - +b);
|
||||||
|
data.type = '4';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-radio-group size="small" v-model:value="data.type">
|
||||||
|
<a-space direction="vertical" :size="18">
|
||||||
|
<a-radio value="1">
|
||||||
|
{{ t('components.CronModal.month1') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="2">
|
||||||
|
{{ t('components.CronModal.month21') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.increment"
|
||||||
|
:min="1"
|
||||||
|
:max="12"
|
||||||
|
placeholder="1-12"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.month22') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.incrementStart"
|
||||||
|
:min="1"
|
||||||
|
:max="12"
|
||||||
|
placeholder="1-12"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.month23') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="3">
|
||||||
|
{{ t('components.CronModal.month31') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeStart"
|
||||||
|
:min="1"
|
||||||
|
:max="12"
|
||||||
|
placeholder="1-12"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.month32') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeEnd"
|
||||||
|
:min="1"
|
||||||
|
:max="12"
|
||||||
|
placeholder="1-12"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.month33') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="4">
|
||||||
|
{{ t('components.CronModal.month4') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-select
|
||||||
|
v-model:value="data.specific"
|
||||||
|
size="small"
|
||||||
|
mode="multiple"
|
||||||
|
style="width: 100%"
|
||||||
|
:placeholder="t('components.CronModal.month4')"
|
||||||
|
:options="optionsSpecific"
|
||||||
|
></a-select>
|
||||||
|
</a-space>
|
||||||
|
</a-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, watch, onBeforeMount } from 'vue';
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:value']);
|
||||||
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '*',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**指定列表初始数据 */
|
||||||
|
const optionsSpecific = Array.from({ length: 60 }, (_, i) => ({
|
||||||
|
label: `${i}`.padStart(2, '0'),
|
||||||
|
value: `${i}`,
|
||||||
|
}));
|
||||||
|
|
||||||
|
/**构建数据 */
|
||||||
|
let data = reactive({
|
||||||
|
/**类型 */
|
||||||
|
type: '1',
|
||||||
|
/**间隔 */
|
||||||
|
increment: 2,
|
||||||
|
incrementStart: 0,
|
||||||
|
/**周期 */
|
||||||
|
rangeStart: 1,
|
||||||
|
rangeEnd: 2,
|
||||||
|
/**指定秒 */
|
||||||
|
specific: ['0'],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**监听数据,将数值格式化 */
|
||||||
|
watch(data, () => {
|
||||||
|
let reultValue = '*';
|
||||||
|
let val = data.type;
|
||||||
|
// 每一
|
||||||
|
if (val === '1') {
|
||||||
|
reultValue = '*';
|
||||||
|
}
|
||||||
|
// 间隔
|
||||||
|
if (val === '2') {
|
||||||
|
let start = data.incrementStart;
|
||||||
|
let increment = data.increment;
|
||||||
|
reultValue = `${start ?? 0}/${increment ?? 0}`;
|
||||||
|
}
|
||||||
|
// 周期
|
||||||
|
if (val === '3') {
|
||||||
|
let start = data.rangeStart;
|
||||||
|
let end = data.rangeEnd;
|
||||||
|
reultValue = `${start ?? 0}-${end ?? 0}`;
|
||||||
|
}
|
||||||
|
// 指定
|
||||||
|
if (val === '4') {
|
||||||
|
reultValue = data.specific.sort((a, b) => +a - +b).join(',');
|
||||||
|
}
|
||||||
|
emit('update:value', reultValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**挂载前初始属性 */
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const val = props.value;
|
||||||
|
if (val === '*') {
|
||||||
|
data.type = '1';
|
||||||
|
}
|
||||||
|
if (val.includes('/')) {
|
||||||
|
const arr = val.split('/');
|
||||||
|
data.incrementStart = Number(arr[0]);
|
||||||
|
data.increment = Number(arr[1]);
|
||||||
|
data.type = '2';
|
||||||
|
}
|
||||||
|
if (val.includes('-')) {
|
||||||
|
const arr = val.split('-');
|
||||||
|
data.rangeStart = Number(arr[0]);
|
||||||
|
data.rangeEnd = Number(arr[1]);
|
||||||
|
data.type = '3';
|
||||||
|
}
|
||||||
|
if (val.includes(',')) {
|
||||||
|
data.specific = val.split(',').sort((a, b) => +a - +b);
|
||||||
|
data.type = '4';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-radio-group size="small" v-model:value="data.type">
|
||||||
|
<a-space direction="vertical" :size="18">
|
||||||
|
<a-radio value="1">
|
||||||
|
{{ t('components.CronModal.second1') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="2">
|
||||||
|
{{ t('components.CronModal.second21') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.increment"
|
||||||
|
:min="0"
|
||||||
|
:max="59"
|
||||||
|
placeholder="0-59"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.second22') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.incrementStart"
|
||||||
|
:min="0"
|
||||||
|
:max="59"
|
||||||
|
placeholder="0-59"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.second23') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="3">
|
||||||
|
{{ t('components.CronModal.second31') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeStart"
|
||||||
|
:min="0"
|
||||||
|
:max="59"
|
||||||
|
placeholder="0-59"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.second32') }}
|
||||||
|
<a-input-number
|
||||||
|
size="small"
|
||||||
|
v-model:value="data.rangeEnd"
|
||||||
|
:min="0"
|
||||||
|
:max="59"
|
||||||
|
placeholder="0-59"
|
||||||
|
></a-input-number>
|
||||||
|
{{ t('components.CronModal.second33') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-radio value="4">
|
||||||
|
{{ t('components.CronModal.second4') }}
|
||||||
|
</a-radio>
|
||||||
|
<a-select
|
||||||
|
v-model:value="data.specific"
|
||||||
|
size="small"
|
||||||
|
mode="multiple"
|
||||||
|
style="width: 100%"
|
||||||
|
:placeholder="t('components.CronModal.second4')"
|
||||||
|
:options="optionsSpecific"
|
||||||
|
></a-select>
|
||||||
|
</a-space>
|
||||||
|
</a-radio-group>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:destroyOnClose="true"
|
||||||
|
:title="t('components.CronModal.title')"
|
||||||
|
:open="props.open"
|
||||||
|
:body-style="{ padding: '0 24px' }"
|
||||||
|
@cancel="fnCronModal(false)"
|
||||||
|
@ok="fnCronModal(true)"
|
||||||
|
>
|
||||||
|
<a-tabs tab-position="top" type="line">
|
||||||
|
<a-tab-pane key="1" :tab="t('common.units.second')">
|
||||||
|
<CronSecond v-model:value="cronValue.second"></CronSecond>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="2" :tab="t('common.units.minute')">
|
||||||
|
<CronMinute v-model:value="cronValue.minute"></CronMinute>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="3" :tab="t('common.units.hour')">
|
||||||
|
<CronHour v-model:value="cronValue.hour"></CronHour>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="4" :tab="t('common.units.day')">
|
||||||
|
<CronDay v-model:value="cronValue.day"></CronDay>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="5" :tab="t('common.units.month')">
|
||||||
|
<CronMonth v-model:value="cronValue.month"></CronMonth>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
|
||||||
|
<a-input
|
||||||
|
class="reultBox"
|
||||||
|
:addon-before="t('components.CronModal.addon')"
|
||||||
|
v-model:value="cronStr"
|
||||||
|
disabled
|
||||||
|
/>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import CronSecond from './components/Second.vue';
|
||||||
|
import CronMinute from './components/Minute.vue';
|
||||||
|
import CronHour from './components/Hour.vue';
|
||||||
|
import CronDay from './components/Day.vue';
|
||||||
|
import CronMonth from './components/Month.vue';
|
||||||
|
import { reactive, computed, watch } from 'vue';
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const emit = defineEmits(['cancel', 'ok', 'update:open']);
|
||||||
|
const props = defineProps({
|
||||||
|
open: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
cron: {
|
||||||
|
type: String,
|
||||||
|
default: '* * * * * ?',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**cron属性值 */
|
||||||
|
let cronValue = reactive({
|
||||||
|
second: '*',
|
||||||
|
minute: '*',
|
||||||
|
hour: '*',
|
||||||
|
day: '*',
|
||||||
|
month: '*',
|
||||||
|
week: '?',
|
||||||
|
});
|
||||||
|
|
||||||
|
/**组合cron结果 */
|
||||||
|
const cronStr = computed(() => {
|
||||||
|
let time = `${cronValue.second} ${cronValue.minute} ${cronValue.hour}`;
|
||||||
|
let date = `${cronValue.day} ${cronValue.month} ${cronValue.week}`;
|
||||||
|
return `${time} ${date}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**监听是否显示,初始cron属性 */
|
||||||
|
watch(
|
||||||
|
() => props.open,
|
||||||
|
val => {
|
||||||
|
if (!val) return;
|
||||||
|
const arr = props.cron.split(' ');
|
||||||
|
// 6 位以上是合法表达式
|
||||||
|
if (arr.length >= 6) {
|
||||||
|
Object.assign(cronValue, {
|
||||||
|
second: arr[0],
|
||||||
|
minute: arr[1],
|
||||||
|
hour: arr[2],
|
||||||
|
day: arr[3],
|
||||||
|
month: arr[4],
|
||||||
|
week: arr[5],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 窗口事件
|
||||||
|
* @param val modal触发事件
|
||||||
|
*/
|
||||||
|
function fnCronModal(val: boolean) {
|
||||||
|
emit('update:open', false);
|
||||||
|
if (val) {
|
||||||
|
emit('ok', cronStr.value);
|
||||||
|
} else {
|
||||||
|
emit('cancel');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.reultBox {
|
||||||
|
margin-top: 48px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, PropType } from 'vue';
|
||||||
|
const props = defineProps({
|
||||||
|
/**数据 */
|
||||||
|
options: {
|
||||||
|
type: Array as PropType<DictType[]>,
|
||||||
|
},
|
||||||
|
/**当前的值对应数据中的项字段 */
|
||||||
|
valueField: {
|
||||||
|
type: String as PropType<keyof DictType>,
|
||||||
|
default: 'value',
|
||||||
|
},
|
||||||
|
/**当前的值 */
|
||||||
|
value: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
/**数据默认值,当前值不存在时 */
|
||||||
|
valueDefault: {
|
||||||
|
type: [Number, String],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**遍历找到对应值数据项 */
|
||||||
|
const item = computed(() => {
|
||||||
|
if (Array.isArray(props.options) && props.options.length > 0) {
|
||||||
|
let option = props.options.find(
|
||||||
|
item => `${item[props.valueField]}` === `${props.value}`
|
||||||
|
);
|
||||||
|
// 数据默认值
|
||||||
|
if (!option && props.valueDefault != undefined) {
|
||||||
|
option = props.options.find(
|
||||||
|
item => `${item[props.valueField]}` === `${props.valueDefault}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<template v-if="item">
|
||||||
|
<a-tag v-if="item.tagType" :class="!item.tagClass?'':item.tagClass" :color="!item.tagType?'':item.tagType">
|
||||||
|
{{ item.label }}
|
||||||
|
</a-tag>
|
||||||
|
<a-tag v-else :class="!item.tagClass?'':item.tagClass">
|
||||||
|
{{ item.label }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<span v-else>{{ value }}</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { isShowBtn } from '@/utils/permission';
|
import { isShowBtn } from '@/utils/permission';
|
||||||
|
import { ContainerOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'TableHeaderOperation'
|
name: 'TableHeaderOperation'
|
||||||
@@ -10,6 +12,9 @@ interface Props {
|
|||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
tableType?: string;
|
tableType?: string;
|
||||||
showDelete?: boolean;
|
showDelete?: boolean;
|
||||||
|
showExport?: boolean;
|
||||||
|
notShowAdd?: boolean;
|
||||||
|
showView?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>();
|
defineProps<Props>();
|
||||||
@@ -18,6 +23,8 @@ interface Emits {
|
|||||||
(e: 'add'): void;
|
(e: 'add'): void;
|
||||||
(e: 'delete'): void;
|
(e: 'delete'): void;
|
||||||
(e: 'refresh'): void;
|
(e: 'refresh'): void;
|
||||||
|
(e: 'export'): void;
|
||||||
|
(e: 'view'): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
const emit = defineEmits<Emits>();
|
||||||
@@ -37,24 +44,30 @@ function batchDelete() {
|
|||||||
function refresh() {
|
function refresh() {
|
||||||
emit('refresh');
|
emit('refresh');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleExport() {
|
||||||
|
emit('export');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleView() {
|
||||||
|
emit('view');
|
||||||
|
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-wrap justify-end gap-x-12px gap-y-8px lt-sm:(w-200px py-12px)">
|
<div class="flex flex-wrap justify-end gap-x-12px gap-y-8px lt-sm:(w-200px py-12px)">
|
||||||
<slot name="prefix"></slot>
|
<slot name="prefix"></slot>
|
||||||
<slot name="default">
|
<slot name="default">
|
||||||
<AButton v-if="isShowBtn(`system:${tableType}:add`)" size="small" ghost type="primary" @click="add">
|
<AButton v-if="isShowBtn(`system:${tableType}:add`) && !notShowAdd" size="small" ghost type="primary"
|
||||||
|
@click="add">
|
||||||
<div class="flex-y-center gap-8px">
|
<div class="flex-y-center gap-8px">
|
||||||
<icon-ic-round-plus class="text-icon" />
|
<icon-ic-round-plus class="text-icon" />
|
||||||
<span>{{ $t('common.add') }}</span>
|
<span>{{ $t('common.add') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</AButton>
|
</AButton>
|
||||||
<APopconfirm
|
<APopconfirm v-if="isShowBtn(`system:${tableType}:remove`) && showDelete" :title="$t('common.confirmDelete')"
|
||||||
v-if="isShowBtn(`system:${tableType}:remove`) && showDelete"
|
:disabled="disabledDelete" @confirm="batchDelete">
|
||||||
:title="$t('common.confirmDelete')"
|
|
||||||
:disabled="disabledDelete"
|
|
||||||
@confirm="batchDelete"
|
|
||||||
>
|
|
||||||
<AButton size="small" danger :disabled="disabledDelete">
|
<AButton size="small" danger :disabled="disabledDelete">
|
||||||
<div class="flex-y-center gap-8px">
|
<div class="flex-y-center gap-8px">
|
||||||
<icon-ic-round-delete class="text-icon" />
|
<icon-ic-round-delete class="text-icon" />
|
||||||
@@ -69,6 +82,19 @@ function refresh() {
|
|||||||
<span>{{ $t('common.refresh') }}</span>
|
<span>{{ $t('common.refresh') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</AButton>
|
</AButton>
|
||||||
|
<AButton size="small" type="primary" ghost @click="handleExport" v-show="showExport">
|
||||||
|
<div class="flex-y-center gap-8px">
|
||||||
|
<icon-mdi-refresh class="text-icon" :class="{ 'animate-spin': loading }" />
|
||||||
|
<span>{{ $t('common.export') }}</span>
|
||||||
|
</div>
|
||||||
|
</AButton>
|
||||||
|
|
||||||
|
<AButton size="small" type="default" @click.prevent="handleView" v-show="showView">
|
||||||
|
<template #icon>
|
||||||
|
<ContainerOutlined />
|
||||||
|
</template>
|
||||||
|
{{ $t('route.manage_dictData') }}
|
||||||
|
</AButton>
|
||||||
<TableColumnSetting v-model:columns="columns" />
|
<TableColumnSetting v-model:columns="columns" />
|
||||||
<slot name="suffix"></slot>
|
<slot name="suffix"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { transformRecordToOption } from '@/utils/common';
|
import { transformRecordToOption } from '@/utils/common';
|
||||||
|
|
||||||
export const enableStatusRecord: Record<Api.Common.EnableStatus, App.I18n.I18nKey> = {
|
export const enableStatusRecord: any= {
|
||||||
'0': 'page.manage.common.status.enable',
|
'0': 'page.manage.common.status.enable',
|
||||||
'1': 'page.manage.common.status.disable'
|
'1': 'page.manage.common.status.disable'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const enableStatusOptions = transformRecordToOption(enableStatusRecord);
|
export const enableStatusOptions = transformRecordToOption(enableStatusRecord);
|
||||||
|
|
||||||
export const menuIconTypeRecord: Record<Api.SystemManage.IconType, App.I18n.I18nKey> = {
|
export const menuIconTypeRecord: any = {
|
||||||
'1': 'page.manage.menu.iconType.iconify',
|
'1': 'page.manage.menu.iconType.iconify',
|
||||||
'2': 'page.manage.menu.iconType.local'
|
'2': 'page.manage.menu.iconType.local'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const REG_PHONE = /^.{3,}$/;
|
|||||||
*
|
*
|
||||||
* 6-18 characters, including letters, numbers, and underscores
|
* 6-18 characters, including letters, numbers, and underscores
|
||||||
*/
|
*/
|
||||||
export const REG_PWD = /^\w{6,18}$/;
|
export const REG_PWD = /^[\w.]{6,18}$/;
|
||||||
|
|
||||||
/** Email reg */
|
/** Email reg */
|
||||||
export const REG_EMAIL = ///^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
|
export const REG_EMAIL = ///^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
|
||||||
|
|||||||
@@ -0,0 +1,314 @@
|
|||||||
|
// 地区选项
|
||||||
|
export const regionOptions = [
|
||||||
|
{ label: 'Afghanistan', value: 'Afghanistan/AF/+93' },
|
||||||
|
{ label: 'Albania', value: 'Albania/AL/+355' },
|
||||||
|
{ label: 'Algeria', value: 'Algeria/DZ/+213' },
|
||||||
|
{ label: 'Angola', value: 'Angola/AO/+244' },
|
||||||
|
{ label: 'Anguilla', value: 'Anguilla/AI/+1264' },
|
||||||
|
{ label: 'Antigua and Barbuda', value: 'Antigua and Barbuda/AG/+268' },
|
||||||
|
{ label: 'Argentina', value: 'Argentina/AR/+54' },
|
||||||
|
{ label: 'Armenia', value: 'Armenia/AM/+374' },
|
||||||
|
{ label: 'Aruba', value: 'Aruba/AW/+297' },
|
||||||
|
{ label: 'Australia', value: 'Australia/AU/+61' },
|
||||||
|
{ label: 'Austria', value: 'Austria/AT/+43' },
|
||||||
|
{ label: 'Azerbaijan', value: 'Azerbaijan/AZ/+994' },
|
||||||
|
{ label: 'Bahamas', value: 'Bahamas/BS/+1242' },
|
||||||
|
{ label: 'Bahrain', value: 'Bahrain/BH/+973' },
|
||||||
|
{ label: 'Bangladesh', value: 'Bangladesh/BD/+880' },
|
||||||
|
{ label: 'Barbados', value: 'Barbados/BB/+1246' },
|
||||||
|
{ label: 'Belarus', value: 'Belarus/BY/+375' },
|
||||||
|
{ label: 'Belgium', value: 'Belgium/BE/+32' },
|
||||||
|
{ label: 'Belize', value: 'Belize/BZ/+501' },
|
||||||
|
{ label: 'Benin', value: 'Benin/BJ/+229' },
|
||||||
|
{ label: 'Bermuda', value: 'Bermuda/BM/+1441' },
|
||||||
|
{ label: 'Bhutan', value: 'Bhutan/BT/+975' },
|
||||||
|
{ label: 'Bolivia', value: 'Bolivia/BO/+591' },
|
||||||
|
{ label: 'Botswana', value: 'Botswana/BW/+267' },
|
||||||
|
{ label: 'Brasil', value: 'Brasil/BR/+55' },
|
||||||
|
{ label: 'Brunei', value: 'Brunei/BN/+673' },
|
||||||
|
{ label: 'Burkina Faso', value: 'Burkina Faso/BF/+226' },
|
||||||
|
{ label: 'Burundi', value: 'Burundi/BI/+257' },
|
||||||
|
{ label: 'Cabo Verde', value: 'Cabo Verde/CV/+238' },
|
||||||
|
{ label: 'Cambodia', value: 'Cambodia/KH/+855' },
|
||||||
|
{ label: 'Cameroon', value: 'Cameroon/CM/+237' },
|
||||||
|
{ label: 'Canada', value: 'Canada/CA/+1' },
|
||||||
|
{ label: 'Cayman Islands', value: 'Cayman Islands/KY/+1345' },
|
||||||
|
{ label: 'Central African', value: 'Central African/CF/+236' },
|
||||||
|
{ label: 'Chad', value: 'Chad/TD/+235' },
|
||||||
|
{ label: 'Chile', value: 'Chile/CL/+56' },
|
||||||
|
{ label: 'China', value: 'China/CN/+86' },
|
||||||
|
{ label: 'Christmas Island', value: 'Christmas Island/CX/+618' },
|
||||||
|
{ label: 'Colombia', value: 'Colombia/CO/+57' },
|
||||||
|
{ label: 'Comoros', value: 'Comoros/KM/+269' },
|
||||||
|
{ label: 'Congo', value: 'Congo/CD/+243' },
|
||||||
|
{ label: 'Congo', value: 'Congo/CG/+242' },
|
||||||
|
{ label: 'Costa Rica', value: 'Costa Rica/CR/+506' },
|
||||||
|
{ label: "Cote d'Ivoire", value: "Cote d'Ivoire/CI/+225" },
|
||||||
|
{ label: 'Croatia', value: 'Croatia/HR/+385' },
|
||||||
|
{ label: 'Cuba', value: 'Cuba/CU/+53' },
|
||||||
|
{ label: 'Cyprus', value: 'Cyprus/CY/+357' },
|
||||||
|
{ label: 'Czech', value: 'Czech/CZ/+420' },
|
||||||
|
{ label: 'Denmark', value: 'Denmark/DK/+45' },
|
||||||
|
{ label: 'Djibouti', value: 'Djibouti/DJ/+253' },
|
||||||
|
{ label: 'Dominica', value: 'Dominica/DM/+1767' },
|
||||||
|
{ label: 'Dominican', value: 'Dominican/DO/+1809' },
|
||||||
|
{ label: 'Ecuador', value: 'Ecuador/EC/+593' },
|
||||||
|
{ label: 'Egypt', value: 'Egypt/EG/+20' },
|
||||||
|
{ label: 'Equatorial Guinea', value: 'Equatorial Guinea/GQ/+240' },
|
||||||
|
{ label: 'Eritrea', value: 'Eritrea/ER/+291' },
|
||||||
|
{ label: 'Estonia', value: 'Estonia/EE/+372' },
|
||||||
|
{ label: 'Ethiopia', value: 'Ethiopia/ET/+251' },
|
||||||
|
{ label: 'Falkland Islands', value: 'Falkland Islands/FK/+500' },
|
||||||
|
{ label: 'Fiji', value: 'Fiji/FJ/+679' },
|
||||||
|
{ label: 'Finland', value: 'Finland/FI/+358' },
|
||||||
|
{ label: 'France', value: 'France/FR/+33' },
|
||||||
|
{ label: 'French Guiana', value: 'French Guiana/GF/+594' },
|
||||||
|
{ label: 'French Polynesia', value: 'French Polynesia/PF/+689' },
|
||||||
|
{ label: 'Gabon', value: 'Gabon/GA/+241' },
|
||||||
|
{ label: 'Gambia', value: 'Gambia/GM/+220' },
|
||||||
|
{ label: 'Georgia', value: 'Georgia/GE/+995' },
|
||||||
|
{ label: 'Germany', value: 'Germany/DE/+49' },
|
||||||
|
{ label: 'Ghana', value: 'Ghana/GH/+233' },
|
||||||
|
{ label: 'Greece', value: 'Greece/GR/+30' },
|
||||||
|
{ label: 'Greenland', value: 'Greenland/GL/+45' },
|
||||||
|
{ label: 'Grenada', value: 'Grenada/GD/+1473' },
|
||||||
|
{ label: 'Guam', value: 'Guam/GU/+1' },
|
||||||
|
{ label: 'Guatemala', value: 'Guatemala/GT/+502' },
|
||||||
|
{ label: 'Guinea', value: 'Guinea/GN/+224' },
|
||||||
|
{ label: 'Guinea-Bissau', value: 'Guinea-Bissau/GW/+245' },
|
||||||
|
{ label: 'Guyana', value: 'Guyana/GY/+592' },
|
||||||
|
{ label: 'Haiti', value: 'Haiti/HT/+509' },
|
||||||
|
{ label: 'Honduras', value: 'Honduras/HN/+504' },
|
||||||
|
{ label: 'Hong Kong', value: 'Hong Kong/HK/+852' },
|
||||||
|
{ label: 'Hungary', value: 'Hungary/HU/+36' },
|
||||||
|
{ label: 'Iceland', value: 'Iceland/IS/+354' },
|
||||||
|
{ label: 'India', value: 'India/IN/+91' },
|
||||||
|
{ label: 'Indonesia', value: 'Indonesia/ID/+62' },
|
||||||
|
{ label: 'Iran', value: 'Iran/IR/+98' },
|
||||||
|
{ label: 'Iraq', value: 'Iraq/IQ/+964' },
|
||||||
|
{ label: 'Ireland', value: 'Ireland/IE/+353' },
|
||||||
|
{ label: 'Israel', value: 'Israel/IL/+972' },
|
||||||
|
{ label: 'Italy', value: 'Italy/IT/+39' },
|
||||||
|
{ label: 'Jamaica', value: 'Jamaica/JM/+876' },
|
||||||
|
{ label: 'Japan', value: 'Japan/JP/+81' },
|
||||||
|
{ label: 'Jordan', value: 'Jordan/JO/+962' },
|
||||||
|
{ label: 'Kazakhstan', value: 'Kazakhstan/KZ/+7' },
|
||||||
|
{ label: 'Kenya', value: 'Kenya/KE/+254' },
|
||||||
|
{ label: 'Kiribati', value: 'Kiribati/KI/+686' },
|
||||||
|
{ label: 'Korea', value: 'Korea/KR/+82' },
|
||||||
|
{ label: 'Kuwait', value: 'Kuwait/KW/+965' },
|
||||||
|
{ label: 'Kyrgyzstan', value: 'Kyrgyzstan/KG/+996' },
|
||||||
|
{ label: 'Lao', value: 'Lao/LA/+856' },
|
||||||
|
{ label: 'Latvia', value: 'Latvia/LV/+371' },
|
||||||
|
{ label: 'Lebanon', value: 'Lebanon/LB/+961' },
|
||||||
|
{ label: 'Lesotho', value: 'Lesotho/LS/+266' },
|
||||||
|
{ label: 'Liberia', value: 'Liberia/LR/+231' },
|
||||||
|
{ label: 'Libya', value: 'Libya/LY/+218' },
|
||||||
|
{ label: 'Liechtenstein', value: 'Liechtenstein/LI/+423' },
|
||||||
|
{ label: 'Lithuania', value: 'Lithuania/LT/+370' },
|
||||||
|
{ label: 'Luxembourg', value: 'Luxembourg/LU/+352' },
|
||||||
|
{ label: 'Macao', value: 'Macao/MO/+853' },
|
||||||
|
{ label: 'Macedonia', value: 'Macedonia/MK/+389' },
|
||||||
|
{ label: 'Madagascar', value: 'Madagascar/MG/+261' },
|
||||||
|
{ label: 'Malawi', value: 'Malawi/MW/+265' },
|
||||||
|
{ label: 'Malaysia', value: 'Malaysia/MY/+60' },
|
||||||
|
{ label: 'Maldives', value: 'Maldives/MV/+960' },
|
||||||
|
{ label: 'Mali', value: 'Mali/ML/+223' },
|
||||||
|
{ label: 'Malta', value: 'Malta/MT/+356' },
|
||||||
|
{ label: 'Marshall Islands', value: 'Marshall Islands/MH/+692' },
|
||||||
|
{ label: 'Mauritania', value: 'Mauritania/MR/+222' },
|
||||||
|
{ label: 'Mauritius', value: 'Mauritius/MU/+230' },
|
||||||
|
{ label: 'Mexico', value: 'Mexico/MX/+52' },
|
||||||
|
{ label: 'Micronesia', value: 'Micronesia/FM/+691' },
|
||||||
|
{ label: 'Moldova', value: 'Moldova/MD/+373' },
|
||||||
|
{ label: 'Monaco', value: 'Monaco/MC/+377' },
|
||||||
|
{ label: 'Mongolia', value: 'Mongolia/MN/+976' },
|
||||||
|
{ label: 'Montenegro', value: 'Montenegro/ME/+382' },
|
||||||
|
{ label: 'Morocco', value: 'Morocco/MA/+212' },
|
||||||
|
{ label: 'Mozambique', value: 'Mozambique/MZ/+258' },
|
||||||
|
{ label: 'Myanmar', value: 'Myanmar/MM/+95' },
|
||||||
|
{ label: 'Namibia', value: 'Namibia/NA/+264' },
|
||||||
|
{ label: 'Nauru', value: 'Nauru/NR/+674' },
|
||||||
|
{ label: 'Nepal', value: 'Nepal/NP/+977' },
|
||||||
|
{ label: 'Netherlands', value: 'Netherlands/NL/+31' },
|
||||||
|
{ label: 'Netherlands Antilles', value: 'Netherlands Antilles/AN/+599' },
|
||||||
|
{ label: 'New Caledonia', value: 'New Caledonia/NC/+687' },
|
||||||
|
{ label: 'New Zealand', value: 'New Zealand/NZ/+64' },
|
||||||
|
{ label: 'Nicaragua', value: 'Nicaragua/NI/+505' },
|
||||||
|
{ label: 'Niger', value: 'Niger/NE/+227' },
|
||||||
|
{ label: 'Nigeria', value: 'Nigeria/NG/+234' },
|
||||||
|
{ label: 'Niue', value: 'Niue/NU/+683' },
|
||||||
|
{ label: 'North Korea', value: 'North Korea/KP/+850' },
|
||||||
|
{ label: 'Norway', value: 'Norway/NO/+47' },
|
||||||
|
{ label: 'Oman', value: 'Oman/OM/+968' },
|
||||||
|
{ label: 'Pakistan', value: 'Pakistan/PK/+92' },
|
||||||
|
{ label: 'Palau', value: 'Palau/PW/+680' },
|
||||||
|
{ label: 'Palestine', value: 'Palestine/PS/+970' },
|
||||||
|
{ label: 'Panama', value: 'Panama/PA/+507' },
|
||||||
|
{ label: 'Papua New Guinea', value: 'Papua New Guinea/PG/+675' },
|
||||||
|
{ label: 'Paraguay', value: 'Paraguay/PY/+595' },
|
||||||
|
{ label: 'Peru', value: 'Peru/PE/+51' },
|
||||||
|
{ label: 'Philippines', value: 'Philippines/PH/+63' },
|
||||||
|
{ label: 'Pitcairn Islands', value: 'Pitcairn Islands/PN/+64' },
|
||||||
|
{ label: 'Poland', value: 'Poland/PL/+48' },
|
||||||
|
{ label: 'Portuguese', value: 'Portuguese/PT/+351' },
|
||||||
|
{ label: 'Puerto Rico', value: 'Puerto Rico/PR/+1787' },
|
||||||
|
{ label: 'Qatar', value: 'Qatar/QA/+974' },
|
||||||
|
{ label: 'Romania', value: 'Romania/RO/+40' },
|
||||||
|
{ label: 'Russia', value: 'Russia/RU/+7' },
|
||||||
|
{ label: 'Rwanda', value: 'Rwanda/RW/+250' },
|
||||||
|
{ label: 'Saint Kitts and Nevis', value: 'Saint Kitts and Nevis/KN/+1869' },
|
||||||
|
{ label: 'Saint Lucia', value: 'Saint Lucia/LC/+1758' },
|
||||||
|
{ label: 'Saint Vincent and the Grenadines', value: 'Saint Vincent and the Grenadines/VC/+1784' },
|
||||||
|
{ label: 'Saint-Martin', value: 'Saint-Martin/MF/+1721' },
|
||||||
|
{ label: 'Salvador', value: 'Salvador/SV/+503' },
|
||||||
|
{ label: 'Samoa', value: 'Samoa/WS/+685' },
|
||||||
|
{ label: 'San Marino', value: 'San Marino/SM/+378' },
|
||||||
|
{ label: 'Sao Tome and Principe', value: 'Sao Tome and Principe/ST/+239' },
|
||||||
|
{ label: 'Saudi Arabia', value: 'Saudi Arabia/SA/+966' },
|
||||||
|
{ label: 'Senegal', value: 'Senegal/SN/+221' },
|
||||||
|
{ label: 'Serbia', value: 'Serbia/RS/+381' },
|
||||||
|
{ label: 'Seychelles', value: 'Seychelles/SC/+248' },
|
||||||
|
{ label: 'Sierra Leone', value: 'Sierra Leone/SL/+232' },
|
||||||
|
{ label: 'Singapore', value: 'Singapore/SG/+65' },
|
||||||
|
{ label: 'Slovak', value: 'Slovak/SK/+421' },
|
||||||
|
{ label: 'Slovenia', value: 'Slovenia/SI/+386' },
|
||||||
|
{ label: 'Solomon Islands', value: 'Solomon Islands/SB/+677' },
|
||||||
|
{ label: 'Somalia', value: 'Somalia/SO/+252' },
|
||||||
|
{ label: 'South Africa', value: 'South Africa/ZA/+27' },
|
||||||
|
{ label: 'South Sudan', value: 'South Sudan/SS/+211' },
|
||||||
|
{ label: 'Spain', value: 'Spain/ES/+34' },
|
||||||
|
{ label: 'Sri Lanka', value: 'Sri Lanka/LK/+94' },
|
||||||
|
{ label: 'Sudan', value: 'Sudan/SD/+249' },
|
||||||
|
{ label: 'Suriname', value: 'Suriname/SR/+597' },
|
||||||
|
{ label: 'Swaziland', value: 'Swaziland/SZ/+268' },
|
||||||
|
{ label: 'Sweden', value: 'Sweden/SE/+46' },
|
||||||
|
{ label: 'Swiss', value: 'Swiss/CH/+41' },
|
||||||
|
{ label: 'Syria', value: 'Syria/SY/+963' },
|
||||||
|
{ label: 'Taiwan', value: 'Taiwan/TW/+886' },
|
||||||
|
{ label: 'Tajikistan', value: 'Tajikistan/TJ/+992' },
|
||||||
|
{ label: 'Tanzania', value: 'Tanzania/TZ/+255' },
|
||||||
|
{ label: 'Thailand', value: 'Thailand/TH/+66' },
|
||||||
|
{ label: 'The Cook Islands', value: 'The Cook Islands/CK/+682' },
|
||||||
|
{ label: 'The Turks and Caicos Islands', value: 'The Turks and Caicos Islands/TC/+1649' },
|
||||||
|
{ label: 'The United States Virgin Islands', value: 'The United States Virgin Islands/VI/+1340' },
|
||||||
|
{ label: 'Timor-Leste', value: 'Timor-Leste/TL/+670' },
|
||||||
|
{ label: 'Togo', value: 'Togo/TG/+228' },
|
||||||
|
{ label: 'Tokelau', value: 'Tokelau/TK/+690' },
|
||||||
|
{ label: 'Tonga', value: 'Tonga/TO/+676' },
|
||||||
|
{ label: 'Trinidad and Tobago', value: 'Trinidad and Tobago/TT/+1868' },
|
||||||
|
{ label: 'Tunisia', value: 'Tunisia/TN/+216' },
|
||||||
|
{ label: 'Turkey', value: 'Turkey/TR/+90' },
|
||||||
|
{ label: 'Turkmenistan', value: 'Turkmenistan/TM/+993' },
|
||||||
|
{ label: 'Tuvalu', value: 'Tuvalu/TV/+688' },
|
||||||
|
{ label: 'Uganda', value: 'Uganda/UG/+256' },
|
||||||
|
{ label: 'Ukraine', value: 'Ukraine/UA/+380' },
|
||||||
|
{ label: 'United Arab Emirates', value: 'United Arab Emirates/AE/+971' },
|
||||||
|
{ label: 'United Kingdom', value: 'United Kingdom/UK/+44' },
|
||||||
|
{ label: 'United States', value: 'United States/US/+1' },
|
||||||
|
{ label: 'Uruguay', value: 'Uruguay/UY/+598' },
|
||||||
|
{ label: 'Uzbekistan', value: 'Uzbekistan/UZ/+998' },
|
||||||
|
{ label: 'Vanuatu', value: 'Vanuatu/VU/+678' },
|
||||||
|
{ label: 'Vatican', value: 'Vatican/VA/+379' },
|
||||||
|
{ label: 'Venezuela', value: 'Venezuela/VE/+58' },
|
||||||
|
{ label: 'Vietnam', value: 'Vietnam/VN/+84' },
|
||||||
|
{ label: 'Yemen', value: 'Yemen/YE/+967' },
|
||||||
|
{ label: 'Zambia', value: 'Zambia/ZM/+260' },
|
||||||
|
{ label: 'Zimbabwe', value: 'Zimbabwe/ZW/+263' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 时区选项
|
||||||
|
export const timeZoneOptions = [
|
||||||
|
{ label: 'Pacific/Wake', value: 'Pacific/Wake' },
|
||||||
|
{ label: 'Pacific/Midway', value: 'Pacific/Midway' },
|
||||||
|
{ label: 'Pacific/Honolulu', value: 'Pacific/Honolulu' },
|
||||||
|
{ label: 'America/Anchorage', value: 'America/Anchorage' },
|
||||||
|
{ label: 'America/Los_Angeles', value: 'America/Los_Angeles' },
|
||||||
|
{ label: 'America/Phoenix', value: 'America/Phoenix' },
|
||||||
|
{ label: 'America/Chihuahua', value: 'America/Chihuahua' },
|
||||||
|
{ label: 'America/Denver', value: 'America/Denver' },
|
||||||
|
{ label: 'America/Tegucigalpa', value: 'America/Tegucigalpa' },
|
||||||
|
{ label: 'America/Chicago', value: 'America/Chicago' },
|
||||||
|
{ label: 'America/Mexico_City', value: 'America/Mexico_City' },
|
||||||
|
{ label: 'Canada/Saskatchewan', value: 'Canada/Saskatchewan' },
|
||||||
|
{ label: 'America/Bogota', value: 'America/Bogota' },
|
||||||
|
{ label: 'America/New_York', value: 'America/New_York' },
|
||||||
|
{ label: 'America/Indiana/Indianapolis', value: 'America/Indiana/Indianapolis' },
|
||||||
|
{ label: 'America/Caracas', value: 'America/Caracas' },
|
||||||
|
{ label: 'America/Asuncion', value: 'America/Asuncion' },
|
||||||
|
{ label: 'America/Halifax', value: 'America/Halifax' },
|
||||||
|
{ label: 'America/Cuiaba', value: 'America/Cuiaba' },
|
||||||
|
{ label: 'America/La_Paz', value: 'America/La_Paz' },
|
||||||
|
{ label: 'Canada/Newfoundland', value: 'Canada/Newfoundland' },
|
||||||
|
{ label: 'America/Sao_Paulo', value: 'America/Sao_Paulo' },
|
||||||
|
{ label: 'America/Buenos_Aires', value: 'America/Buenos_Aires' },
|
||||||
|
{ label: 'America/Cayenne', value: 'America/Cayenne' },
|
||||||
|
{ label: 'America/Godthab', value: 'America/Godthab' },
|
||||||
|
{ label: 'America/Montevideo', value: 'America/Montevideo' },
|
||||||
|
{ label: 'America/Santiago', value: 'America/Santiago' },
|
||||||
|
{ label: 'Atlantic/South_Georgia', value: 'Atlantic/South_Georgia' },
|
||||||
|
{ label: 'Atlantic/Azores', value: 'Atlantic/Azores' },
|
||||||
|
{ label: 'Atlantic/Cape_Verde', value: 'Atlantic/Cape_Verde' },
|
||||||
|
{ label: 'Africa/Casablanca', value: 'Africa/Casablanca' },
|
||||||
|
{ label: 'UTC', value: 'UTC' },
|
||||||
|
{ label: 'Europe/London', value: 'Europe/London' },
|
||||||
|
{ label: 'Atlantic/Reykjavik', value: 'Atlantic/Reykjavik' },
|
||||||
|
{ label: 'Europe/Amsterdam', value: 'Europe/Amsterdam' },
|
||||||
|
{ label: 'Europe/Belgrade', value: 'Europe/Belgrade' },
|
||||||
|
{ label: 'Europe/Brussels', value: 'Europe/Brussels' },
|
||||||
|
{ label: 'Europe/Sarajevo', value: 'Europe/Sarajevo' },
|
||||||
|
{ label: 'Africa/Algiers', value: 'Africa/Algiers' },
|
||||||
|
{ label: 'Europe/Athens', value: 'Europe/Athens' },
|
||||||
|
{ label: 'Asia/Beirut', value: 'Asia/Beirut' },
|
||||||
|
{ label: 'Africa/Cairo', value: 'Africa/Cairo' },
|
||||||
|
{ label: 'Asia/Damascus', value: 'Asia/Damascus' },
|
||||||
|
{ label: 'Africa/Harare', value: 'Africa/Harare' },
|
||||||
|
{ label: 'Europe/Vilnius', value: 'Europe/Vilnius' },
|
||||||
|
{ label: 'Asia/Jerusalem', value: 'Asia/Jerusalem' },
|
||||||
|
{ label: 'Asia/Amman', value: 'Asia/Amman' },
|
||||||
|
{ label: 'Asia/Baghdad', value: 'Asia/Baghdad' },
|
||||||
|
{ label: 'Europe/Minsk', value: 'Europe/Minsk' },
|
||||||
|
{ label: 'Asia/Kuwait', value: 'Asia/Kuwait' },
|
||||||
|
{ label: 'Africa/Nairobi', value: 'Africa/Nairobi' },
|
||||||
|
{ label: 'Asia/Istanbul', value: 'Asia/Istanbul' },
|
||||||
|
{ label: 'Asia/Tehran', value: 'Asia/Tehran' },
|
||||||
|
{ label: 'Asia/Muscat', value: 'Asia/Muscat' },
|
||||||
|
{ label: 'Asia/Baku', value: 'Asia/Baku' },
|
||||||
|
{ label: 'Europe/Moscow', value: 'Europe/Moscow' },
|
||||||
|
{ label: 'Asia/Tbilisi', value: 'Asia/Tbilisi' },
|
||||||
|
{ label: 'Asia/Yerevan', value: 'Asia/Yerevan' },
|
||||||
|
{ label: 'Asia/Kabul', value: 'Asia/Kabul' },
|
||||||
|
{ label: 'Asia/Karachi', value: 'Asia/Karachi' },
|
||||||
|
{ label: 'Asia/Yekaterinburg', value: 'Asia/Yekaterinburg' },
|
||||||
|
{ label: 'Asia/Tashkent', value: 'Asia/Tashkent' },
|
||||||
|
{ label: 'Asia/Kolkata', value: 'Asia/Kolkata' },
|
||||||
|
{ label: 'Asia/Colombo', value: 'Asia/Colombo' },
|
||||||
|
{ label: 'Asia/Katmandu', value: 'Asia/Katmandu' },
|
||||||
|
{ label: 'Asia/Dhaka', value: 'Asia/Dhaka' },
|
||||||
|
{ label: 'Asia/Rangoon', value: 'Asia/Rangoon' },
|
||||||
|
{ label: 'Asia/Bangkok', value: 'Asia/Bangkok' },
|
||||||
|
{ label: 'Asia/Novosibirsk', value: 'Asia/Novosibirsk' },
|
||||||
|
{ label: 'Asia/Hong_Kong', value: 'Asia/Hong_Kong' },
|
||||||
|
{ label: 'Asia/Krasnoyarsk', value: 'Asia/Krasnoyarsk' },
|
||||||
|
{ label: 'Asia/Kuala_Lumpur', value: 'Asia/Kuala_Lumpur' },
|
||||||
|
{ label: 'Australia/Perth', value: 'Australia/Perth' },
|
||||||
|
{ label: 'Asia/Taipei', value: 'Asia/Taipei' },
|
||||||
|
{ label: 'Asia/Ulaanbaatar', value: 'Asia/Ulaanbaatar' },
|
||||||
|
{ label: 'Asia/Irkutsk', value: 'Asia/Irkutsk' },
|
||||||
|
{ label: 'Asia/Tokyo', value: 'Asia/Tokyo' },
|
||||||
|
{ label: 'Asia/Seoul', value: 'Asia/Seoul' },
|
||||||
|
{ label: 'Australia/Adelaide', value: 'Australia/Adelaide' },
|
||||||
|
{ label: 'Australia/Darwin', value: 'Australia/Darwin' },
|
||||||
|
{ label: 'Australia/Brisbane', value: 'Australia/Brisbane' },
|
||||||
|
{ label: 'Australia/Canberra', value: 'Australia/Canberra' },
|
||||||
|
{ label: 'Pacific/Guam', value: 'Pacific/Guam' },
|
||||||
|
{ label: 'Australia/Hobart', value: 'Australia/Hobart' },
|
||||||
|
{ label: 'Asia/Yakutsk', value: 'Asia/Yakutsk' },
|
||||||
|
{ label: 'Pacific/Noumea', value: 'Pacific/Noumea' },
|
||||||
|
{ label: 'Asia/Vladivostok', value: 'Asia/Vladivostok' },
|
||||||
|
{ label: 'Pacific/Auckland', value: 'Pacific/Auckland' },
|
||||||
|
{ label: 'Pacific/Fiji', value: 'Pacific/Fiji' },
|
||||||
|
{ label: 'Asia/Magadan', value: 'Asia/Magadan' },
|
||||||
|
{ label: 'Asia/Kamchatka', value: 'Asia/Kamchatka' },
|
||||||
|
{ label: 'Pacific/Tongatapu', value: 'Pacific/Tongatapu' }
|
||||||
|
];
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useAuthStore } from '@/store/modules/auth';
|
import {useAuthStore} from '@/store/modules/auth';
|
||||||
|
|
||||||
export function useAuth() {
|
export function useAuth() {
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
@@ -9,13 +9,26 @@ export function useAuth() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof codes === 'string') {
|
if (typeof codes === 'string') {
|
||||||
return authStore.userInfo.buttons.includes(codes);
|
return authStore.userInfo.permissions.includes(codes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return codes.some(code => authStore.userInfo.buttons.includes(code));
|
return codes.some(code => authStore.userInfo.permissions.includes(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasRole(role: string | string[]) {
|
||||||
|
if (!authStore.isLogin) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof role === 'string') {
|
||||||
|
return authStore.userInfo.roles.includes(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
return role.some(code => authStore.userInfo.roles.includes(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasAuth
|
hasAuth,
|
||||||
|
hasRole,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useCountDown, useLoading } from '@sa/hooks';
|
import { useCountDown, useLoading } from '@sa/hooks';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
import {REG_EMAIL} from '@/constants/reg';
|
import { REG_EMAIL } from '@/constants/reg';
|
||||||
import {useAuthStore} from "@/store/modules/auth";
|
import { useAuthStore } from '@/store/modules/auth';
|
||||||
|
|
||||||
export function useCaptcha() {
|
export function useCaptcha() {
|
||||||
const { loading, startLoading, endLoading } = useLoading();
|
const { loading, startLoading, endLoading } = useLoading();
|
||||||
@@ -39,20 +39,17 @@ export function useCaptcha() {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取验证码方法
|
//获取验证码方法
|
||||||
async function getCaptcha(email: string) {
|
async function getCaptcha(email: string) {
|
||||||
console.log(email)
|
|
||||||
//const valid = isPhoneValid(phone);
|
|
||||||
const valid = isEmailValid(email);
|
const valid = isEmailValid(email);
|
||||||
if (!valid || loading.value) {
|
if (!valid || loading.value) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
startLoading();
|
startLoading();
|
||||||
|
|
||||||
await authStore.captcha(
|
const data = await authStore.captcha(email);
|
||||||
email,
|
|
||||||
);
|
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
setTimeout(resolve, 500);
|
setTimeout(resolve, 500);
|
||||||
});
|
});
|
||||||
@@ -62,6 +59,7 @@ export function useCaptcha() {
|
|||||||
start();
|
start();
|
||||||
|
|
||||||
endLoading();
|
endLoading();
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import type { FormInstance } from 'ant-design-vue';
|
|||||||
import {REG_CODE_FOUR, REG_EMAIL, REG_PHONE, REG_PWD, REG_USER_NAME} from '@/constants/reg';
|
import {REG_CODE_FOUR, REG_EMAIL, REG_PHONE, REG_PWD, REG_USER_NAME} from '@/constants/reg';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
|
|
||||||
|
|
||||||
|
const regExpPasswd =/^(?![A-Za-z0-9]+$)(?![a-z0-9\W]+$)(?![A-Za-z\W]+$)(?![A-Z0-9\W]+$)[a-zA-Z0-9\W]{6,}$/;
|
||||||
|
|
||||||
export function useFormRules() {
|
export function useFormRules() {
|
||||||
const patternRules = {
|
const patternRules = {
|
||||||
username: {
|
username: {
|
||||||
@@ -30,7 +33,12 @@ export function useFormRules() {
|
|||||||
pattern: REG_EMAIL,
|
pattern: REG_EMAIL,
|
||||||
message: $t('form.email.invalid'),
|
message: $t('form.email.invalid'),
|
||||||
trigger: 'change'
|
trigger: 'change'
|
||||||
}
|
},
|
||||||
|
userPwd:{
|
||||||
|
pattern: regExpPasswd,
|
||||||
|
message: $t('form.pwd.invalid'),
|
||||||
|
trigger: 'change'
|
||||||
|
},
|
||||||
} satisfies Record<string, App.Global.FormRule>;
|
} satisfies Record<string, App.Global.FormRule>;
|
||||||
|
|
||||||
const formRules = {
|
const formRules = {
|
||||||
@@ -38,7 +46,8 @@ export function useFormRules() {
|
|||||||
phone: [createRequiredRule($t('form.phone.required')), patternRules.phone],
|
phone: [createRequiredRule($t('form.phone.required')), patternRules.phone],
|
||||||
pwd: [createRequiredRule($t('form.pwd.required')), patternRules.pwd],
|
pwd: [createRequiredRule($t('form.pwd.required')), patternRules.pwd],
|
||||||
code: [createRequiredRule($t('form.code.required')), patternRules.code],
|
code: [createRequiredRule($t('form.code.required')), patternRules.code],
|
||||||
email: [createRequiredRule($t('form.email.required')), patternRules.email]
|
email: [createRequiredRule($t('form.email.required')), patternRules.email],
|
||||||
|
userPwd: [createRequiredRule($t('form.pwd.required')), patternRules.userPwd],
|
||||||
} satisfies Record<string, App.Global.FormRule[]>;
|
} satisfies Record<string, App.Global.FormRule[]>;
|
||||||
|
|
||||||
/** the default required rule */
|
/** the default required rule */
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useRouter } from 'vue-router';
|
import type {RouteLocationRaw} from 'vue-router';
|
||||||
import type { RouteLocationRaw } from 'vue-router';
|
import {useRouter} from 'vue-router';
|
||||||
import type { RouteKey } from '@elegant-router/types';
|
import type {RouteKey} from '@elegant-router/types';
|
||||||
import { router as globalRouter } from '@/router';
|
import {router as globalRouter} from '@/router';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Router push
|
* Router push
|
||||||
@@ -24,7 +24,7 @@ export function useRouterPush(inSetup = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function routerPushByKey(key: RouteKey, options?: RouterPushOptions) {
|
async function routerPushByKey(key: RouteKey, options?: RouterPushOptions) {
|
||||||
const { query, params } = options || {};
|
const {query, params} = options || {};
|
||||||
|
|
||||||
const routeLocation: RouteLocationRaw = {
|
const routeLocation: RouteLocationRaw = {
|
||||||
name: key
|
name: key
|
||||||
@@ -53,7 +53,6 @@ export function useRouterPush(inSetup = true) {
|
|||||||
*/
|
*/
|
||||||
async function toLogin(loginModule?: UnionKey.LoginModule, redirectUrl?: string) {
|
async function toLogin(loginModule?: UnionKey.LoginModule, redirectUrl?: string) {
|
||||||
const module = loginModule || 'pwd-login';
|
const module = loginModule || 'pwd-login';
|
||||||
|
|
||||||
const options: RouterPushOptions = {
|
const options: RouterPushOptions = {
|
||||||
params: {
|
params: {
|
||||||
module
|
module
|
||||||
@@ -77,7 +76,7 @@ export function useRouterPush(inSetup = true) {
|
|||||||
async function toggleLoginModule(module: UnionKey.LoginModule) {
|
async function toggleLoginModule(module: UnionKey.LoginModule) {
|
||||||
const query = route.value.query as Record<string, string>;
|
const query = route.value.query as Record<string, string>;
|
||||||
|
|
||||||
return routerPushByKey('login', { query, params: { module } });
|
return routerPushByKey('login', {query, params: {module}});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Redirect from login */
|
/** Redirect from login */
|
||||||
|
|||||||
+21
-20
@@ -6,10 +6,8 @@ import { useAppStore } from '@/store/modules/app';
|
|||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
|
|
||||||
type TableData<T = object> = AntDesign.TableData<T>;
|
type TableData<T = object> = AntDesign.TableData<T>;
|
||||||
type GetTableData<A extends AntDesign.TableApiFn> = AntDesign.GetTableData<A>;
|
|
||||||
type TableColumn<T> = AntDesign.TableColumn<T>;
|
|
||||||
|
|
||||||
export function useTable<A extends AntDesign.TableApiFn>(config: AntDesign.AntDesignTableConfig<A>) {
|
export function useTable(config: any) {
|
||||||
const scope = effectScope();
|
const scope = effectScope();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
|
||||||
@@ -26,21 +24,21 @@ export function useTable<A extends AntDesign.TableApiFn>(config: AntDesign.AntDe
|
|||||||
searchParams,
|
searchParams,
|
||||||
updateSearchParams,
|
updateSearchParams,
|
||||||
resetSearchParams
|
resetSearchParams
|
||||||
} = useHookTable<A, GetTableData<A>, TableColumn<AntDesign.TableDataWithIndex<GetTableData<A>>>>({
|
} = useHookTable({
|
||||||
apiFn,
|
apiFn,
|
||||||
apiParams,
|
apiParams,
|
||||||
columns: config.columns,
|
columns: config.columns,
|
||||||
transformer: res => {
|
transformer: (res:any) => {
|
||||||
const { rows = [], total = 0 } = res.data || {};
|
const { rows = [], total = 0 } = res.data || {};
|
||||||
return {
|
return {
|
||||||
rows: rows.map((row, index) => ({ ...row, id: rowKey ? row[rowKey] : index })),
|
rows: rows.map((row:any, index:any) => ({ ...row, id: rowKey ? row[rowKey] : index })),
|
||||||
total
|
total
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getColumnChecks: cols => {
|
getColumnChecks: (cols:any) => {
|
||||||
const checks: AntDesign.TableColumnCheck[] = [];
|
const checks: AntDesign.TableColumnCheck[] = [];
|
||||||
|
|
||||||
cols.forEach(column => {
|
cols.forEach((column:any) => {
|
||||||
if (column.key) {
|
if (column.key) {
|
||||||
checks.push({
|
checks.push({
|
||||||
key: column.key as string,
|
key: column.key as string,
|
||||||
@@ -52,22 +50,22 @@ export function useTable<A extends AntDesign.TableApiFn>(config: AntDesign.AntDe
|
|||||||
|
|
||||||
return checks;
|
return checks;
|
||||||
},
|
},
|
||||||
getColumns: (cols, checks) => {
|
getColumns: (cols:any, checks:any) => {
|
||||||
const columnMap = new Map<string, TableColumn<GetTableData<A>>>();
|
const columnMap = new Map<string, any>();
|
||||||
|
|
||||||
cols.forEach(column => {
|
cols.forEach((column:any) => {
|
||||||
if (column.key) {
|
if (column.key) {
|
||||||
columnMap.set(column.key as string, column);
|
columnMap.set(column.key as string, column);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const filteredColumns = checks
|
const filteredColumns = checks
|
||||||
.filter(item => item.checked)
|
.filter((item:any) => item.checked)
|
||||||
.map(check => columnMap.get(check.key) as TableColumn<GetTableData<A>>);
|
.map((check:any) => columnMap.get(check.key) );
|
||||||
|
|
||||||
return filteredColumns;
|
return filteredColumns;
|
||||||
},
|
},
|
||||||
onFetched: async transformed => {
|
onFetched: async (transformed:any) => {
|
||||||
const { total } = transformed;
|
const { total } = transformed;
|
||||||
|
|
||||||
updatePagination({
|
updatePagination({
|
||||||
@@ -79,22 +77,25 @@ export function useTable<A extends AntDesign.TableApiFn>(config: AntDesign.AntDe
|
|||||||
|
|
||||||
const pagination: TablePaginationConfig = reactive({
|
const pagination: TablePaginationConfig = reactive({
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
pageSizeOptions: [10, 15, 20, 25, 30],
|
pageSizeOptions: ['10', '15', '20', '25', '30'],
|
||||||
total: 0,
|
total: 0,
|
||||||
simple: false,
|
simple: false,
|
||||||
// size: 'f',
|
// size: 'f',
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
|
defaultPageSize: 10,
|
||||||
|
responsive: true,
|
||||||
onChange: async (current: number, pageSize: number) => {
|
onChange: async (current: number, pageSize: number) => {
|
||||||
pagination.current = current;
|
pagination.current = current;
|
||||||
|
pagination.pageSize = pageSize;
|
||||||
updateSearchParams({
|
updateSearchParams({
|
||||||
pageNum: current,
|
pageNum: current,
|
||||||
pageSize
|
pageSize
|
||||||
});
|
});
|
||||||
|
|
||||||
getData();
|
getData();
|
||||||
}
|
},
|
||||||
|
showTotal: (total: number) =>
|
||||||
|
$t('common.tablePaginationTotal', { total: total })
|
||||||
});
|
});
|
||||||
|
|
||||||
// this is for mobile, if the system does not support mobile, you can use `pagination` directly
|
// this is for mobile, if the system does not support mobile, you can use `pagination` directly
|
||||||
@@ -150,10 +151,10 @@ export function useTableOperate<T extends TableData<{ [key: string]: any }>>(
|
|||||||
) {
|
) {
|
||||||
const { bool: drawerVisible, setTrue: openDrawer, setFalse: closeDrawer } = useBoolean();
|
const { bool: drawerVisible, setTrue: openDrawer, setFalse: closeDrawer } = useBoolean();
|
||||||
|
|
||||||
const operateType = ref<AntDesign.TableOperateType>('add');
|
const operateType = ref<any>('add');
|
||||||
const { getData, idKey = 'id' } = options;
|
const { getData, idKey = 'id' } = options;
|
||||||
/** the editing row data */
|
/** the editing row data */
|
||||||
const editingData: Ref<T | null> = ref(null);
|
const editingData: any = ref(null);
|
||||||
|
|
||||||
function handleAdd() {
|
function handleAdd() {
|
||||||
operateType.value = 'add';
|
operateType.value = 'add';
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'GlobalFooter'
|
name: 'GlobalFooter'
|
||||||
});
|
});
|
||||||
@@ -6,9 +10,7 @@ defineOptions({
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DarkModeContainer class="h-full flex-center">
|
<DarkModeContainer class="h-full flex-center">
|
||||||
<a href="https://github.com/honghuangdc/soybean-admin/blob/main/LICENSE" target="_blank" rel="noopener noreferrer">
|
<a href="#" target="_blank" rel="noopener noreferrer">Copyright © 2024 {{ $t('system.title') }}</a>
|
||||||
Copyright MIT © 2021 Soybean
|
|
||||||
</a>
|
|
||||||
</DarkModeContainer>
|
</DarkModeContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,16 @@ import { Modal } from 'ant-design-vue';
|
|||||||
import { useAuthStore } from '@/store/modules/auth';
|
import { useAuthStore } from '@/store/modules/auth';
|
||||||
import { useRouterPush } from '@/hooks/common/router';
|
import { useRouterPush } from '@/hooks/common/router';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
|
import {useRouter} from "vue-router";
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const router = useRouter();
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'UserAvatar'
|
name: 'UserAvatar'
|
||||||
});
|
});
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const { routerPushByKey, toLogin } = useRouterPush();
|
const { toLogin } = useRouterPush();
|
||||||
|
|
||||||
function loginOrRegister() {
|
function loginOrRegister() {
|
||||||
toLogin();
|
toLogin();
|
||||||
@@ -22,7 +25,7 @@ function logout() {
|
|||||||
okText: $t('common.confirm'),
|
okText: $t('common.confirm'),
|
||||||
cancelText: $t('common.cancel'),
|
cancelText: $t('common.cancel'),
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
authStore.resetStore();
|
authStore.resetStore(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -37,10 +40,14 @@ function logout() {
|
|||||||
</ButtonIcon>
|
</ButtonIcon>
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<AMenu>
|
<AMenu>
|
||||||
<AMenuItem @click="routerPushByKey('user-center')">
|
<!-- <AMenuItem @click="router.push('/user-center/email')">
|
||||||
<div class="flex-center gap-8px">
|
<div class="flex-center gap-8px">
|
||||||
<SvgIcon icon="ph:user-circle" class="text-icon" />
|
{{ $t('common.setemail') }}
|
||||||
{{ $t('common.userCenter') }}
|
</div>
|
||||||
|
</AMenuItem> -->
|
||||||
|
<AMenuItem @click="router.push('/static/resetpwd')">
|
||||||
|
<div class="flex-center gap-8px">
|
||||||
|
{{ $t('common.resetpwd') }}
|
||||||
</div>
|
</div>
|
||||||
</AMenuItem>
|
</AMenuItem>
|
||||||
<AMenuDivider />
|
<AMenuDivider />
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import GlobalBreadcrumb from '../global-breadcrumb/index.vue';
|
|||||||
import { useMixMenuContext } from '../../context';
|
import { useMixMenuContext } from '../../context';
|
||||||
import ThemeButton from './components/theme-button.vue';
|
import ThemeButton from './components/theme-button.vue';
|
||||||
import UserAvatar from './components/user-avatar.vue';
|
import UserAvatar from './components/user-avatar.vue';
|
||||||
|
import {useAuth} from "@/hooks/business/auth";
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'GlobalHeader'
|
name: 'GlobalHeader'
|
||||||
@@ -29,6 +30,8 @@ defineProps<Props>();
|
|||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
|
const { hasRole } = useAuth();
|
||||||
|
|
||||||
const { isFullscreen, toggle } = useFullscreen();
|
const { isFullscreen, toggle } = useFullscreen();
|
||||||
const { menus } = useMixMenuContext();
|
const { menus } = useMixMenuContext();
|
||||||
|
|
||||||
@@ -54,14 +57,14 @@ const headerMenus = computed(() => {
|
|||||||
<GlobalBreadcrumb v-if="!appStore.isMobile" class="ml-12px" />
|
<GlobalBreadcrumb v-if="!appStore.isMobile" class="ml-12px" />
|
||||||
</div>
|
</div>
|
||||||
<div class="h-full flex-y-center justify-end">
|
<div class="h-full flex-y-center justify-end">
|
||||||
|
<LangSwitch :lang="appStore.locale" :lang-options="appStore.localeOptions" @change-lang="appStore.changeLocale" "/>
|
||||||
<FullScreen v-if="!appStore.isMobile" :full="isFullscreen" @click="toggle" />
|
<FullScreen v-if="!appStore.isMobile" :full="isFullscreen" @click="toggle" />
|
||||||
<LangSwitch :lang="appStore.locale" :lang-options="appStore.localeOptions" @change-lang="appStore.changeLocale" />
|
|
||||||
<ThemeSchemaSwitch
|
<ThemeSchemaSwitch
|
||||||
:theme-schema="themeStore.themeScheme"
|
:theme-schema="themeStore.themeScheme"
|
||||||
:is-dark="themeStore.darkMode"
|
:is-dark="themeStore.darkMode"
|
||||||
@switch="themeStore.toggleThemeScheme"
|
@switch="themeStore.toggleThemeScheme"
|
||||||
/>
|
/>
|
||||||
<ThemeButton />
|
<ThemeButton v-if="hasRole('super')" />
|
||||||
<UserAvatar />
|
<UserAvatar />
|
||||||
</div>
|
</div>
|
||||||
</DarkModeContainer>
|
</DarkModeContainer>
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ function handleClickMixMenu(menu: App.Global.Menu) {
|
|||||||
<MixMenuItem
|
<MixMenuItem
|
||||||
v-for="menu in routeStore.menus"
|
v-for="menu in routeStore.menus"
|
||||||
:key="menu.key"
|
:key="menu.key"
|
||||||
|
:title="menu.label"
|
||||||
:label="menu.label"
|
:label="menu.label"
|
||||||
:icon="menu.icon"
|
:icon="menu.icon"
|
||||||
:active="menu.key === activeMenuKey"
|
:active="menu.key === activeMenuKey"
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ const { routerPushByKey } = useRouterPush();
|
|||||||
|
|
||||||
function handleSelectMixMenu(menu: App.Global.Menu) {
|
function handleSelectMixMenu(menu: App.Global.Menu) {
|
||||||
setActiveFirstLevelMenuKey(menu.key);
|
setActiveFirstLevelMenuKey(menu.key);
|
||||||
|
// 选择首个子菜单
|
||||||
|
if (Array.isArray(menu.children) && menu.children.length > 0) {
|
||||||
|
routerPushByKey(menu.children[0].routeKey);
|
||||||
|
}
|
||||||
if (!menu.children?.length) {
|
if (!menu.children?.length) {
|
||||||
routerPushByKey(menu.routeKey);
|
routerPushByKey(menu.routeKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import { localStg } from '@/utils/storage';
|
|||||||
*
|
*
|
||||||
* @param lang
|
* @param lang
|
||||||
*/
|
*/
|
||||||
export function setDayjsLocale(lang: App.I18n.LangType = 'zh-CN') {
|
export function setDayjsLocale(lang: App.I18n.LangType = 'en-US') {
|
||||||
const localMap = {
|
const localMap = {
|
||||||
'zh-CN': 'zh-cn',
|
'zh-CN': 'zh-cn',
|
||||||
'en-US': 'en'
|
'en-US': 'en'
|
||||||
} satisfies Record<App.I18n.LangType, string>;
|
} satisfies Record<App.I18n.LangType, string>;
|
||||||
|
|
||||||
const l = lang || localStg.get('lang') || 'zh-CN';
|
const l = lang || localStg.get('lang') || 'en-US';
|
||||||
|
|
||||||
locale(localMap[l]);
|
locale(localMap[l]);
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ import { localStg } from '@/utils/storage';
|
|||||||
import messages from './locale';
|
import messages from './locale';
|
||||||
|
|
||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
locale: localStg.get('lang') || 'zh-CN',
|
locale: localStg.get('lang') || 'en-US',
|
||||||
fallbackLocale: 'en',
|
fallbackLocale: 'en',
|
||||||
messages,
|
messages,
|
||||||
legacy: false
|
legacy: false
|
||||||
|
|||||||
+785
-12
@@ -1,3 +1,13 @@
|
|||||||
|
const viewEn: any = {
|
||||||
|
"view.dashboard":"dashboard",
|
||||||
|
"view.endpoint": "endpoint",
|
||||||
|
"view.endpoint_access": "current",
|
||||||
|
"view.endpoint_records": "Historical",
|
||||||
|
"view.billing": "Billing",
|
||||||
|
"view.billing_histories": "Historical",
|
||||||
|
"view.set-meal": "Package",
|
||||||
|
};
|
||||||
|
|
||||||
const local: any = {
|
const local: any = {
|
||||||
system: {
|
system: {
|
||||||
title: 'WANFi Platform'
|
title: 'WANFi Platform'
|
||||||
@@ -14,9 +24,15 @@ const local: any = {
|
|||||||
columnSetting: 'Column Setting',
|
columnSetting: 'Column Setting',
|
||||||
config: 'Config',
|
config: 'Config',
|
||||||
confirm: 'Confirm',
|
confirm: 'Confirm',
|
||||||
|
submit:'Confirm',
|
||||||
delete: 'Delete',
|
delete: 'Delete',
|
||||||
|
view: 'View',
|
||||||
|
exportOk: "Export Completed",
|
||||||
|
exportTip: "Confirm exporting xlsx table files based on search criteria?",
|
||||||
deleteSuccess: 'Delete Success',
|
deleteSuccess: 'Delete Success',
|
||||||
confirmDelete: 'Are you sure you want to delete?',
|
confirmDelete: 'Are you sure you want to delete?',
|
||||||
|
confirmClean: 'Are you sure you want to Clean?',
|
||||||
|
clearText: "Clean",
|
||||||
edit: 'Edit',
|
edit: 'Edit',
|
||||||
index: 'Index',
|
index: 'Index',
|
||||||
keywordSearch: 'Please enter keyword',
|
keywordSearch: 'Please enter keyword',
|
||||||
@@ -26,7 +42,7 @@ const local: any = {
|
|||||||
modify: 'Modify',
|
modify: 'Modify',
|
||||||
modifySuccess: 'Modify Success',
|
modifySuccess: 'Modify Success',
|
||||||
noData: 'No Data',
|
noData: 'No Data',
|
||||||
operate: 'Operate',
|
operate: 'Action',
|
||||||
pleaseCheckValue: 'Please check whether the value is valid',
|
pleaseCheckValue: 'Please check whether the value is valid',
|
||||||
refresh: 'Refresh',
|
refresh: 'Refresh',
|
||||||
reset: 'Reset',
|
reset: 'Reset',
|
||||||
@@ -37,11 +53,94 @@ const local: any = {
|
|||||||
update: 'Update',
|
update: 'Update',
|
||||||
updateSuccess: 'Update Success',
|
updateSuccess: 'Update Success',
|
||||||
userCenter: 'User Center',
|
userCenter: 'User Center',
|
||||||
|
setemail:'Bind Email',
|
||||||
|
resetpwd:'Reset Password',
|
||||||
yesOrNo: {
|
yesOrNo: {
|
||||||
yes: 'Yes',
|
yes: 'Yes',
|
||||||
no: 'No'
|
no: 'No'
|
||||||
|
},
|
||||||
|
ms: 'ms',
|
||||||
|
normal: 'Nomal',
|
||||||
|
abnormal: 'Abnormal',
|
||||||
|
export: 'Export',
|
||||||
|
loading: 'Loading',
|
||||||
|
selectPlease: 'please select',
|
||||||
|
disable: 'Disable',
|
||||||
|
default: 'Default',
|
||||||
|
system:'System',
|
||||||
|
record: 'Record',
|
||||||
|
noRecord: 'No Record',
|
||||||
|
msgSuccess: 'Success {msg}',
|
||||||
|
errorFields: 'Please fill in the required information in {num} correctly!',
|
||||||
|
tipTitle: 'Prompt',
|
||||||
|
units: {
|
||||||
|
second: 'Second',
|
||||||
|
minute: 'Minute',
|
||||||
|
hour: 'Hour',
|
||||||
|
day: 'Day',
|
||||||
|
week: 'Week',
|
||||||
|
month: 'Month',
|
||||||
|
year: 'Year',
|
||||||
|
core: 'Core',
|
||||||
|
},
|
||||||
|
tablePaginationTotal: 'Total {total} items',
|
||||||
|
inputPlease: 'Please input',
|
||||||
|
time:{
|
||||||
|
second: 's',
|
||||||
|
minute: 'Min',
|
||||||
|
hour: 'Hour',
|
||||||
|
day: 'Day'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// 组件
|
||||||
|
components: {
|
||||||
|
CronModal: {
|
||||||
|
title: "Cron Expression Generator",
|
||||||
|
addon: "Expression Preview:",
|
||||||
|
day1: "Every day",
|
||||||
|
day21: "Execute every",
|
||||||
|
day22: "days, starting from the",
|
||||||
|
day23: "day",
|
||||||
|
day31: "Cycle from",
|
||||||
|
day32: "to",
|
||||||
|
day33: "days",
|
||||||
|
day4: "Designated day (optional)",
|
||||||
|
day5: "Last day of the month",
|
||||||
|
hour1: "Hourly",
|
||||||
|
hour21: "Execute every",
|
||||||
|
hour22: "hours, starting from the",
|
||||||
|
hour23: "hour",
|
||||||
|
hour31: "Cycle time from",
|
||||||
|
hour32: "to",
|
||||||
|
hour33: "hours",
|
||||||
|
hour4: "Specified hours (multiple options available)",
|
||||||
|
minute1: "Every minute",
|
||||||
|
minute21: "Execute every",
|
||||||
|
minute22: "minutes, starting from the",
|
||||||
|
minute23: "minute",
|
||||||
|
minute31: "Cycle time from",
|
||||||
|
minute32: "to",
|
||||||
|
minute33: "minutes",
|
||||||
|
minute4: "Specified minutes (multiple options available)",
|
||||||
|
month1: "Every month",
|
||||||
|
month21: "Execute every",
|
||||||
|
month22: "months, starting from the",
|
||||||
|
month23: "month",
|
||||||
|
month31: "Cycle time from",
|
||||||
|
month32: "to",
|
||||||
|
month33: "months",
|
||||||
|
month4: "Specified months (multiple options available)",
|
||||||
|
second1: "Every second",
|
||||||
|
second21: "Execute every",
|
||||||
|
second22: "seconds, starting from the",
|
||||||
|
second23: "second",
|
||||||
|
second31: "Cycle time from",
|
||||||
|
second32: "to",
|
||||||
|
second33: "seconds",
|
||||||
|
second4: "Specify the number of seconds (multiple selectable)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
request: {
|
request: {
|
||||||
logout: 'Logout user after request failed',
|
logout: 'Logout user after request failed',
|
||||||
logoutMsg: 'User status is invalid, please log in again',
|
logoutMsg: 'User status is invalid, please log in again',
|
||||||
@@ -137,7 +236,7 @@ const local: any = {
|
|||||||
403: 'No Permission',
|
403: 'No Permission',
|
||||||
404: 'Page Not Found',
|
404: 'Page Not Found',
|
||||||
500: 'Server Error',
|
500: 'Server Error',
|
||||||
home: 'Home',
|
home: 'Dashboard',
|
||||||
'user-center': 'User Center',
|
'user-center': 'User Center',
|
||||||
about: 'About',
|
about: 'About',
|
||||||
function: 'System Function',
|
function: 'System Function',
|
||||||
@@ -162,7 +261,9 @@ const local: any = {
|
|||||||
manage_dept: 'Dept Manage',
|
manage_dept: 'Dept Manage',
|
||||||
manage_route: 'Route Manage',
|
manage_route: 'Route Manage',
|
||||||
manage_post: 'Post Manage',
|
manage_post: 'Post Manage',
|
||||||
manage_dict: 'Dict Manage'
|
manage_dict: 'Dict Manage',
|
||||||
|
manage_dictData:'Dict Data',
|
||||||
|
manage_task_log: 'Task Log',
|
||||||
},
|
},
|
||||||
page: {
|
page: {
|
||||||
login: {
|
login: {
|
||||||
@@ -210,6 +311,8 @@ const local: any = {
|
|||||||
agreeTerms: 'I have read and agree to the User Agreement and Privacy Policy',
|
agreeTerms: 'I have read and agree to the User Agreement and Privacy Policy',
|
||||||
code:'Code',
|
code:'Code',
|
||||||
password:'Password',
|
password:'Password',
|
||||||
|
newPassword:'New Password',
|
||||||
|
oldPassword:'Old Password',
|
||||||
confirmPassword:'ConfirmPassword',
|
confirmPassword:'ConfirmPassword',
|
||||||
basicInfo: 'BasicInfo',
|
basicInfo: 'BasicInfo',
|
||||||
terms: 'Terms',
|
terms: 'Terms',
|
||||||
@@ -228,6 +331,18 @@ const local: any = {
|
|||||||
birthDate: 'Birth Date',
|
birthDate: 'Birth Date',
|
||||||
birthDatePlaceholder: 'Please select birth date',
|
birthDatePlaceholder: 'Please select birth date',
|
||||||
birthDateRequired: 'Please select birth date',
|
birthDateRequired: 'Please select birth date',
|
||||||
|
genderRequired:'Please select gender',
|
||||||
|
usernameLengthLimit:"Username is too short",
|
||||||
|
usernameExists:"The username is already registered",
|
||||||
|
usernameRequired:"The username cannot be empty",
|
||||||
|
phoneInvalid:"The mobile phone number is incorrect",
|
||||||
|
phoneExists:"The mobile phone number has been registered",
|
||||||
|
emailInvalid:"The email is incorrect",
|
||||||
|
emailExists:"The email has been registered",
|
||||||
|
emailRequired:"The email cannot be empty",
|
||||||
|
codeRequired:"The code cannot be empty",
|
||||||
|
passwordRequired:"The password cannot be empty",
|
||||||
|
passwordLength:"The password is too short",
|
||||||
},
|
},
|
||||||
resetPwd: {
|
resetPwd: {
|
||||||
title: 'Reset Password'
|
title: 'Reset Password'
|
||||||
@@ -239,7 +354,7 @@ const local: any = {
|
|||||||
|
|
||||||
about: {
|
about: {
|
||||||
title: 'About',
|
title: 'About',
|
||||||
introduction: `Soybean Admin is an elegant and powerful admin template, based on the latest front-end technology stack, including Vue3, Vite5, TypeScript, Pinia and UnoCSS. It has built-in rich theme configuration and components, strict code specifications, and an automated file routing system. In addition, it also uses the online mock data solution based on ApiFox. Soybean Admin provides you with a one-stop admin solution, no additional configuration, and out of the box. It is also a best practice for learning cutting-edge technologies quickly.`,
|
introduction: `Admin is an elegant and powerful admin template, based on the latest front-end technology stack, including Vue3, Vite5, TypeScript, Pinia and UnoCSS. It has built-in rich theme configuration and components, strict code specifications, and an automated file routing system. In addition, it also uses the online mock data solution based on ApiFox. WANFI Admin provides you with a one-stop admin solution, no additional configuration, and out of the box. It is also a best practice for learning cutting-edge technologies quickly.`,
|
||||||
projectInfo: {
|
projectInfo: {
|
||||||
title: 'Project Info',
|
title: 'Project Info',
|
||||||
version: 'Version',
|
version: 'Version',
|
||||||
@@ -269,11 +384,11 @@ const local: any = {
|
|||||||
projectNews: {
|
projectNews: {
|
||||||
title: 'Project News',
|
title: 'Project News',
|
||||||
moreNews: 'More News',
|
moreNews: 'More News',
|
||||||
desc1: 'Soybean created the open source project soybean-admin on May 28, 2021!',
|
desc1: 'created the open source project WANFI-admin on May 28, 2021!',
|
||||||
desc2: 'zyh submitted a bug to soybean-admin, the multi-tab bar will not adapt.',
|
desc2: 'zyh submitted a bug to WANFI-admin, the multi-tab bar will not adapt.',
|
||||||
desc3: 'Soybean is ready to do sufficient preparation for the release of soybean-admin!',
|
desc3: 'WANFI is ready to do sufficient preparation for the release of WANFI-admin!',
|
||||||
desc4: 'Soybean is busy writing project documentation for soybean-admin!',
|
desc4: 'WANFI is busy writing project documentation for WANFI-admin!',
|
||||||
desc5: 'Soybean just wrote some of the workbench pages casually, and it was enough to see!'
|
desc5: 'WANFI just wrote some of the workbench pages casually, and it was enough to see!'
|
||||||
},
|
},
|
||||||
creativity: 'Creativity'
|
creativity: 'Creativity'
|
||||||
},
|
},
|
||||||
@@ -348,6 +463,7 @@ const local: any = {
|
|||||||
password: 'Password',
|
password: 'Password',
|
||||||
post: 'Post',
|
post: 'Post',
|
||||||
role: 'Role',
|
role: 'Role',
|
||||||
|
createtime:'Create time',
|
||||||
form: {
|
form: {
|
||||||
userName: 'Please enter username',
|
userName: 'Please enter username',
|
||||||
email: 'Please enter email',
|
email: 'Please enter email',
|
||||||
@@ -462,10 +578,666 @@ const local: any = {
|
|||||||
remark: 'Please enter remark'
|
remark: 'Please enter remark'
|
||||||
},
|
},
|
||||||
addDict: 'Add Dictionary',
|
addDict: 'Add Dictionary',
|
||||||
editDict: 'Edit Dictionary'
|
editDict: 'Edit Dictionary',
|
||||||
|
dictDataTitle:'Dictionary Data',
|
||||||
|
dictData:{
|
||||||
|
dictType: "Dictionary name",
|
||||||
|
dictCode: "Data Code",
|
||||||
|
dictLabel: "Data Key",
|
||||||
|
dictLabelPleac: "Please enter the data key correctly",
|
||||||
|
dictValue: "Data Value",
|
||||||
|
dictValuePleac: "Please enter the data value correctly",
|
||||||
|
dictSort: "Data Sort",
|
||||||
|
status: "Status",
|
||||||
|
createTime: "CreateTime",
|
||||||
|
tagType: "Tag Type",
|
||||||
|
tagTypeShow: "Tag Type Show",
|
||||||
|
tagClass: "Tag Class",
|
||||||
|
remark: "Remark",
|
||||||
|
viewInfo: "Dictionary Data Info",
|
||||||
|
viewInfoErr: "Failed to get dictionary data information",
|
||||||
|
addInfo: "Add Dictionary Data",
|
||||||
|
editInfo: "Modifying Dictionary Data",
|
||||||
|
delTip: "Confirm deleting the data item with dictionary data code [{txt}]?",
|
||||||
|
delOk: "Deleted successfully",
|
||||||
|
exportTip: "Confirm exporting xlsx table files based on search criteria?",
|
||||||
|
exportOk: "Completed export",
|
||||||
|
typeDataErr: "Failed to get dictionary type information",
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
log:{
|
||||||
|
logId:'Log ID',
|
||||||
|
module:'Module Title',
|
||||||
|
operType:'Business Type',
|
||||||
|
operName:'Operator',
|
||||||
|
operIp:'Operation Address',
|
||||||
|
operArea:'Operation Location',
|
||||||
|
operStatus:'Status',
|
||||||
|
operTime:'Operation Time',
|
||||||
|
useTime:'Time Consumption',
|
||||||
|
backUser:'Back User',
|
||||||
|
phoneUser:'Phone User',
|
||||||
|
other:'Other',
|
||||||
|
operUrl:'Operation URL',
|
||||||
|
operParam:'Operation Parameters',
|
||||||
|
jsonResult:"Result",
|
||||||
|
title:"Log Management",
|
||||||
|
},
|
||||||
|
task:{
|
||||||
|
title:'Task Management',
|
||||||
|
taskId:'ID',
|
||||||
|
taskName:'Name',
|
||||||
|
logTitle:'Task Log',
|
||||||
|
group:'Group',
|
||||||
|
invoke:'Invoke',
|
||||||
|
cron:'Cron',
|
||||||
|
status:'Status',
|
||||||
|
log:'Log',
|
||||||
|
createTime:'Create Time',
|
||||||
|
targetParams:'Arguments',
|
||||||
|
remark:'Remark',
|
||||||
|
viewJob:'View Job',
|
||||||
|
addJob:'Add Job',
|
||||||
|
editJob:'Edit Job',
|
||||||
|
viewInfoErr:'Failed to get job information',
|
||||||
|
getInfoError:'Get Info Error',
|
||||||
|
jobNamePlease: 'Please enter the task name correctly, limited to 2-50 characters',
|
||||||
|
invokeTargetPlease: 'Please enter the call target correctly, limited to 2-50 characters.',
|
||||||
|
cronExpressionPlease: 'Please enter or generate a cron execution expression',
|
||||||
|
jobGroup: "Job Group",
|
||||||
|
saveLog: "Save Log",
|
||||||
|
invokeTargetTip: "Parameter description: support for preset incoming parameters, serialized processing parameters in the processor",
|
||||||
|
cronExpressionTip: "Example of an expression:0/20 * * * * ?",
|
||||||
|
cronExpressionTip1: "Illustrative example: Execute tasks every 20 seconds",
|
||||||
|
cronExpressionNew: "Generating Expression",
|
||||||
|
targetParamsPlease: 'Call target incoming parameters, only support json strings',
|
||||||
|
delTip: "Are you sure you want to delete task number [{num}]?",
|
||||||
|
delLogTip: "Are you sure you want to delete Log number [{num}]?",
|
||||||
|
runOneTip: "Are you sure you want to perform a [{num}] task right away?",
|
||||||
|
runOneOk: "{num} Executed successfully",
|
||||||
|
runOne:'execute once',
|
||||||
|
jobLog: "Task Log",
|
||||||
|
jobMessage: "Task Message",
|
||||||
|
clearTip: "Confirm that all dispatch log data items are cleared?",
|
||||||
|
clearOk: "Cleared Successfully",
|
||||||
|
statusChange: "Are you sure you want the {text} {num} job?",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
carddata:{
|
||||||
|
sitelist:'Site List',
|
||||||
|
sitename:'NAME',
|
||||||
|
country:'COUNTRY/REGION',
|
||||||
|
alert:'ALERTS',
|
||||||
|
gateway:'GATEWAY',
|
||||||
|
switches:'SWITCHES',
|
||||||
|
clients:'CLIENTS',
|
||||||
|
search:'Search site name',
|
||||||
|
total:'Total',
|
||||||
|
addsite:'Add New Site',
|
||||||
|
region:'Country/Region',
|
||||||
|
timezone:'TimeZone',
|
||||||
|
scenario:'Scenario',
|
||||||
|
username:'Username',
|
||||||
|
password:'Password',
|
||||||
|
deleteConfirmTitle:'Are you sure to delete',
|
||||||
|
deleteConfirmContent:'Are you sure to delete {name}?',
|
||||||
|
confirm:'Confirm',
|
||||||
|
cancel:'Cancel',
|
||||||
|
deleteSuccess:'Delete Success',
|
||||||
|
editsite:'Edit Site',
|
||||||
|
office:'Office',
|
||||||
|
hotel:'Hotel',
|
||||||
|
education:'Education',
|
||||||
|
retail:'Retail',
|
||||||
|
other:'Other',
|
||||||
|
updateSuccess:'Update Success',
|
||||||
|
wireless:'Wireless Features',
|
||||||
|
autoFailover:'Auto Failover',
|
||||||
|
conDetection:'Connectivity Detection',
|
||||||
|
autoRec:'Auto(Recommended)',
|
||||||
|
custom:'Custom',
|
||||||
|
fastRoaming:'Fast Roaming',
|
||||||
|
aiRoaming:'AI Roaming',
|
||||||
|
passwordInvalid:'The password format is incorrect, please include uppercase and lowercase letters and symbols.',
|
||||||
|
addSuccess:'Add success',
|
||||||
|
meshtext:'If the IP Address of the Wireless Device is in different network segments from the Custom IP Address, the Wireless Device will use the default gateway IP address for the detection.'
|
||||||
|
},
|
||||||
|
headerbanner:{
|
||||||
|
controller:'Controller Overview',
|
||||||
|
connected:'Connected',
|
||||||
|
cloud:'Cloud Access',
|
||||||
|
sites:'Sites',
|
||||||
|
totalsite:'Total Sites',
|
||||||
|
gateway:'Gateways',
|
||||||
|
switches:'Switches',
|
||||||
|
register:'Register Users',
|
||||||
|
online:'Online Users',
|
||||||
|
client:'Client',
|
||||||
|
alerts:'Alerts',
|
||||||
|
connect:'Connected',
|
||||||
|
disconnect:'Disconnected',
|
||||||
|
registuser:'Register',
|
||||||
|
onlineuser:'Online',
|
||||||
|
isolated:'Isolated',
|
||||||
|
wired:'Wired client',
|
||||||
|
wireless:'Wireless client',
|
||||||
|
guest:'Wireless Guest',
|
||||||
|
alert:'Alerts',
|
||||||
|
},
|
||||||
|
bill:{
|
||||||
|
username:'User Name',
|
||||||
|
billtime:'Order Time',
|
||||||
|
billtype:'Order Type',
|
||||||
|
packagebill:'Package',
|
||||||
|
rechargebill:'Recharge',
|
||||||
|
packagename:'Package Name',
|
||||||
|
amount:'Amount',
|
||||||
|
status:'Status',
|
||||||
|
wait:'Pending',
|
||||||
|
done:'Paid',
|
||||||
|
close:'Canceled',
|
||||||
|
billinfo:'Billing information',
|
||||||
|
total:'Total',
|
||||||
|
pleusername:'Please enter username',
|
||||||
|
plebilltype:'Please select order type',
|
||||||
|
plestatus:'Please select order status',
|
||||||
|
reset:'Reset',
|
||||||
|
search:'Search',
|
||||||
|
},
|
||||||
|
apdevice:{
|
||||||
|
aptitle:'AP Device Management',
|
||||||
|
online:'Online',
|
||||||
|
outline:'Offline',
|
||||||
|
pending:'Pending',
|
||||||
|
apname:'Device Name',
|
||||||
|
ip:'IP',
|
||||||
|
mac:'MAC',
|
||||||
|
model:'Model',
|
||||||
|
uptime:'Online Time',
|
||||||
|
status:'Status',
|
||||||
|
total:'Total',
|
||||||
|
pledevice:'Please enter device name',
|
||||||
|
plemac:'Please enter MAC address',
|
||||||
|
search:'Search',
|
||||||
|
reset:'Reset',
|
||||||
|
confirmReboot:'Confirm Restart',
|
||||||
|
confirmForget:'Confirm Forget',
|
||||||
|
forgetConfirmContent:'Sure to forget { name }?',
|
||||||
|
rebootConfirmContent:'Sure to restart { name }?',
|
||||||
|
rebootSuccess:'Send to restart success',
|
||||||
|
editConfig:'Edit config',
|
||||||
|
forget:'Forget device',
|
||||||
|
restart:'Restart device',
|
||||||
|
adopt:'Adopt device',
|
||||||
|
addDevice:'Add device',
|
||||||
|
sn:'Serial number',
|
||||||
|
name:'Device name(optional)',
|
||||||
|
username:'Device username(optional)',
|
||||||
|
password:'Device password(optional)',
|
||||||
|
snFormatError:'A-Z or 13-bit characters from 0-9',
|
||||||
|
nameFormatError:"Cannot start with space, +、-、{test}, = characters,cannot end with space, the length is between 1-128",
|
||||||
|
forgetConfirm:'Are you sure you want to forget your device?',
|
||||||
|
restartConfirm:'Are you sure you want to restart your device?',
|
||||||
|
led:'LED',
|
||||||
|
useSiteSettings:'Use Site settings',
|
||||||
|
on:'On',
|
||||||
|
off:'Off',
|
||||||
|
longitude:'Longitude(optional)',
|
||||||
|
latitude:'Latitude(optional)',
|
||||||
|
address:'Address(optional)',
|
||||||
|
plesearch:'Search Devicename,IP,Model',
|
||||||
|
selectSite:'No site',
|
||||||
|
adoptSuccess:'Adopt success',
|
||||||
|
adoptError:'Adopt error',
|
||||||
|
forgetSuccess:'Forget success',
|
||||||
|
forgetError:'Forget error',
|
||||||
|
getConfigError:'Get config error',
|
||||||
|
snRequired:'Serial number',
|
||||||
|
addSuccess:'Add success',
|
||||||
|
addError:'Add error',
|
||||||
|
longitudeError:'Longitude error',
|
||||||
|
latitudeError:'latitude error',
|
||||||
|
configSuccess:'Config success',
|
||||||
|
configError:'config error',
|
||||||
|
},
|
||||||
|
wlan:{
|
||||||
|
title:'WLAN',
|
||||||
|
selectSite:'No Site',
|
||||||
|
selectGroup:'No Group',
|
||||||
|
total:'Total',
|
||||||
|
name:'SSID Name',
|
||||||
|
none:'None',
|
||||||
|
passwordPlaceholder:'Please enter an 8~63-digit password',
|
||||||
|
passwordRequired:'The password cannot be empty',
|
||||||
|
passwordLength:'Please enter 8~63 characters or numbers for the password',
|
||||||
|
security: {
|
||||||
|
security:'Security',
|
||||||
|
wpaEnterprise: 'WPA-Enterprise',
|
||||||
|
wpaPersonal: 'WPA-Personal',
|
||||||
|
ppskWithoutRadius: 'PPSK without RADIUS',
|
||||||
|
ppskWithRadius: 'PPSK with RADIUS',
|
||||||
|
},
|
||||||
|
password:'Password',
|
||||||
|
portalEnable:'Portal',
|
||||||
|
portalName:'Portal Name',
|
||||||
|
band:'Band',
|
||||||
|
bandtip:'Only 8 SSIDs can exist for each band type at 2.4 GHz, 5 GHz, and 6 GHz',
|
||||||
|
guestNetwork:'Guest Network',
|
||||||
|
enable:'Enable',
|
||||||
|
disable:'Disable',
|
||||||
|
deviceType:'Device Type',
|
||||||
|
broadcast:'SSID Broadcast',
|
||||||
|
vlan:'VLAN',
|
||||||
|
addSsid:'Add SSID',
|
||||||
|
open:'Open',
|
||||||
|
vlanId:'VLAN ID',
|
||||||
|
default:'Default',
|
||||||
|
custom:'Custom',
|
||||||
|
nameRequired:'Name can not be empty',
|
||||||
|
nameLength:'Length of name is 1~32 characters',
|
||||||
|
vlanIdRequired:'VLAN ID can not be empty',
|
||||||
|
addSuccess:'Add success',
|
||||||
|
confirmDelete:'Delete device',
|
||||||
|
deleteConfirmContent:'Do you want to delete the device?',
|
||||||
|
deleteSuccess:'Delete success',
|
||||||
|
editSsid:'Edit SSID',
|
||||||
|
updateSuccess:'Update success',
|
||||||
|
},
|
||||||
|
portal: {
|
||||||
|
title: 'Portal management',
|
||||||
|
name: 'Name',
|
||||||
|
selectSite:'no site',
|
||||||
|
authType: 'Authentication Type',
|
||||||
|
auth: {
|
||||||
|
none: 'No Authentication',
|
||||||
|
simplePassword: 'Simple password',
|
||||||
|
externalRadius: 'RADIUS server',
|
||||||
|
externalPortal: 'External Portal server',
|
||||||
|
hotspot: 'Hotspot',
|
||||||
|
ldap: 'LDAP'
|
||||||
|
},
|
||||||
|
addPortal: 'Add Portal',
|
||||||
|
enable: 'Enable',
|
||||||
|
ssid: 'SSID',
|
||||||
|
selectSsid: 'Please select SSID',
|
||||||
|
authTimeout: 'Authentication Timeout',
|
||||||
|
dailyLimit: 'Daily Limit',
|
||||||
|
enableDailyLimit: 'Enable',
|
||||||
|
httpsRedirect: 'HTTPS Redirection',
|
||||||
|
enableHttpsRedirect: 'Enable',
|
||||||
|
landingPage: 'Landing Page',
|
||||||
|
landingUrl: 'URL',
|
||||||
|
enterUrl: 'Please enter URL',
|
||||||
|
nameRequired: 'Please enter portal name',
|
||||||
|
ssidRequired: 'Please select SSID',
|
||||||
|
urlRequired: 'Please enter URL',
|
||||||
|
addSuccess: 'Add Success',
|
||||||
|
addError: 'Add Error',
|
||||||
|
total:'Total',
|
||||||
|
updateSuccess:'Update success',
|
||||||
|
editPortal:'Edit Portal',
|
||||||
|
timeUnit: {
|
||||||
|
min: 'Min',
|
||||||
|
hour: 'Hour',
|
||||||
|
day: 'Day'
|
||||||
|
},
|
||||||
|
landing: {
|
||||||
|
originalUrl: 'The Original URL',
|
||||||
|
promotionUrl: 'The Promotional URL',
|
||||||
|
logoutPage: 'The Success Page'
|
||||||
|
},
|
||||||
|
externalPortal: 'External Portal server',
|
||||||
|
ipAddress: 'IP Address',
|
||||||
|
url: 'URL',
|
||||||
|
ipRequired: 'Please enter IP',
|
||||||
|
invalidUrl: 'The URL is not formatted correctly',
|
||||||
|
confirmDelete: 'Confirm Delete',
|
||||||
|
deleteConfirmContent: 'Sure to delete portal {name} ?',
|
||||||
|
deleteSuccess: 'Delete success'
|
||||||
|
},
|
||||||
|
alerts:{
|
||||||
|
alerts:'Alerts',
|
||||||
|
choosesite: 'Please select a site',
|
||||||
|
deletesuccess: 'Delete successful',
|
||||||
|
deletefail: 'Delete failed',
|
||||||
|
choserecord: 'Please select the record to operate on',
|
||||||
|
deletetitle: 'Confirm deletion',
|
||||||
|
deletebody: 'record(s)?',
|
||||||
|
suredelete: 'Are you sure you want to delete this alarm record?',
|
||||||
|
sure: 'Confirm',
|
||||||
|
cancel: 'Cancel',
|
||||||
|
unresolved: 'Unresolved',
|
||||||
|
resolved: 'Resolved',
|
||||||
|
all: 'All',
|
||||||
|
system: 'System',
|
||||||
|
device: 'Device',
|
||||||
|
batchdelete: 'Batch delete',
|
||||||
|
resovetitle: 'Mark as resolved',
|
||||||
|
delete: 'Delete',
|
||||||
|
type:'TYPE',
|
||||||
|
level:'LEVEL',
|
||||||
|
content:'CONTENT',
|
||||||
|
time:'TIME',
|
||||||
|
action:'ACTION',
|
||||||
|
},
|
||||||
|
access:{
|
||||||
|
title:'Access Control',
|
||||||
|
plesite:'please select site',
|
||||||
|
authaccess:'Pre-Authentication Access',
|
||||||
|
enable:'Enable',
|
||||||
|
authaccesslist:'Pre-Authentication Access List',
|
||||||
|
delete:'Delete',
|
||||||
|
authclient:'Authentication-Free Client',
|
||||||
|
authclientlist:'Authentication-Free Client List',
|
||||||
|
apply:'Apply',
|
||||||
|
cancel:'Cancel',
|
||||||
|
type:'TYPE',
|
||||||
|
pleurl:'Please select URL',
|
||||||
|
addauth:'Add Pre-Authentication Access',
|
||||||
|
addclient:'Add Authentication-Free Client',
|
||||||
|
add:'Add',
|
||||||
|
info:'INFORMATION',
|
||||||
|
action:'ACTION',
|
||||||
|
deletetitle:'Delete',
|
||||||
|
deletebody:'Are you sure you want to delete this record?',
|
||||||
|
ok:'confirm',
|
||||||
|
plenumber:'Please enter a valid number',
|
||||||
|
subnetMask:'Subnet mask must be between 0-32',
|
||||||
|
iperror:'ip is not right',
|
||||||
|
applysuccess:'Apply Success',
|
||||||
|
|
||||||
|
},
|
||||||
|
terminal:{
|
||||||
|
title:'Terminal',
|
||||||
|
total:'Total',
|
||||||
|
unknow:'Unknow',
|
||||||
|
day:'Day',
|
||||||
|
hour:'Hour',
|
||||||
|
min:'min',
|
||||||
|
second:'s',
|
||||||
|
name:'Device Name',
|
||||||
|
ip:'IP',
|
||||||
|
status:'Status',
|
||||||
|
ssid:'SSID',
|
||||||
|
apname:'Affiliated AP device',
|
||||||
|
activity:'Rate',
|
||||||
|
down:'Traffic Down',
|
||||||
|
up:'Traffic Up',
|
||||||
|
uptime:'Online Time',
|
||||||
|
pledevice:'Please enter device name',
|
||||||
|
model:'Model',
|
||||||
|
plemodel:'Please enter type of device',
|
||||||
|
mac:'MAC',
|
||||||
|
plemac:'Please enter MAC address',
|
||||||
|
search:'Search',
|
||||||
|
reset:'Reset',
|
||||||
|
pending:'Pending',
|
||||||
|
authorized:'Authorized',
|
||||||
|
authfree:'AUTH-FREE',
|
||||||
|
},
|
||||||
|
user:{
|
||||||
|
title:'User Information',
|
||||||
|
username:'User Name',
|
||||||
|
fullname:'Full Name',
|
||||||
|
sex:'Gender',
|
||||||
|
man:'Male',
|
||||||
|
woman:'Female',
|
||||||
|
birthdate:'Birth Date',
|
||||||
|
age:'Age ',
|
||||||
|
email:'Email',
|
||||||
|
phone:'Phone',
|
||||||
|
kyc:'KYC',
|
||||||
|
ver:'Verified',
|
||||||
|
unver:'Unverified',
|
||||||
|
pending:'Pending',
|
||||||
|
rejected:'Rejected',
|
||||||
|
pleusername:'Please enter username',
|
||||||
|
pleemail:'Please enter email address',
|
||||||
|
search:'Search',
|
||||||
|
reset:'Reset',
|
||||||
|
},
|
||||||
|
cdr:{
|
||||||
|
hour:'hour',
|
||||||
|
min:'min',
|
||||||
|
sec:'s',
|
||||||
|
username:'User Name',
|
||||||
|
clientname:'Client Name',
|
||||||
|
clientmac:'Client MAC',
|
||||||
|
up:'Traffic Up',
|
||||||
|
down:'Traffic Down',
|
||||||
|
start:'Start Time',
|
||||||
|
end:'End Time',
|
||||||
|
duration:'Duration',
|
||||||
|
title:'CDR Records',
|
||||||
|
total:'Total',
|
||||||
|
pleusername:'Please enter username',
|
||||||
|
pleclientname:'Please enter device name',
|
||||||
|
search:'Search',
|
||||||
|
reset:'Reset',
|
||||||
|
timerange:'End time range',
|
||||||
|
startTime:'StartTime',
|
||||||
|
endTime:'EndTime'
|
||||||
|
},
|
||||||
|
kyc:{
|
||||||
|
title:'KYC Authentication Review',
|
||||||
|
total:'Total',
|
||||||
|
pass:'Pass',
|
||||||
|
refuse:'Refuse',
|
||||||
|
verified:'Verified',
|
||||||
|
unverified:'Unverified',
|
||||||
|
pending:'Pending',
|
||||||
|
approved:'Approved',
|
||||||
|
rejected:'Rejected',
|
||||||
|
unknow:'unknow',
|
||||||
|
username:'User Name',
|
||||||
|
realname:'Real Name',
|
||||||
|
type:'Identification type',
|
||||||
|
file:'Identification photograph',
|
||||||
|
picture:'Facial photograph',
|
||||||
|
status:'Status',
|
||||||
|
createtime:'Create Time',
|
||||||
|
operate:'Action',
|
||||||
|
confirmtitle:'Confirmation approved.',
|
||||||
|
confirmcontent:'Are you sure you want to verify this user\'s real-name authentication?',
|
||||||
|
confirmsuc:'Successfully approved.',
|
||||||
|
confirmerr:'Operation failed.',
|
||||||
|
rejecttitle:'Confirm rejection',
|
||||||
|
rejectcontent:'Are you sure you want to reject this user\'s real-name authentication?',
|
||||||
|
rejectpla:'Please enter the reason for refusal.',
|
||||||
|
rejectsuc:'successfully rejected',
|
||||||
|
searchtime:'Submission Time',
|
||||||
|
starttime:'Start Time',
|
||||||
|
endtime:'End Time',
|
||||||
|
plestatus:'Please select status.',
|
||||||
|
search:'Search',
|
||||||
|
reset:'Reset',
|
||||||
|
},
|
||||||
|
rule:{
|
||||||
|
title:'Configure Billing Rules',
|
||||||
|
edit:'Edit',
|
||||||
|
traffic:'Traffic',
|
||||||
|
pletraffic:'Please enter flow rate',
|
||||||
|
price:'Price',
|
||||||
|
pleprice:'Please enter price',
|
||||||
|
unit:'Unit',
|
||||||
|
pleunit:'Please select unit',
|
||||||
|
status:'Status',
|
||||||
|
close:'Cancel',
|
||||||
|
confirm:'Confirm',
|
||||||
|
modaltitle:'Edit rule',
|
||||||
|
use:'Enable',
|
||||||
|
unuse:'Not enabled',
|
||||||
|
action:'Action',
|
||||||
|
geterr:'Failed to get the billing rule',
|
||||||
|
updatesuc:'Update successful',
|
||||||
|
updateerr:'Update failed',
|
||||||
|
currencySettings: 'Currency Settings',
|
||||||
|
currencySelect: 'Select Currency',
|
||||||
|
currentCurrency: 'Current Currency',
|
||||||
|
currencyName: 'Currency Name',
|
||||||
|
currencyCode: 'Currency Code',
|
||||||
|
currencySymbol: 'Currency symbol',
|
||||||
|
paymentMethods:'Pay Methods',
|
||||||
|
},
|
||||||
|
ratelimit:{
|
||||||
|
title:'Rate limit management',
|
||||||
|
change:'Modify rate limit configuration',
|
||||||
|
add:'New rate limit configuration.',
|
||||||
|
name:'Limit Name',
|
||||||
|
plename:'Please enter rate limit name.',
|
||||||
|
upratelimit:'Up Rate Limit',
|
||||||
|
useuplimit:'Enable upstream rate limiting.',
|
||||||
|
uplimit:'Upstream bandwidth',
|
||||||
|
pleuplimit:'Please enter upstream bandwidth.',
|
||||||
|
downratelimit:'Down Rate Limit',
|
||||||
|
usedownlimit:'Enable downstream rate limit',
|
||||||
|
downlimit:'Downstream bandwidth',
|
||||||
|
pledownlimit:'Please enter downstream bandwidth.',
|
||||||
|
reject:'Please enter bandwidth value greater than 0.',
|
||||||
|
confirmdelete:'Confirm deletion.',
|
||||||
|
deletecontant:'It is confirmed to delete the rate limit configuration',
|
||||||
|
deletesuc:'Deletion successful.',
|
||||||
|
idnull:'The editor ID cannot be empty.',
|
||||||
|
changesuc:'Modification successful.',
|
||||||
|
addsuc:'Addition successful.',
|
||||||
|
changeerror:'Modification failed.',
|
||||||
|
adderror:'Failed to add.',
|
||||||
|
unlimit:'Unlimited',
|
||||||
|
operate:'Action',
|
||||||
|
changed:'Edit',
|
||||||
|
delete:'Delete',
|
||||||
|
},
|
||||||
|
package: {
|
||||||
|
title: 'Package Management',
|
||||||
|
add: 'Package',
|
||||||
|
packagename: 'Package Name',
|
||||||
|
plepackagename: 'Please enter package name',
|
||||||
|
period: 'Billing Cycle',
|
||||||
|
pleperiod: 'Please enter cycle number',
|
||||||
|
pleunit:'Please enter the billing period unit',
|
||||||
|
price: 'Price',
|
||||||
|
pleprice: 'Please enter price',
|
||||||
|
traffic: 'Traffic Limit',
|
||||||
|
pletraffic: 'Please enter traffic',
|
||||||
|
limit: 'Bandwidth Limit',
|
||||||
|
plelimit: 'Please select bandwidth limit configuration',
|
||||||
|
duration: 'Duration Limit',
|
||||||
|
pleduration: 'Please enter duration',
|
||||||
|
client: 'Device Limit',
|
||||||
|
pleclient: 'Please enter number of devices',
|
||||||
|
unit: 'Units',
|
||||||
|
usepackage: 'Package Status',
|
||||||
|
day: 'Day',
|
||||||
|
month: 'Month',
|
||||||
|
year: 'Year',
|
||||||
|
unlimit: 'Unlimited',
|
||||||
|
up: 'Upload',
|
||||||
|
down: 'Download',
|
||||||
|
status:'Status',
|
||||||
|
use: 'Enable',
|
||||||
|
unuse: 'Disable',
|
||||||
|
operate: 'Action',
|
||||||
|
edit: 'Edit',
|
||||||
|
delete: 'Delete',
|
||||||
|
hour: 'Hour',
|
||||||
|
second:'s',
|
||||||
|
rejtraffic: 'Please enter a traffic value greater than 0 and less than 1025',
|
||||||
|
rejduration: 'Please enter a duration value greater than 0',
|
||||||
|
rejclient: 'Please enter a device number greater than 0',
|
||||||
|
idnull: 'Edit ID cannot be empty',
|
||||||
|
editsuc: 'Modified successfully',
|
||||||
|
addsuc: 'Added successfully',
|
||||||
|
editerr: 'Modification failed',
|
||||||
|
adderr: 'Add failed',
|
||||||
|
confirmdelete: 'Confirm Delete',
|
||||||
|
deletecontent: 'Are you sure to delete this package?',
|
||||||
|
confirm: 'Confirm',
|
||||||
|
close: 'Cancel',
|
||||||
|
deletesuc: 'Deleted successfully',
|
||||||
|
deleteerr: 'Delete failed',
|
||||||
|
},
|
||||||
|
dict:{
|
||||||
|
dictname:'Dictionary Name',
|
||||||
|
dicttype:'Dictionary type',
|
||||||
|
status:'Status',
|
||||||
|
remark:'Remarks',
|
||||||
|
createtime:'Creation time',
|
||||||
|
operate:'Action',
|
||||||
|
deleteask:'Do you confirm the deletion?',
|
||||||
|
title:'Dictionary list',
|
||||||
|
},
|
||||||
|
menu:{
|
||||||
|
menuname:'Name',
|
||||||
|
path:'Path',
|
||||||
|
component:'Component',
|
||||||
|
status:'Status',
|
||||||
|
nomal:'Normal',
|
||||||
|
disable:'Disable',
|
||||||
|
menutype:'Type',
|
||||||
|
table:'Directory',
|
||||||
|
menu:'Menu',
|
||||||
|
button:'Button',
|
||||||
|
ordernum:'Sort',
|
||||||
|
icon:'Icon',
|
||||||
|
createtime:'Create Time',
|
||||||
|
operate:'Action',
|
||||||
|
edit:'Edit',
|
||||||
|
delete:'Delete',
|
||||||
|
modaltitle:'Tips',
|
||||||
|
deleteask:'Are you sure you want to delete the menu?',
|
||||||
|
deletesuc:'Deletion successful.',
|
||||||
|
title:'Menu List',
|
||||||
|
addmenu:'Add Menu',
|
||||||
|
editmenu:'Edit Menu',
|
||||||
|
root:'Root node',
|
||||||
|
parent:'Parent',
|
||||||
|
islink:'Is backlink',
|
||||||
|
yes:'Yes',
|
||||||
|
no:'No',
|
||||||
|
menucomponent:'Path',
|
||||||
|
hidemenu:'Hide Menu',
|
||||||
|
cache:'Cache',
|
||||||
|
perms:'Permission Identifier',
|
||||||
|
confirm:'Determine',
|
||||||
|
close:'Cancel',
|
||||||
|
nozero:'The sort must be greater than or equal to 0'
|
||||||
|
},
|
||||||
|
resetPwd:{
|
||||||
|
title:'Change your password',
|
||||||
|
byEmail:'Change by email',
|
||||||
|
byPassword:'Change by old password',
|
||||||
|
email:'Email',
|
||||||
|
getCode:'Get code',
|
||||||
|
code:'Code',
|
||||||
|
oldPassword:'Old password',
|
||||||
|
newPassword:'New password',
|
||||||
|
confirmPassword:'confirm password',
|
||||||
|
emailPlaceholder:'Please enter the email',
|
||||||
|
codePlaceholder:'Please enter the code',
|
||||||
|
passwordPlaceholder:'Please enter new password',
|
||||||
|
oldPasswordPlaceholder:'Please enter old password',
|
||||||
|
confirmPasswordPlaceholder:'Please enter again',
|
||||||
|
submit:'Confirm',
|
||||||
|
emailRequired:'Email can not be empty',
|
||||||
|
codeSent:'Code enter',
|
||||||
|
success:'Reset Success',
|
||||||
|
},
|
||||||
|
email:{
|
||||||
|
title:'Bind Email',
|
||||||
|
currentEmail:'Current Email',
|
||||||
|
email:'Email',
|
||||||
|
code:'Code',
|
||||||
|
getCode:'Get Code',
|
||||||
|
submit:'Submit',
|
||||||
|
codeSent:'Code Sent',
|
||||||
|
codeRequired:'Code can not be empty',
|
||||||
|
updateSuccess:'Update Success',
|
||||||
|
updateFailed:'Update Failed',
|
||||||
|
emailRequired:'Email can not be empty',
|
||||||
|
emailInvalid:'Email Invalid',
|
||||||
|
codeLength:'Code Invalid',
|
||||||
|
},
|
||||||
|
},
|
||||||
form: {
|
form: {
|
||||||
required: 'Cannot be empty',
|
required: 'Cannot be empty',
|
||||||
username: {
|
username: {
|
||||||
@@ -478,7 +1250,7 @@ const local: any = {
|
|||||||
},
|
},
|
||||||
pwd: {
|
pwd: {
|
||||||
required: 'Please enter password',
|
required: 'Please enter password',
|
||||||
invalid: '6-18 characters, including letters, numbers, and underscores'
|
invalid: 'The password should contain at least uppercase and lowercase letters, numbers, special symbols, and no less than 6 digits'
|
||||||
},
|
},
|
||||||
confirmPwd: {
|
confirmPwd: {
|
||||||
required: 'Please enter password again',
|
required: 'Please enter password again',
|
||||||
@@ -511,7 +1283,8 @@ const local: any = {
|
|||||||
expand: 'Expand Menu',
|
expand: 'Expand Menu',
|
||||||
pin: 'Pin',
|
pin: 'Pin',
|
||||||
unpin: 'Unpin'
|
unpin: 'Unpin'
|
||||||
}
|
},
|
||||||
|
...viewEn
|
||||||
};
|
};
|
||||||
|
|
||||||
export default local;
|
export default local;
|
||||||
+785
-11
@@ -1,3 +1,13 @@
|
|||||||
|
const viewZh: any = {
|
||||||
|
"view.dashboard":"仪表盘",
|
||||||
|
"view.endpoint": "终端设备",
|
||||||
|
"view.endpoint_access": "当前设备",
|
||||||
|
"view.endpoint_records": "历史设备",
|
||||||
|
"view.billing": "账单",
|
||||||
|
"view.billing_histories": "历史查询",
|
||||||
|
"view.set-meal": "套餐",
|
||||||
|
};
|
||||||
|
|
||||||
const local:any = {
|
const local:any = {
|
||||||
system: {
|
system: {
|
||||||
title: 'WANFi 平台',
|
title: 'WANFi 平台',
|
||||||
@@ -14,9 +24,15 @@ const local:any = {
|
|||||||
columnSetting: '列设置',
|
columnSetting: '列设置',
|
||||||
config: '配置',
|
config: '配置',
|
||||||
confirm: '确认',
|
confirm: '确认',
|
||||||
|
submit:'确定',
|
||||||
delete: '删除',
|
delete: '删除',
|
||||||
|
view:'查看',
|
||||||
|
exportOk: "已完成导出",
|
||||||
|
exportTip: "确认根据搜索条件导出xlsx表格文件吗?",
|
||||||
deleteSuccess: '删除成功',
|
deleteSuccess: '删除成功',
|
||||||
confirmDelete: '确认删除吗?',
|
confirmDelete: '确认删除吗?',
|
||||||
|
confirmClean: '确认清空吗?',
|
||||||
|
clearText: "清空",
|
||||||
edit: '编辑',
|
edit: '编辑',
|
||||||
index: '序号',
|
index: '序号',
|
||||||
keywordSearch: '请输入关键词搜索',
|
keywordSearch: '请输入关键词搜索',
|
||||||
@@ -37,11 +53,94 @@ const local:any = {
|
|||||||
update: '更新',
|
update: '更新',
|
||||||
updateSuccess: '更新成功',
|
updateSuccess: '更新成功',
|
||||||
userCenter: '个人中心',
|
userCenter: '个人中心',
|
||||||
|
setemail:'绑定邮箱',
|
||||||
|
resetpwd:'修改密码',
|
||||||
yesOrNo: {
|
yesOrNo: {
|
||||||
yes: '是',
|
yes: '是',
|
||||||
no: '否'
|
no: '否'
|
||||||
|
},
|
||||||
|
ms: '毫秒',
|
||||||
|
normal: '正常',
|
||||||
|
abnormal: '异常',
|
||||||
|
export:'导出',
|
||||||
|
loading: '加载中...',
|
||||||
|
selectPlease: '请选择',
|
||||||
|
disable: '停用',
|
||||||
|
default: '默认',
|
||||||
|
system:'系统',
|
||||||
|
record: '记录',
|
||||||
|
noRecord: '不记录',
|
||||||
|
msgSuccess: '{msg} 成功',
|
||||||
|
errorFields: '请正确填写 {num} 处必填信息!',
|
||||||
|
tipTitle: '提示',
|
||||||
|
units: {
|
||||||
|
second: '秒',
|
||||||
|
minute: '分钟',
|
||||||
|
hour: '小时',
|
||||||
|
day: '天',
|
||||||
|
week: '周',
|
||||||
|
month: '月',
|
||||||
|
year: '年',
|
||||||
|
core: '核',
|
||||||
|
},
|
||||||
|
tablePaginationTotal: '总共 {total} 条',
|
||||||
|
inputPlease: '请输入',
|
||||||
|
time:{
|
||||||
|
second: '秒',
|
||||||
|
minute: '分钟',
|
||||||
|
hour: '小时',
|
||||||
|
day: '天'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// 组件
|
||||||
|
components: {
|
||||||
|
CronModal: {
|
||||||
|
title: "Cron表达式生成",
|
||||||
|
addon: "表达式预览:",
|
||||||
|
day1: "每一天",
|
||||||
|
day21: "每隔",
|
||||||
|
day22: "天执行一次,从",
|
||||||
|
day23: "日开始",
|
||||||
|
day31: "周期从",
|
||||||
|
day32: "到",
|
||||||
|
day33: "日",
|
||||||
|
day4: "指定日(可多选)",
|
||||||
|
day5: "本月最后一天",
|
||||||
|
hour1: "每一小时",
|
||||||
|
hour21: "每隔",
|
||||||
|
hour22: "小时执行一次,从",
|
||||||
|
hour23: "时开始",
|
||||||
|
hour31: "周期从",
|
||||||
|
hour32: "到",
|
||||||
|
hour33: "小时",
|
||||||
|
hour4: "指定小时(可多选)",
|
||||||
|
minute1: "每一分钟",
|
||||||
|
minute21: "每隔",
|
||||||
|
minute22: "分钟执行一次,从",
|
||||||
|
minute23: "分钟开始",
|
||||||
|
minute31: "周期从",
|
||||||
|
minute32: "到",
|
||||||
|
minute33: "分钟",
|
||||||
|
minute4: "指定分钟(可多选)",
|
||||||
|
month1: "每一月",
|
||||||
|
month21: "每隔",
|
||||||
|
month22: "月执行,从",
|
||||||
|
month23: "月开始",
|
||||||
|
month31: "周期从",
|
||||||
|
month32: "到",
|
||||||
|
month33: "月之间的每个月",
|
||||||
|
month4: "指定月(可多选)",
|
||||||
|
second1: "每一秒钟",
|
||||||
|
second21: "每隔",
|
||||||
|
second22: "秒执行一次,从",
|
||||||
|
second23: "秒开始",
|
||||||
|
second31: "周期从",
|
||||||
|
second32: "到",
|
||||||
|
second33: "秒",
|
||||||
|
second4: "指定秒数(可多选)",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
request: {
|
request: {
|
||||||
logout: '请求失败后登出用户',
|
logout: '请求失败后登出用户',
|
||||||
logoutMsg: '用户状态失效,请重新登录',
|
logoutMsg: '用户状态失效,请重新登录',
|
||||||
@@ -137,7 +236,7 @@ const local:any = {
|
|||||||
403: '无权限',
|
403: '无权限',
|
||||||
404: '页面不存在',
|
404: '页面不存在',
|
||||||
500: '服务器错误',
|
500: '服务器错误',
|
||||||
home: '首页',
|
home: '仪表盘',
|
||||||
'user-center': '个人中心',
|
'user-center': '个人中心',
|
||||||
about: '关于',
|
about: '关于',
|
||||||
function: '系统功能',
|
function: '系统功能',
|
||||||
@@ -162,7 +261,9 @@ const local:any = {
|
|||||||
manage_dept: '部门管理',
|
manage_dept: '部门管理',
|
||||||
manage_route: '路由管理',
|
manage_route: '路由管理',
|
||||||
manage_post: '岗位管理',
|
manage_post: '岗位管理',
|
||||||
manage_dict: '字典管理'
|
manage_dict: '字典管理',
|
||||||
|
manage_dictData:'字典数据',
|
||||||
|
manage_task_log: '任务日志',
|
||||||
},
|
},
|
||||||
page: {
|
page: {
|
||||||
login: {
|
login: {
|
||||||
@@ -210,6 +311,8 @@ const local:any = {
|
|||||||
agreeTerms: '我已阅读并同意用户协议和隐私政策',
|
agreeTerms: '我已阅读并同意用户协议和隐私政策',
|
||||||
code:'验证码',
|
code:'验证码',
|
||||||
password:'密码',
|
password:'密码',
|
||||||
|
newPassword:'新密码',
|
||||||
|
oldPassword:'旧密码',
|
||||||
confirmPassword:'再次输入密码',
|
confirmPassword:'再次输入密码',
|
||||||
basicInfo: '基本信息',
|
basicInfo: '基本信息',
|
||||||
terms: '协议条款',
|
terms: '协议条款',
|
||||||
@@ -228,6 +331,18 @@ const local:any = {
|
|||||||
birthDate: '出生日期',
|
birthDate: '出生日期',
|
||||||
birthDatePlaceholder: '请选择出生日期',
|
birthDatePlaceholder: '请选择出生日期',
|
||||||
birthDateRequired: '请选择出生日期',
|
birthDateRequired: '请选择出生日期',
|
||||||
|
genderRequired:'请选择性别',
|
||||||
|
usernameLengthLimit:"用户名太短",
|
||||||
|
usernameExists:"用户名已经注册",
|
||||||
|
usernameRequired:"用户名不能为空",
|
||||||
|
phoneInvalid:"手机号格式不正确",
|
||||||
|
phoneExists:"手机号已经注册",
|
||||||
|
emailInvalid:"邮箱格式不正确",
|
||||||
|
emailExists:"邮箱已经注册",
|
||||||
|
emailRequired:"邮箱不能为空",
|
||||||
|
codeRequired:"验证码不能为空",
|
||||||
|
passwordRequired:"密码不能为空",
|
||||||
|
passwordLength:"密码太短",
|
||||||
},
|
},
|
||||||
resetPwd: {
|
resetPwd: {
|
||||||
title: '重置密码'
|
title: '重置密码'
|
||||||
@@ -239,7 +354,7 @@ const local:any = {
|
|||||||
|
|
||||||
about: {
|
about: {
|
||||||
title: '关于',
|
title: '关于',
|
||||||
introduction: `Soybean Admin 是一个优雅且功能强大的后台管理模板,基于最新的前端技术栈,包括 Vue3, Vite5, TypeScript, Pinia 和 UnoCSS。它内置了丰富的主题配置和组件,代码规范严谨,实现了自动化的文件路由系统。此外,它还采用了基于 ApiFox 的在线Mock数据方案。Soybean Admin 为您提供了一站式的后台管理解决方案,无需额外配置,开箱即用。同样是一个快速学习前沿技术的最佳实践。`,
|
introduction: `WANFI Admin 是一个优雅且功能强大的后台管理模板,基于最新的前端技术栈,包括 Vue3, Vite5, TypeScript, Pinia 和 UnoCSS。它内置了丰富的主题配置和组件,代码规范严谨,实现了自动化的文件路由系统。此外,它还采用了基于 ApiFox 的在线Mock数据方案。WANFI Admin 为您提供了一站式的后台管理解决方案,无需额外配置,开箱即用。同样是一个快速学习前沿技术的最佳实践。`,
|
||||||
projectInfo: {
|
projectInfo: {
|
||||||
title: '项目信息',
|
title: '项目信息',
|
||||||
version: '版本',
|
version: '版本',
|
||||||
@@ -269,11 +384,11 @@ const local:any = {
|
|||||||
projectNews: {
|
projectNews: {
|
||||||
title: '项目动态',
|
title: '项目动态',
|
||||||
moreNews: '更多动态',
|
moreNews: '更多动态',
|
||||||
desc1: 'Soybean 在2021年5月28日创建了开源项目 soybean-admin!',
|
desc1: 'WANFI 在2021年5月28日创建了开源项目 WANFI-admin!',
|
||||||
desc2: 'soybean-admin 提交了一个bug,多标签栏不会自适应。',
|
desc2: 'WANFI-admin 提交了一个bug,多标签栏不会自适应。',
|
||||||
desc3: 'Soybean 准备为 soybean-admin 的发布做充分的准备工作!',
|
desc3: 'WANFI 准备为 WANFI-admin 的发布做充分的准备工作!',
|
||||||
desc4: 'Soybean 正在忙于为soybean-admin写项目说明文档!',
|
desc4: 'WANFI 正在忙于为WANFI-admin写项目说明文档!',
|
||||||
desc5: 'Soybean 刚才把工作台页面随便写了一些,凑合能看了!'
|
desc5: 'WANFI 刚才把工作台页面随便写了一些,凑合能看了!'
|
||||||
},
|
},
|
||||||
creativity: '创意'
|
creativity: '创意'
|
||||||
},
|
},
|
||||||
@@ -348,6 +463,7 @@ const local:any = {
|
|||||||
password: '密码',
|
password: '密码',
|
||||||
role: '角色',
|
role: '角色',
|
||||||
post: '岗位',
|
post: '岗位',
|
||||||
|
createtime:'创建时间',
|
||||||
form: {
|
form: {
|
||||||
userName: '请输入用户名',
|
userName: '请输入用户名',
|
||||||
email: '请输入电子邮件',
|
email: '请输入电子邮件',
|
||||||
@@ -462,10 +578,667 @@ const local:any = {
|
|||||||
remark: '请输入备注'
|
remark: '请输入备注'
|
||||||
},
|
},
|
||||||
addDict: '新增字典',
|
addDict: '新增字典',
|
||||||
editDict: '编辑字典'
|
editDict: '编辑字典',
|
||||||
|
dictDataTitle:'字典数据',
|
||||||
|
dictData:{
|
||||||
|
dictType: "字典名称",
|
||||||
|
dictCode: "数据代码",
|
||||||
|
dictLabel: "数据键名",
|
||||||
|
dictLabelPleac: "请正确输入数据键名",
|
||||||
|
dictValue: "数据键值",
|
||||||
|
dictValuePleac: "请正确输入数据键值",
|
||||||
|
dictSort: "数据排序",
|
||||||
|
status: "数据状态",
|
||||||
|
createTime: "创建时间",
|
||||||
|
tagType: "标签类型",
|
||||||
|
tagTypeShow: "回显预览",
|
||||||
|
tagClass: "样式属性",
|
||||||
|
remark: "数据说明",
|
||||||
|
viewInfo: "字典数据信息",
|
||||||
|
viewInfoErr: "获取字典数据信息失败",
|
||||||
|
addInfo: "添加字典数据",
|
||||||
|
editInfo: "修改字典数据",
|
||||||
|
delTip: "确认删除字典数据代码为 【{txt}】 的数据项?",
|
||||||
|
delOk: "删除成功",
|
||||||
|
exportTip: "确认根据搜索条件导出xlsx表格文件吗?",
|
||||||
|
exportOk: "已完成导出",
|
||||||
|
typeDataErr: "获取字典类型信息失败",
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
log:{
|
||||||
|
logId:'日志编号',
|
||||||
|
module:'模块标题',
|
||||||
|
operType:'业务类型',
|
||||||
|
operName:'操作人员',
|
||||||
|
operIp:'操作地址',
|
||||||
|
operArea:'操作地点',
|
||||||
|
operStatus:'操作状态',
|
||||||
|
operTime:'操作日期',
|
||||||
|
useTime:'消耗时间',
|
||||||
|
backUser:'后台用户',
|
||||||
|
phoneUser:'手机用户',
|
||||||
|
other:'其他',
|
||||||
|
operUrl:'请求URL',
|
||||||
|
operParam:'请求参数',
|
||||||
|
jsonResult:"结果",
|
||||||
|
title:"日志管理",
|
||||||
|
},
|
||||||
|
task:{
|
||||||
|
title:'任务管理',
|
||||||
|
taskId:'编号',
|
||||||
|
taskName:'任务名称',
|
||||||
|
logTitle:'任务日志',
|
||||||
|
group:'任务组名',
|
||||||
|
invoke:'调用目标',
|
||||||
|
cron:'cron表达式',
|
||||||
|
status:'状态',
|
||||||
|
log:'记录日志',
|
||||||
|
createTime:'创建时间',
|
||||||
|
targetParams:'传入参数',
|
||||||
|
remark:'备注',
|
||||||
|
viewJob:'查看任务',
|
||||||
|
addJob:'新增任务',
|
||||||
|
editJob:'编辑任务',
|
||||||
|
viewInfoErr:'查看异常信息',
|
||||||
|
getInfoError:'获取信息失败',
|
||||||
|
jobNamePlease: '请正确输入任务名称,限2-50个字符',
|
||||||
|
invokeTargetPlease: '请正确输入调用目标,限2-50个字符',
|
||||||
|
cronExpressionPlease: '请输入或生成cron执行表达式',
|
||||||
|
jobGroup: "任务组名",
|
||||||
|
saveLog: "记录日志",
|
||||||
|
invokeTargetTip: "参数说明:支持预设传入参数,在处理器中进行序列化处理参数",
|
||||||
|
cronExpressionTip: "表达式示例:0/20 * * * * ?",
|
||||||
|
cronExpressionTip1: "示例说明:每20秒执行任务",
|
||||||
|
cronExpressionNew: "生成表达式",
|
||||||
|
targetParamsPlease: '调用目标传入参数,仅支持json字符串',
|
||||||
|
delTip: "确认删除定时任务编号为 【{num}】 任务吗?",
|
||||||
|
delLogTip: "确认删除日志编号为 【{num}】 任务日志吗?",
|
||||||
|
runOneTip: "确定要立即执行一次 【{num}】 任务吗?",
|
||||||
|
runOneOk: "{num} 执行成功",
|
||||||
|
runOne:'执行一次',
|
||||||
|
jobLog: "任务日志",
|
||||||
|
jobMessage: "执行信息",
|
||||||
|
clearTip: "确认清空所有调度日志数据项吗?",
|
||||||
|
clearOk: "清空成功",
|
||||||
|
statusChange: "确定要{text} {num} 任务吗?",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
carddata:{
|
||||||
|
sitelist:'站点列表',
|
||||||
|
sitename:'站点名称',
|
||||||
|
country:'国家/地区',
|
||||||
|
alert:'警告',
|
||||||
|
gateway:'网关',
|
||||||
|
switches:'交换机',
|
||||||
|
clients:'终端',
|
||||||
|
search:'输入站点名称',
|
||||||
|
total:'共',
|
||||||
|
addsite:'添加站点',
|
||||||
|
region:'国家/地区',
|
||||||
|
timezone:'时区',
|
||||||
|
scenario:'场景',
|
||||||
|
username:'用户名',
|
||||||
|
password:'密码',
|
||||||
|
deleteConfirmTitle:'确定要删除吗',
|
||||||
|
deleteConfirmContent:'确定要删除站点{name}吗?',
|
||||||
|
confirm:'确定',
|
||||||
|
cancel:'取消',
|
||||||
|
deleteSuccess:'删除成功',
|
||||||
|
editsite:'修改配置',
|
||||||
|
office:'办公室',
|
||||||
|
hotel:'医院',
|
||||||
|
education:'教育',
|
||||||
|
retail:'零售业',
|
||||||
|
other:'其他',
|
||||||
|
updateSuccess:'更新成功',
|
||||||
|
wireless:'无线功能',
|
||||||
|
autoFailover:'自动恢复',
|
||||||
|
conDetection:'连接检测',
|
||||||
|
autoRec:'自动(建议选项)',
|
||||||
|
custom:'自定义',
|
||||||
|
fastRoaming:'快速漫游',
|
||||||
|
aiRoaming:'AI漫游',
|
||||||
|
passwordInvalid:'密码格式不正确,请包含大小写字母和符号',
|
||||||
|
addSuccess:'添加成功',
|
||||||
|
meshtext:'如果 Wireless Device 的 IP 地址与自定义 IP 地址位于不同的网段,则 Wireless Device 将使用默认网关 IP 地址进行检测'
|
||||||
|
},
|
||||||
|
headerbanner:{
|
||||||
|
controller:'控制仪表盘',
|
||||||
|
connected:'连接',
|
||||||
|
cloud:'云访问',
|
||||||
|
sites:'站点',
|
||||||
|
totalsite:'站点数',
|
||||||
|
gateway:'网关',
|
||||||
|
switches:'交换机',
|
||||||
|
register:'注册用户',
|
||||||
|
online:'在线用户',
|
||||||
|
client:'装置',
|
||||||
|
alerts:'警告',
|
||||||
|
connect:'连接数',
|
||||||
|
disconnect:'断连数',
|
||||||
|
registuser:'注册用户数',
|
||||||
|
onlineuser:'在线用户数',
|
||||||
|
isolated:'隔离',
|
||||||
|
wired:'有线客户端',
|
||||||
|
wireless:'无线客户端',
|
||||||
|
guest:'无线访客',
|
||||||
|
alert:'警报数',
|
||||||
|
},
|
||||||
|
bill:{
|
||||||
|
username:'用户名',
|
||||||
|
billtime:'订单时间',
|
||||||
|
billtype:'订单类型',
|
||||||
|
packagebill:'套餐订单',
|
||||||
|
rechargebill:'充值订单',
|
||||||
|
packagename:'套餐名称',
|
||||||
|
amount:'金额',
|
||||||
|
status:'状态',
|
||||||
|
wait:'待支付',
|
||||||
|
done:'已支付',
|
||||||
|
close:'已取消',
|
||||||
|
billinfo:'账单信息',
|
||||||
|
total:'共',
|
||||||
|
pleusername:'请输入用户名',
|
||||||
|
plebilltype:'请选择订单类型',
|
||||||
|
plestatus:'请选择订单状态',
|
||||||
|
reset:'重置',
|
||||||
|
search:'查询',
|
||||||
|
},
|
||||||
|
apdevice:{
|
||||||
|
aptitle:'AP设备管理',
|
||||||
|
online:'在线',
|
||||||
|
outline:'离线',
|
||||||
|
pending:'待定',
|
||||||
|
apname:'设备名称',
|
||||||
|
ip:'IP地址',
|
||||||
|
mac:'MAC地址',
|
||||||
|
model:'型号',
|
||||||
|
uptime:'在线时间',
|
||||||
|
status:'状态',
|
||||||
|
total:'共',
|
||||||
|
pledevice:'请输入设备名称',
|
||||||
|
plemac:'请输入MAC地址',
|
||||||
|
search:'搜索',
|
||||||
|
reset:'重置',
|
||||||
|
editConfig:'修改配置',
|
||||||
|
forget:'移除设备',
|
||||||
|
restart:'重启设备',
|
||||||
|
confirmReboot:'确定重启',
|
||||||
|
confirmForget:'确定移除',
|
||||||
|
forgetConfirmContent:'确定要移除设备{ name }吗',
|
||||||
|
rebootConfirmContent:'确定要重启设备{ name }吗',
|
||||||
|
rebootSuccess:'重启发送成功',
|
||||||
|
adopt:'纳管设备',
|
||||||
|
addDevice:'增加设备',
|
||||||
|
sn:'产品序号',
|
||||||
|
name:'设备名称',
|
||||||
|
username:'设备用户名',
|
||||||
|
password:'设备密码',
|
||||||
|
snFormatError:'A-Z 或 0-9 的 13 位字符',
|
||||||
|
nameFormatError:'不能以空格、+、-、{test}、=字符开头,不能以空格结尾,长度在 1-128 之间',
|
||||||
|
forgetConfirm:'确认要移除设备吗?',
|
||||||
|
restartConfirm:'确认要重启设备吗?',
|
||||||
|
led:'LED',
|
||||||
|
useSiteSettings:'使用站点设置',
|
||||||
|
on:'打开',
|
||||||
|
off:'关闭',
|
||||||
|
longitude:'经度(可选)',
|
||||||
|
latitude:'纬度(可选)',
|
||||||
|
address:'地址(可选)',
|
||||||
|
plesearch:'搜索设备名字,站点名字,IP,型号',
|
||||||
|
selectSite:'无站点',
|
||||||
|
adoptSuccess:'纳管成功',
|
||||||
|
adoptError:'纳管失败',
|
||||||
|
forgetSuccess:'移除设备成功',
|
||||||
|
forgetError:'移除设备失败',
|
||||||
|
getConfigError:'获取配置失败',
|
||||||
|
snRequired:'产品序号',
|
||||||
|
addSuccess:'添加成功',
|
||||||
|
addError:'添加失败',
|
||||||
|
longitudeError:'经度错误',
|
||||||
|
latitudeError:'纬度错误',
|
||||||
|
configSuccess:'配置成功',
|
||||||
|
configError:'配置失败',
|
||||||
|
|
||||||
|
},
|
||||||
|
wlan:{
|
||||||
|
title:'无线网络',
|
||||||
|
selectSite:'无站点',
|
||||||
|
selectGroup:'无网络组',
|
||||||
|
total:'共',
|
||||||
|
name:'SSID名称',
|
||||||
|
none:'无',
|
||||||
|
passwordPlaceholder:'请输入8~63位的密码',
|
||||||
|
passwordRequired:'密码不能为空',
|
||||||
|
passwordLength:'密码请输入长度8~63位字符或数字',
|
||||||
|
security: {
|
||||||
|
security:'安全性',
|
||||||
|
wpaEnterprise: 'WPA-Enterprise',
|
||||||
|
wpaPersonal: 'WPA-Personal',
|
||||||
|
ppskWithoutRadius: 'PPSK without RADIUS',
|
||||||
|
ppskWithRadius: 'PPSK with RADIUS',
|
||||||
|
},
|
||||||
|
password:'密码',
|
||||||
|
portalEnable:'门户',
|
||||||
|
portalName:'门户名称',
|
||||||
|
band:'频段',
|
||||||
|
bandtip:'2.4GHz、5GHz、6GHz每种Band类型只能存在8个ssid',
|
||||||
|
guestNetwork:'访客网络',
|
||||||
|
enable:'开启',
|
||||||
|
disable:'关闭',
|
||||||
|
deviceType:'设备类型',
|
||||||
|
broadcast:'广播',
|
||||||
|
vlan:'VLAN',
|
||||||
|
addSsid:'SSID配置',
|
||||||
|
open:'开启',
|
||||||
|
vlanId:'VLAN ID',
|
||||||
|
default:'默认',
|
||||||
|
custom:'定制',
|
||||||
|
nameRequired:'名称不能为空',
|
||||||
|
nameLength:'名称长度1~32字符',
|
||||||
|
vlanIdRequired:'VLAN ID不能为空',
|
||||||
|
addSuccess:'添加成功',
|
||||||
|
confirmDelete:'删除设备',
|
||||||
|
deleteConfirmContent:'确认要删除设备吗',
|
||||||
|
deleteSuccess:'删除成功',
|
||||||
|
editSsid:'修改配置',
|
||||||
|
updateSuccess:'修改成功',
|
||||||
|
},
|
||||||
|
portal: {
|
||||||
|
title: '门户管理',
|
||||||
|
name: '名称',
|
||||||
|
selectSite:'无站点',
|
||||||
|
authType: '身份验证类型',
|
||||||
|
auth: {
|
||||||
|
none: '无认证',
|
||||||
|
simplePassword: '简单密码',
|
||||||
|
externalRadius: '外部 Radius 服务器',
|
||||||
|
externalPortal: '外部 Portal 服务器',
|
||||||
|
hotspot: '热点',
|
||||||
|
ldap: 'LDAP 格式'
|
||||||
|
},
|
||||||
|
addPortal: '添加门户',
|
||||||
|
enable: '启用',
|
||||||
|
ssid: 'SSID',
|
||||||
|
selectSsid: '请选择SSID',
|
||||||
|
authTimeout: '身份验证时间',
|
||||||
|
dailyLimit: '每日限额',
|
||||||
|
enableDailyLimit: '启用每日限额',
|
||||||
|
httpsRedirect: 'HTTPS 重定向',
|
||||||
|
enableHttpsRedirect: '启用 HTTPS 重定向',
|
||||||
|
landingPage: '登录页面',
|
||||||
|
landingUrl: '促销 URL',
|
||||||
|
enterUrl: '请输入 URL',
|
||||||
|
nameRequired: '请输入门户名称',
|
||||||
|
ssidRequired: '请选择 SSID',
|
||||||
|
urlRequired: '请输入 URL',
|
||||||
|
addSuccess: '添加成功',
|
||||||
|
addError: '添加失败',
|
||||||
|
total:'共',
|
||||||
|
updateSuccess:'更新成功',
|
||||||
|
editPortal:'修改配置',
|
||||||
|
timeUnit: {
|
||||||
|
min: '分钟',
|
||||||
|
hour: '小时',
|
||||||
|
day: '天'
|
||||||
|
},
|
||||||
|
landing: {
|
||||||
|
originalUrl: '重定向到原始 URL',
|
||||||
|
promotionUrl: '重定向到促销 URL',
|
||||||
|
logoutPage: '重定向到注销页面'
|
||||||
|
},
|
||||||
|
externalPortal: '自定义 Portal 服务器',
|
||||||
|
ipAddress: 'IP地址',
|
||||||
|
url: 'URL',
|
||||||
|
ipRequired: '请输入IP地址',
|
||||||
|
invalidUrl: 'URL 格式不正确',
|
||||||
|
confirmDelete: '确认删除',
|
||||||
|
deleteConfirmContent: '确定要删除门户 {name} 吗?',
|
||||||
|
deleteSuccess: '删除成功'
|
||||||
|
},
|
||||||
|
alerts:{
|
||||||
|
alerts:'警报',
|
||||||
|
chosesite:'请选择站点',
|
||||||
|
deletesuccess:'删除成功',
|
||||||
|
deletefail:'删除失败',
|
||||||
|
choserecord:'请选择需要操作的记录',
|
||||||
|
deletetitle:'确认删除',
|
||||||
|
deletebody:'条记录吗?',
|
||||||
|
suredelete:'确定要删除该条警报记录吗?',
|
||||||
|
sure:'确定',
|
||||||
|
cancel:'取消',
|
||||||
|
unresolved:'未解决',
|
||||||
|
resolved:'已解决',
|
||||||
|
all:'全部',
|
||||||
|
system:'系统',
|
||||||
|
device:'设备',
|
||||||
|
batchdelete:'批量删除',
|
||||||
|
resovetitle:'标记为已解决',
|
||||||
|
delete:'删除',
|
||||||
|
type:'类型',
|
||||||
|
level:'等级',
|
||||||
|
content:'说明',
|
||||||
|
time:'时间',
|
||||||
|
action:'操作',
|
||||||
|
},
|
||||||
|
access:{
|
||||||
|
title:'白名单控制',
|
||||||
|
plesite:'请选择站点',
|
||||||
|
authaccess:'预认证访问',
|
||||||
|
enable:'开启',
|
||||||
|
authaccesslist:'预认证访问列表',
|
||||||
|
delete:'删除',
|
||||||
|
authclient:'免认证客户端',
|
||||||
|
authclientlist:'免认证客户端列表',
|
||||||
|
apply:'提交',
|
||||||
|
cancel:'取消',
|
||||||
|
type:'类型',
|
||||||
|
pleurl:'请输入URL',
|
||||||
|
addauth:'添加预认证访问',
|
||||||
|
addclient:'添加免认证客户端',
|
||||||
|
add:'添加',
|
||||||
|
info:'信息',
|
||||||
|
action:'操作',
|
||||||
|
deletetitle:'确认删除',
|
||||||
|
deletebody:'确定要删除这条记录吗?',
|
||||||
|
ok:'确认',
|
||||||
|
plenumber:'请输入有效数字',
|
||||||
|
subnetMask:'子网掩码必须在0-32之间',
|
||||||
|
iperror:'ip地址格式不正确',
|
||||||
|
applysuccess:'提交成功',
|
||||||
|
|
||||||
|
},
|
||||||
|
terminal:{
|
||||||
|
title:'终端设备',
|
||||||
|
total:'共',
|
||||||
|
unknow:'未知',
|
||||||
|
day:'天',
|
||||||
|
hour:'小时',
|
||||||
|
min:'分钟',
|
||||||
|
second:'秒',
|
||||||
|
name:'设备名称',
|
||||||
|
ip:'IP地址',
|
||||||
|
status:'状态',
|
||||||
|
ssid:'网络',
|
||||||
|
apname:'所属AP设备',
|
||||||
|
activity:'下载速率',
|
||||||
|
down:'下载量',
|
||||||
|
up:'上传量',
|
||||||
|
uptime:'在线时长',
|
||||||
|
pledevice:'请输入设备名称',
|
||||||
|
model:'设备类型',
|
||||||
|
plemodel:'请输入设备类型',
|
||||||
|
mac:'MAC地址',
|
||||||
|
plemac:'请输入MAC地址',
|
||||||
|
search:'搜索',
|
||||||
|
reset:'重置',
|
||||||
|
pending:'未授权',
|
||||||
|
authorized:'已授权',
|
||||||
|
authfree:'免认证',
|
||||||
|
},
|
||||||
|
user:{
|
||||||
|
title:'用户信息',
|
||||||
|
username:'用户名',
|
||||||
|
fullname:'姓名',
|
||||||
|
sex:'性别',
|
||||||
|
man:'男',
|
||||||
|
woman:'女',
|
||||||
|
birthdate:'出生日期',
|
||||||
|
age:'年龄',
|
||||||
|
email:'邮箱',
|
||||||
|
phone:'手机号',
|
||||||
|
kyc:'KYC验证',
|
||||||
|
ver:'已验证',
|
||||||
|
unver:'未验证',
|
||||||
|
pending:'待审核',
|
||||||
|
rejected:'未批准',
|
||||||
|
pleusername:'请输入用户名',
|
||||||
|
pleemail:'请输入邮箱',
|
||||||
|
search:'搜索',
|
||||||
|
reset:'重置',
|
||||||
|
},
|
||||||
|
cdr:{
|
||||||
|
hour:'时',
|
||||||
|
min:'分',
|
||||||
|
sec:'秒',
|
||||||
|
username:'用户名',
|
||||||
|
clientname:'设备名',
|
||||||
|
clientmac:'设备MAC地址',
|
||||||
|
up:'上行流量',
|
||||||
|
down:'下行流量',
|
||||||
|
start:'开始时间',
|
||||||
|
end:'结束时间',
|
||||||
|
duration:'时长',
|
||||||
|
title:'话单记录',
|
||||||
|
total:'共',
|
||||||
|
pleusername:'请输入用户名',
|
||||||
|
pleclientname:'请输入设备名',
|
||||||
|
search:'搜索',
|
||||||
|
reset:'重置',
|
||||||
|
timerange:'结束时间范围',
|
||||||
|
startTime:'开始时间',
|
||||||
|
endTime:'结束时间'
|
||||||
|
},
|
||||||
|
kyc:{
|
||||||
|
title:'KYC实名认证审核',
|
||||||
|
total:'共',
|
||||||
|
pass:'通过',
|
||||||
|
refuse:'拒绝',
|
||||||
|
verified:'已认证',
|
||||||
|
unverified:'未认证',
|
||||||
|
pending:'待审核',
|
||||||
|
approved:'已通过',
|
||||||
|
rejected:'已拒绝',
|
||||||
|
unknow:'未知',
|
||||||
|
username:'用户名',
|
||||||
|
realname:'姓名',
|
||||||
|
type:'证件类型',
|
||||||
|
file:'证件照片',
|
||||||
|
picture:'面部照片',
|
||||||
|
status:'状态',
|
||||||
|
createtime:'提交时间',
|
||||||
|
operate:'操作',
|
||||||
|
confirmtitle:'确认通过',
|
||||||
|
confirmcontent:'确定要通过该用户的实名认证吗?',
|
||||||
|
confirmsuc:'审核通过成功',
|
||||||
|
confirmerr:'操作失败',
|
||||||
|
rejecttitle:'确认拒绝',
|
||||||
|
rejectcontent:'确定要拒绝该用户的实名认证吗?',
|
||||||
|
rejectpla:'请输入拒绝原因',
|
||||||
|
rejectsuc:'审核拒绝成功',
|
||||||
|
searchtime:'提交时间',
|
||||||
|
starttime:'开始时间',
|
||||||
|
endtime:'结束时间',
|
||||||
|
plestatus:'请选择状态',
|
||||||
|
search:'查询',
|
||||||
|
reset:'重置',
|
||||||
|
},
|
||||||
|
rule:{
|
||||||
|
title:'计费规则配置',
|
||||||
|
edit:'编辑',
|
||||||
|
traffic:'流量',
|
||||||
|
pletraffic:'请输入流量大小',
|
||||||
|
price:'价格',
|
||||||
|
pleprice:'请输入价格',
|
||||||
|
unit:'单位',
|
||||||
|
pleunit:'请选择单位',
|
||||||
|
status:'状态',
|
||||||
|
close:'取消',
|
||||||
|
confirm:'确定',
|
||||||
|
modaltitle:'编辑规则',
|
||||||
|
use:'启用',
|
||||||
|
unuse:'未启用',
|
||||||
|
action:'操作',
|
||||||
|
geterr:'获取计费规则失败',
|
||||||
|
updatesuc:'更新成功',
|
||||||
|
updateerr:'更新失败',
|
||||||
|
currencySettings: '货币设置',
|
||||||
|
currencySelect: '选择货币',
|
||||||
|
currentCurrency: '当前货币',
|
||||||
|
currencyName: '货币名称',
|
||||||
|
currencyCode: '货币代码',
|
||||||
|
currencySymbol: '货币符号',
|
||||||
|
paymentMethods:'支付方式',
|
||||||
|
},
|
||||||
|
ratelimit:{
|
||||||
|
title:'限速管理',
|
||||||
|
change:'修改限速配置',
|
||||||
|
add:'新增限速配置',
|
||||||
|
name:'限速名称',
|
||||||
|
plename:'请输入限速名称',
|
||||||
|
upratelimit:'上行限速',
|
||||||
|
useuplimit:'启用上行限速',
|
||||||
|
uplimit:'上行带宽',
|
||||||
|
pleuplimit:'请输入上行带宽',
|
||||||
|
downratelimit:'下行限速',
|
||||||
|
usedownlimit:'启用下行限速',
|
||||||
|
downlimit:'下行带宽',
|
||||||
|
pledownlimit:'请输入下行带宽',
|
||||||
|
reject:'请输入大于0的带宽值',
|
||||||
|
confirmdelete:'确认删除',
|
||||||
|
deletecontant:'确定要删除限速配置',
|
||||||
|
deletesuc:'删除成功',
|
||||||
|
idnull:'编辑ID不能为空',
|
||||||
|
changesuc:'修改成功',
|
||||||
|
addsuc:'添加成功',
|
||||||
|
changeerror:'修改失败',
|
||||||
|
adderror:'添加失败',
|
||||||
|
unlimit:'无限制',
|
||||||
|
operate:'操作',
|
||||||
|
changed:'编辑',
|
||||||
|
delete:'删除',
|
||||||
|
},
|
||||||
|
package:{
|
||||||
|
title:'套餐管理',
|
||||||
|
add:'新增套餐',
|
||||||
|
packagename:'套餐名称',
|
||||||
|
plepackagename:'请输入套餐名称',
|
||||||
|
period:'计费周期',
|
||||||
|
pleperiod:'请输入周期数',
|
||||||
|
pleunit:'请输入计费周期单位',
|
||||||
|
price:'价格',
|
||||||
|
pleprice:'请输入价格',
|
||||||
|
traffic:'流量限制',
|
||||||
|
pletraffic:'请输入流量',
|
||||||
|
limit:'带宽限制',
|
||||||
|
plelimit:'请选择带宽限速配置',
|
||||||
|
duration:'时长限制',
|
||||||
|
pleduration:'请输入时长',
|
||||||
|
client:'设备数限制',
|
||||||
|
pleclient:'请输入设备数',
|
||||||
|
unit:'台',
|
||||||
|
usepackage:'套餐启用',
|
||||||
|
day:'天',
|
||||||
|
month:'月',
|
||||||
|
year:'年',
|
||||||
|
unlimit:'无限制',
|
||||||
|
up:'上行',
|
||||||
|
down:'下行',
|
||||||
|
status:'套餐状态',
|
||||||
|
use:'启用',
|
||||||
|
unuse:'禁用',
|
||||||
|
operate:'操作',
|
||||||
|
edit:'编辑',
|
||||||
|
delete:'删除',
|
||||||
|
hour:'小时',
|
||||||
|
second:'秒',
|
||||||
|
rejtraffic:'请输入大于0小于1025的流量值',
|
||||||
|
rejduration:'请输入大于0的时长值',
|
||||||
|
rejclient:'请输入大于0的设备数',
|
||||||
|
idnull:'编辑ID不能为空',
|
||||||
|
editsuc:'修改成功',
|
||||||
|
addsuc:'添加成功',
|
||||||
|
editerr:'修改失败',
|
||||||
|
adderr:'添加失败',
|
||||||
|
confirmdelete:'确认删除',
|
||||||
|
deletecontent:'是否确认删除该套餐?',
|
||||||
|
confirm:'确认',
|
||||||
|
close:'取消',
|
||||||
|
deletesuc:'删除成功',
|
||||||
|
deleteerr:'删除失败',
|
||||||
|
},
|
||||||
|
dict:{
|
||||||
|
dictname:'字典名称',
|
||||||
|
dicttype:'字典类型',
|
||||||
|
status:'状态',
|
||||||
|
remark:'备注',
|
||||||
|
createtime:'创建时间',
|
||||||
|
operate:'操作',
|
||||||
|
deleteask:'确认删除吗?',
|
||||||
|
title:'字典列表',
|
||||||
|
},
|
||||||
|
menu:{
|
||||||
|
menuname:'菜单名称',
|
||||||
|
path:'路由地址',
|
||||||
|
component:'组件路径',
|
||||||
|
status:'状态',
|
||||||
|
nomal:'正常',
|
||||||
|
disable:'停用',
|
||||||
|
menutype:'类型',
|
||||||
|
table:'目录',
|
||||||
|
menu:'菜单',
|
||||||
|
button:'按钮',
|
||||||
|
ordernum:'排序',
|
||||||
|
icon:'图标',
|
||||||
|
createtime:'创建时间',
|
||||||
|
operate:'操作',
|
||||||
|
edit:'编辑',
|
||||||
|
delete:'删除',
|
||||||
|
modaltitle:'提示',
|
||||||
|
deleteask:'确定删除该菜单吗',
|
||||||
|
deletesuc:'删除成功',
|
||||||
|
title:'菜单列表',
|
||||||
|
addmenu:'新增菜单',
|
||||||
|
editmenu:'编辑菜单',
|
||||||
|
root:'根节点',
|
||||||
|
parent:'上级菜单',
|
||||||
|
islink:'是否外链',
|
||||||
|
yes:'是',
|
||||||
|
no:'否',
|
||||||
|
menucomponent:'菜单路径',
|
||||||
|
hidemenu:'隐藏菜单',
|
||||||
|
cache:'缓存',
|
||||||
|
perms:'权限标识',
|
||||||
|
confirm:'确定',
|
||||||
|
close:'取消',
|
||||||
|
nozero:'排序必须大于等于0'
|
||||||
|
},
|
||||||
|
resetPwd:{
|
||||||
|
title:'修改密码',
|
||||||
|
byEmail:'通过邮箱修改密码',
|
||||||
|
byPassword:'通过原密码修改密码',
|
||||||
|
email:'邮箱',
|
||||||
|
getCode:'获取验证码',
|
||||||
|
code:'验证码',
|
||||||
|
oldPassword:'原密码',
|
||||||
|
newPassword:'新密码',
|
||||||
|
confirmPassword:'确认密码',
|
||||||
|
emailPlaceholder:'请输入邮箱',
|
||||||
|
codePlaceholder:'请输入验证码',
|
||||||
|
passwordPlaceholder:'请输入新密码',
|
||||||
|
oldPasswordPlaceholder:'请输入旧密码',
|
||||||
|
confirmPasswordPlaceholder:'请再次输入新密码',
|
||||||
|
submit:'确认',
|
||||||
|
emailRequired:'邮箱不能为空',
|
||||||
|
codeSent:'验证码发送',
|
||||||
|
success:'修改成功',
|
||||||
|
},
|
||||||
|
email:{
|
||||||
|
title:'绑定邮箱',
|
||||||
|
currentEmail:'当前邮箱',
|
||||||
|
email:'新邮箱',
|
||||||
|
code:'验证码',
|
||||||
|
getCode:'获取验证码',
|
||||||
|
submit:'确定',
|
||||||
|
codeSent:'验证码发送',
|
||||||
|
codeRequired:'验证码不能为空',
|
||||||
|
updateSuccess:'修改成功',
|
||||||
|
updateFailed:'修改失败',
|
||||||
|
emailRequired:'邮箱不能为空',
|
||||||
|
emailInvalid:'邮箱格式错误',
|
||||||
|
codeLength:'验证码长度错误',
|
||||||
|
},
|
||||||
|
},
|
||||||
form: {
|
form: {
|
||||||
required: '不能为空',
|
required: '不能为空',
|
||||||
username: {
|
username: {
|
||||||
@@ -478,7 +1251,7 @@ const local:any = {
|
|||||||
},
|
},
|
||||||
pwd: {
|
pwd: {
|
||||||
required: '请输入密码',
|
required: '请输入密码',
|
||||||
invalid: '密码格式不正确,6-18位字符,包含字母、数字、下划线'
|
invalid: '密码至少包含大小写字母、数字、特殊符号,且不少于6位'
|
||||||
},
|
},
|
||||||
confirmPwd: {
|
confirmPwd: {
|
||||||
required: '请输入确认密码',
|
required: '请输入确认密码',
|
||||||
@@ -511,7 +1284,8 @@ const local:any = {
|
|||||||
expand: '展开菜单',
|
expand: '展开菜单',
|
||||||
pin: '固定',
|
pin: '固定',
|
||||||
unpin: '取消固定'
|
unpin: '取消固定'
|
||||||
}
|
},
|
||||||
|
...viewZh
|
||||||
};
|
};
|
||||||
|
|
||||||
export default local;
|
export default local;
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
import zhCN from './langs/zh-cn';
|
import localeZhCN from './langs/zh-cn';
|
||||||
import enUS from './langs/en-us';
|
import localeEnUS from './langs/en-us';
|
||||||
|
|
||||||
|
const fullZhCN = { ...localeZhCN, ...zhCN };
|
||||||
|
const fullEnUS = { ...localeEnUS, ...enUS };
|
||||||
|
|
||||||
const locales: Record<App.I18n.LangType, App.I18n.Schema> = {
|
const locales: Record<App.I18n.LangType, App.I18n.Schema> = {
|
||||||
'zh-CN': zhCN,
|
'zh-CN': fullZhCN,
|
||||||
'en-US': enUS
|
'en-US': fullEnUS
|
||||||
};
|
};
|
||||||
|
|
||||||
export default locales;
|
export default locales;
|
||||||
+259
-140
@@ -5,6 +5,11 @@
|
|||||||
|
|
||||||
import type { GeneratedRoute } from '@elegant-router/types';
|
import type { GeneratedRoute } from '@elegant-router/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* custom routes
|
||||||
|
*
|
||||||
|
* @link https://github.com/soybeanjs/elegant-router?tab=readme-ov-file#custom-route
|
||||||
|
*/
|
||||||
export const generatedRoutes: GeneratedRoute[] = [
|
export const generatedRoutes: GeneratedRoute[] = [
|
||||||
{
|
{
|
||||||
name: '403',
|
name: '403',
|
||||||
@@ -40,143 +45,14 @@ export const generatedRoutes: GeneratedRoute[] = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'about',
|
name: 'dashboard',
|
||||||
path: '/about',
|
path: '/dashboard',
|
||||||
component: 'layout.base$view.about',
|
component: 'layout.base$view.dashboard',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'about',
|
title: 'dashboard',
|
||||||
i18nKey: 'route.about',
|
|
||||||
icon: 'fluent:book-information-24-regular',
|
|
||||||
order: 10
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function',
|
|
||||||
path: '/function',
|
|
||||||
component: 'layout.base',
|
|
||||||
meta: {
|
|
||||||
title: 'function',
|
|
||||||
i18nKey: 'route.function',
|
|
||||||
icon: 'icon-park-outline:all-application',
|
|
||||||
order: 6
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'function_hide-child',
|
|
||||||
path: '/function/hide-child',
|
|
||||||
meta: {
|
|
||||||
title: 'function_hide-child',
|
|
||||||
i18nKey: 'route.function_hide-child',
|
|
||||||
icon: 'material-symbols:filter-list-off',
|
|
||||||
order: 2
|
|
||||||
},
|
|
||||||
redirect: '/function/hide-child/one',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'function_hide-child_one',
|
|
||||||
path: '/function/hide-child/one',
|
|
||||||
component: 'view.function_hide-child_one',
|
|
||||||
meta: {
|
|
||||||
title: 'function_hide-child_one',
|
|
||||||
i18nKey: 'route.function_hide-child_one',
|
|
||||||
icon: 'material-symbols:filter-list-off',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: 'function_hide-child'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_hide-child_three',
|
|
||||||
path: '/function/hide-child/three',
|
|
||||||
component: 'view.function_hide-child_three',
|
|
||||||
meta: {
|
|
||||||
title: 'function_hide-child_three',
|
|
||||||
i18nKey: 'route.function_hide-child_three',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: 'function_hide-child'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_hide-child_two',
|
|
||||||
path: '/function/hide-child/two',
|
|
||||||
component: 'view.function_hide-child_two',
|
|
||||||
meta: {
|
|
||||||
title: 'function_hide-child_two',
|
|
||||||
i18nKey: 'route.function_hide-child_two',
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: 'function_hide-child'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_multi-tab',
|
|
||||||
path: '/function/multi-tab',
|
|
||||||
component: 'view.function_multi-tab',
|
|
||||||
meta: {
|
|
||||||
title: 'function_multi-tab',
|
|
||||||
i18nKey: 'route.function_multi-tab',
|
|
||||||
icon: 'ic:round-tab',
|
|
||||||
multiTab: true,
|
|
||||||
hideInMenu: true,
|
|
||||||
activeMenu: 'function_tab'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_request',
|
|
||||||
path: '/function/request',
|
|
||||||
component: 'view.function_request',
|
|
||||||
meta: {
|
|
||||||
title: 'function_request',
|
|
||||||
i18nKey: 'route.function_request',
|
|
||||||
icon: 'carbon:network-overlay',
|
|
||||||
order: 3
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_super-page',
|
|
||||||
path: '/function/super-page',
|
|
||||||
component: 'view.function_super-page',
|
|
||||||
meta: {
|
|
||||||
title: 'function_super-page',
|
|
||||||
i18nKey: 'route.function_super-page',
|
|
||||||
icon: 'ic:round-supervisor-account',
|
|
||||||
order: 5,
|
|
||||||
roles: ['R_SUPER']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_tab',
|
|
||||||
path: '/function/tab',
|
|
||||||
component: 'view.function_tab',
|
|
||||||
meta: {
|
|
||||||
title: 'function_tab',
|
|
||||||
i18nKey: 'route.function_tab',
|
|
||||||
icon: 'ic:round-tab',
|
|
||||||
order: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'function_toggle-auth',
|
|
||||||
path: '/function/toggle-auth',
|
|
||||||
component: 'view.function_toggle-auth',
|
|
||||||
meta: {
|
|
||||||
title: 'function_toggle-auth',
|
|
||||||
i18nKey: 'route.function_toggle-auth',
|
|
||||||
icon: 'ic:round-construction',
|
|
||||||
order: 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'home',
|
|
||||||
path: '/home',
|
|
||||||
component: 'layout.base$view.home',
|
|
||||||
meta: {
|
|
||||||
title: 'home',
|
|
||||||
i18nKey: 'route.home',
|
i18nKey: 'route.home',
|
||||||
icon: 'mdi:monitor-dashboard',
|
icon: 'mdi:monitor-dashboard',
|
||||||
order: 1
|
order: 0,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -192,15 +68,258 @@ export const generatedRoutes: GeneratedRoute[] = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'user-center',
|
name: 'static',
|
||||||
path: '/user-center',
|
path: '/static',
|
||||||
component: 'layout.base$view.user-center',
|
component: 'layout.base',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'user-center',
|
title: 'static',
|
||||||
hideInMenu: true,
|
hideInMenu: true,
|
||||||
constant: true,
|
|
||||||
keepAlive: false,
|
|
||||||
i18nKey: 'route.user-center'
|
i18nKey: 'route.user-center'
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: 'static_resetpwd',
|
||||||
|
path: '/static/resetpwd',
|
||||||
|
component: 'view.static_resetpwd',
|
||||||
|
meta: {
|
||||||
|
title: 'static_resetpwd',
|
||||||
|
hideInMenu: true,
|
||||||
|
i18nKey: 'common.resetpwd'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// 下面是指定角色才有
|
||||||
|
// {
|
||||||
|
// name: 'function',
|
||||||
|
// path: '/function',
|
||||||
|
// component: 'layout.base',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function',
|
||||||
|
// i18nKey: 'route.function',
|
||||||
|
// icon: 'icon-park-outline:all-application',
|
||||||
|
// order: 1002,
|
||||||
|
// roles: ['super']
|
||||||
|
// },
|
||||||
|
// children: [
|
||||||
|
// {
|
||||||
|
// name: 'function_hide-child',
|
||||||
|
// path: '/function/hide-child',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function_hide-child',
|
||||||
|
// i18nKey: 'route.function_hide-child',
|
||||||
|
// icon: 'material-symbols:filter-list-off',
|
||||||
|
// order: 2
|
||||||
|
// },
|
||||||
|
// redirect: '/function/hide-child/one',
|
||||||
|
// children: [
|
||||||
|
// {
|
||||||
|
// name: 'function_hide-child_one',
|
||||||
|
// path: '/function/hide-child/one',
|
||||||
|
// component: 'view.function_hide-child_one',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function_hide-child_one',
|
||||||
|
// i18nKey: 'route.function_hide-child_one',
|
||||||
|
// icon: 'material-symbols:filter-list-off',
|
||||||
|
// hideInMenu: true,
|
||||||
|
// activeMenu: 'function_hide-child'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'function_hide-child_three',
|
||||||
|
// path: '/function/hide-child/three',
|
||||||
|
// component: 'view.function_hide-child_three',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function_hide-child_three',
|
||||||
|
// i18nKey: 'route.function_hide-child_three',
|
||||||
|
// hideInMenu: true,
|
||||||
|
// activeMenu: 'function_hide-child'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'function_hide-child_two',
|
||||||
|
// path: '/function/hide-child/two',
|
||||||
|
// component: 'view.function_hide-child_two',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function_hide-child_two',
|
||||||
|
// i18nKey: 'route.function_hide-child_two',
|
||||||
|
// hideInMenu: true,
|
||||||
|
// activeMenu: 'function_hide-child'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'function_multi-tab',
|
||||||
|
// path: '/function/multi-tab',
|
||||||
|
// component: 'view.function_multi-tab',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function_multi-tab',
|
||||||
|
// i18nKey: 'route.function_multi-tab',
|
||||||
|
// icon: 'ic:round-tab',
|
||||||
|
// multiTab: true,
|
||||||
|
// hideInMenu: true,
|
||||||
|
// activeMenu: 'function_tab'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'function_request',
|
||||||
|
// path: '/function/request',
|
||||||
|
// component: 'view.function_request',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function_request',
|
||||||
|
// i18nKey: 'route.function_request',
|
||||||
|
// icon: 'carbon:network-overlay',
|
||||||
|
// order: 3
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'function_super-page',
|
||||||
|
// path: '/function/super-page',
|
||||||
|
// component: 'view.function_super-page',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function_super-page',
|
||||||
|
// i18nKey: 'route.function_super-page',
|
||||||
|
// icon: 'ic:round-supervisor-account',
|
||||||
|
// order: 5,
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'function_tab',
|
||||||
|
// path: '/function/tab',
|
||||||
|
// component: 'view.function_tab',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function_tab',
|
||||||
|
// i18nKey: 'route.function_tab',
|
||||||
|
// icon: 'ic:round-tab',
|
||||||
|
// order: 1
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'function_toggle-auth',
|
||||||
|
// path: '/function/toggle-auth',
|
||||||
|
// component: 'view.function_toggle-auth',
|
||||||
|
// meta: {
|
||||||
|
// title: 'function_toggle-auth',
|
||||||
|
// i18nKey: 'route.function_toggle-auth',
|
||||||
|
// icon: 'ic:round-construction',
|
||||||
|
// order: 4
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: 'about',
|
||||||
|
// path: '/about',
|
||||||
|
// component: 'layout.base$view.about',
|
||||||
|
// meta: {
|
||||||
|
// title: 'about',
|
||||||
|
// i18nKey: 'route.about',
|
||||||
|
// icon: 'fluent:book-information-24-regular',
|
||||||
|
// order: 1003,
|
||||||
|
// roles: ['super']
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
name: 'dictData',
|
||||||
|
path: '/manage/dict/dictData',
|
||||||
|
component: 'layout.base$view.manage_dict_dictData',
|
||||||
|
meta: {
|
||||||
|
title: 'Dict Data',
|
||||||
|
i18nKey: 'route.manage_dictData',
|
||||||
|
icon: 'fluent:book-information-24-regular',
|
||||||
|
order: 1003,
|
||||||
|
hideInMenu: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'log',
|
||||||
|
path: '/manage/task/log',
|
||||||
|
component: 'layout.base$view.manage_task_log',
|
||||||
|
meta: {
|
||||||
|
title: 'Task Log',
|
||||||
|
i18nKey: 'route.manage_task_log',
|
||||||
|
icon: 'fluent:book-information-24-regular',
|
||||||
|
order: 1003,
|
||||||
|
hideInMenu: true
|
||||||
|
}
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**自定义静态菜单 */
|
||||||
|
export const customRoutes: GeneratedRoute[] = [
|
||||||
|
{
|
||||||
|
name: 'endpoint',
|
||||||
|
path: '/endpoint',
|
||||||
|
component: 'layout.base',
|
||||||
|
meta: {
|
||||||
|
title: '终端设备',
|
||||||
|
i18nKey: 'view.endpoint',
|
||||||
|
icon: 'icon-park-outline:all-application',
|
||||||
|
order: 11,
|
||||||
|
hideInMenu: true
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: 'endpoint_access',
|
||||||
|
path: '/endpoint/access',
|
||||||
|
component: 'view.endpoint_access',
|
||||||
|
meta: {
|
||||||
|
title: '当前',
|
||||||
|
i18nKey: 'view.endpoint_access',
|
||||||
|
icon: 'material-symbols:filter-list-off',
|
||||||
|
order: 1
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'endpoint_records',
|
||||||
|
path: '/endpoint/records',
|
||||||
|
component: 'view.endpoint_records',
|
||||||
|
meta: {
|
||||||
|
title: '历史',
|
||||||
|
i18nKey: 'view.endpoint_records',
|
||||||
|
icon: 'ic:round-supervisor-account',
|
||||||
|
order: 3,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'billing',
|
||||||
|
path: '/billing',
|
||||||
|
component: 'layout.base',
|
||||||
|
meta: {
|
||||||
|
title: '账单',
|
||||||
|
i18nKey: 'view.billing',
|
||||||
|
icon: 'icon-park-outline:all-application',
|
||||||
|
order: 13,
|
||||||
|
hideInMenu: true
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
name: 'billing_histories',
|
||||||
|
path: '/billing/histories',
|
||||||
|
component: 'view.billing_histories',
|
||||||
|
meta: {
|
||||||
|
title: '历史查询',
|
||||||
|
i18nKey: 'view.billing_histories',
|
||||||
|
icon: 'material-symbols:filter-list-off',
|
||||||
|
order: 2
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'set-meal',
|
||||||
|
path: '/set-meal',
|
||||||
|
component: 'layout.base$view.set-meal',
|
||||||
|
meta: {
|
||||||
|
title: '套餐',
|
||||||
|
i18nKey: 'view.set-meal',
|
||||||
|
icon: 'icon-park-outline:all-application',
|
||||||
|
order: 15,
|
||||||
|
hideInMenu: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
// Generated by elegant-router
|
// Generated by elegant-router
|
||||||
// Read more: https://github.com/soybeanjs/elegant-router
|
// Read more: https://github.com/soybeanjs/elegant-router
|
||||||
|
|
||||||
import type { RouteRecordRaw } from 'vue-router';
|
import type {RouteRecordRaw} from 'vue-router';
|
||||||
import type { ElegantConstRoute } from '@elegant-router/vue';
|
import type {ElegantConstRoute} from '@elegant-router/vue';
|
||||||
import type { RouteKey, RouteMap, RoutePath } from '@elegant-router/types';
|
import type {RouteKey, RouteMap} from '@elegant-router/types';
|
||||||
import BaseLayout from '@/layouts/base-layout/index.vue';
|
import BaseLayout from '@/layouts/base-layout/index.vue';
|
||||||
import BlankLayout from '@/layouts/blank-layout/index.vue';
|
import BlankLayout from '@/layouts/blank-layout/index.vue';
|
||||||
|
|
||||||
@@ -84,14 +84,14 @@ function transformElegantRouteToVueRoute(
|
|||||||
route.props = true;
|
route.props = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, path, component, children, ...rest } = route;
|
const {name, path, component, children, ...rest} = route;
|
||||||
|
|
||||||
const vueRoute = { name, path, ...rest } as RouteRecordRaw;
|
const vueRoute = {name, path, ...rest} as RouteRecordRaw;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (component) {
|
if (component) {
|
||||||
if (isSingleLevelRoute(route)) {
|
if (isSingleLevelRoute(route)) {
|
||||||
const { layout, view } = getSingleLevelRouteComponent(component);
|
const {layout, view} = getSingleLevelRouteComponent(component);
|
||||||
|
|
||||||
const singleLevelRoute: RouteRecordRaw = {
|
const singleLevelRoute: RouteRecordRaw = {
|
||||||
path,
|
path,
|
||||||
@@ -198,9 +198,11 @@ const routeMap: RouteMap = {
|
|||||||
'function_super-page': '/function/super-page',
|
'function_super-page': '/function/super-page',
|
||||||
'function_tab': '/function/tab',
|
'function_tab': '/function/tab',
|
||||||
'function_toggle-auth': '/function/toggle-auth',
|
'function_toggle-auth': '/function/toggle-auth',
|
||||||
'home': '/home',
|
'dashboard': '/dashboard',
|
||||||
'login': '/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?',
|
'login': '/login/:module(pwd-login|code-login|register|reset-pwd|bind-wechat)?',
|
||||||
'user-center': '/user-center'
|
'user-center': '/user-center',
|
||||||
|
'reset-pwd':'/reset-pwd',
|
||||||
|
'forgot-pwd':'/user-center/resetpwd'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,18 +210,5 @@ const routeMap: RouteMap = {
|
|||||||
* @param name route name
|
* @param name route name
|
||||||
*/
|
*/
|
||||||
export function getRoutePath<T extends RouteKey>(name: T) {
|
export function getRoutePath<T extends RouteKey>(name: T) {
|
||||||
console.log(name);
|
|
||||||
return routeMap[name];
|
return routeMap[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* get route name by route path
|
|
||||||
* @param path route path
|
|
||||||
*/
|
|
||||||
export function getRouteName(path: RoutePath) {
|
|
||||||
const routeEntries = Object.entries(routeMap) as [RouteKey, RoutePath][];
|
|
||||||
|
|
||||||
const routeName: RouteKey | null = routeEntries.find(([, routePath]) => routePath === path)?.[0] || null;
|
|
||||||
|
|
||||||
return routeName;
|
|
||||||
}
|
|
||||||
@@ -30,12 +30,12 @@ export function createRouteGuard(router: Router) {
|
|||||||
const loginRoute: RouteKey = 'login';
|
const loginRoute: RouteKey = 'login';
|
||||||
const noAuthorizationRoute: RouteKey = '403';
|
const noAuthorizationRoute: RouteKey = '403';
|
||||||
|
|
||||||
const isLogin = Boolean(localStg.get('token'));
|
const isLogin = Boolean(localStg.get('tokenSys'));
|
||||||
const needLogin = !to.meta.constant;
|
const needLogin = !to.meta.constant;
|
||||||
const routeRoles = to.meta.roles || [];
|
const routeRoles = to.meta.roles || [];
|
||||||
|
|
||||||
// const hasRole = authStore.userInfo.roles?.some(role => routeRoles.includes(role));
|
const hasRole = authStore.userInfo.roles?.some(role => routeRoles.includes(role));
|
||||||
const hasAuth = authStore.isStaticSuper || !routeRoles.length;
|
const hasAuth = !routeRoles.length || hasRole
|
||||||
|
|
||||||
const routeSwitches: CommonType.StrategicPattern[] = [
|
const routeSwitches: CommonType.StrategicPattern[] = [
|
||||||
// if it is login route when logged in, then switch to the root page
|
// if it is login route when logged in, then switch to the root page
|
||||||
@@ -147,7 +147,7 @@ async function checkRoute(to: RouteLocationNormalized): Promise<RouteLocationRaw
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if the auth route is not initialized, then initialize the auth route
|
// if the auth route is not initialized, then initialize the auth route
|
||||||
const isLogin = Boolean(localStg.get('token'));
|
const isLogin = Boolean(localStg.get('tokenSys'));
|
||||||
// initialize the auth route requires the user to be logged in, if not, redirect to the login page
|
// initialize the auth route requires the user to be logged in, if not, redirect to the login page
|
||||||
if (!isLogin) {
|
if (!isLogin) {
|
||||||
const loginRoute: RouteKey = 'login';
|
const loginRoute: RouteKey = 'login';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { transformElegantRoutesToVueRoutes } from '../elegant/transform';
|
|||||||
export const ROOT_ROUTE: CustomRoute = {
|
export const ROOT_ROUTE: CustomRoute = {
|
||||||
name: 'root',
|
name: 'root',
|
||||||
path: '/',
|
path: '/',
|
||||||
redirect: '/home',
|
redirect: '/dashboard',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'root',
|
title: 'root',
|
||||||
constant: true
|
constant: true
|
||||||
|
|||||||
@@ -1,57 +1,6 @@
|
|||||||
import type { ElegantConstRoute } from '@elegant-router/types';
|
import type {ElegantConstRoute} from '@elegant-router/types';
|
||||||
import { generatedRoutes } from '../elegant/routes';
|
import {customRoutes, generatedRoutes} from '../elegant/routes';
|
||||||
import { transformElegantRoutesToVueRoutes } from '../elegant/transform';
|
import {transformElegantRoutesToVueRoutes} from '../elegant/transform';
|
||||||
|
|
||||||
/**
|
|
||||||
* custom routes
|
|
||||||
*
|
|
||||||
* @link https://github.com/soybeanjs/elegant-router?tab=readme-ov-file#custom-route
|
|
||||||
*/
|
|
||||||
const customRoutes: any[] = [
|
|
||||||
{
|
|
||||||
name: 'exception',
|
|
||||||
path: '/exception',
|
|
||||||
component: 'layout.base',
|
|
||||||
meta: {
|
|
||||||
title: 'exception',
|
|
||||||
i18nKey: 'route.exception',
|
|
||||||
icon: 'ant-design:exception-outlined',
|
|
||||||
order: 7
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
name: 'exception_403',
|
|
||||||
path: '/exception/403',
|
|
||||||
component: 'view._builtin_403',
|
|
||||||
meta: {
|
|
||||||
title: 'exception_403',
|
|
||||||
i18nKey: 'route.exception_403',
|
|
||||||
icon: 'ic:baseline-block'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'exception_404',
|
|
||||||
path: '/exception/404',
|
|
||||||
component: 'view._builtin_404',
|
|
||||||
meta: {
|
|
||||||
title: 'exception_404',
|
|
||||||
i18nKey: 'route.exception_404',
|
|
||||||
icon: 'ic:baseline-web-asset-off'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'exception_500',
|
|
||||||
path: '/exception/500',
|
|
||||||
component: 'view._builtin_500',
|
|
||||||
meta: {
|
|
||||||
title: 'exception_500',
|
|
||||||
i18nKey: 'route.exception_500',
|
|
||||||
icon: 'ic:baseline-wifi-off'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
/** create routes when the auth route mode is static */
|
/** create routes when the auth route mode is static */
|
||||||
export function createStaticRoutes() {
|
export function createStaticRoutes() {
|
||||||
@@ -59,7 +8,7 @@ export function createStaticRoutes() {
|
|||||||
|
|
||||||
const authRoutes: any[] = [];
|
const authRoutes: any[] = [];
|
||||||
|
|
||||||
[...customRoutes, ...generatedRoutes].forEach(item => {
|
[...generatedRoutes, ...customRoutes].forEach(item => {
|
||||||
if (item.meta?.constant) {
|
if (item.meta?.constant) {
|
||||||
constantRoutes.push(item);
|
constantRoutes.push(item);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+560
-5
@@ -13,14 +13,23 @@ export function fetchLogin(body: Api.Auth.LoginBody) {
|
|||||||
data: body
|
data: body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//邮箱验证码接口
|
//邮箱验证码接口
|
||||||
export function sendCaptcha(body:Api.Auth.EmailCaptcha){
|
export function sendCaptcha(body: Api.Auth.EmailCaptcha) {
|
||||||
return request({
|
return request({
|
||||||
url:`/system/email/code?email=${body.email}`,
|
url: `/system/email/code?email=${body.email}`,
|
||||||
method:'get',
|
method: 'get'
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//验证注册
|
//验证注册
|
||||||
|
export function doCheckUserRepeat(body: Api.Auth.CheckBody) {
|
||||||
|
return request<boolean>({
|
||||||
|
url: '/auth/checkRepeat',
|
||||||
|
method: 'post',
|
||||||
|
data: body
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//添加注册
|
//添加注册
|
||||||
export function fetchRegister(body: Api.Auth.RegisterBody) {
|
export function fetchRegister(body: Api.Auth.RegisterBody) {
|
||||||
@@ -30,6 +39,7 @@ export function fetchRegister(body: Api.Auth.RegisterBody) {
|
|||||||
data: body
|
data: body
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** logout */
|
/** logout */
|
||||||
export function doDeleteLogout() {
|
export function doDeleteLogout() {
|
||||||
return request<App.Service.Response<null>>({
|
return request<App.Service.Response<null>>({
|
||||||
@@ -40,7 +50,7 @@ export function doDeleteLogout() {
|
|||||||
|
|
||||||
/** Get user info */
|
/** Get user info */
|
||||||
export function doGetUserInfo() {
|
export function doGetUserInfo() {
|
||||||
return request<Api.Auth.UserInfo>({ url: '/u/user/getInfo' });
|
return request<Api.Auth.UserInfo>({ url: '/system/user/getInfo' });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,3 +84,548 @@ export function doGetCheckCode() {
|
|||||||
url: '/code'
|
url: '/code'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/** Get rate limit list */
|
||||||
|
export function fetchRateLimitList() {
|
||||||
|
return request<Api.Auth.RateLimit[]>({
|
||||||
|
url: '/system/rateLimit/list',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** Add rate limit config */
|
||||||
|
export function addRateLimit(data: Api.Auth.RateLimitAdd) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/rateLimit',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Edit rate limit config */
|
||||||
|
export function editRateLimit(data: Api.Auth.RateLimitAdd & { id: number }) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/rateLimit',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove rate limit config */
|
||||||
|
export function removeRateLimit(ids: number | number[]) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/rateLimit/${ids}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** Get package list */
|
||||||
|
export function fetchPackageList() {
|
||||||
|
return request<Api.Auth.Package[]>({
|
||||||
|
url: '/system/package/list',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** Add package config */
|
||||||
|
export function addPackage(data: Api.Auth.PackageAdd) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/package',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 修改套餐 */
|
||||||
|
export function updatePackage(data: Api.Auth.PackageAdd & { id: string }) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/package',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除套餐 */
|
||||||
|
export function deletePackage(id: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/package/${id}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** Get CDR history list */
|
||||||
|
export function fetchCdrHistory(params: Api.Auth.CdrHistoryParams) {
|
||||||
|
return request<Api.Auth.CdrHistoryResponse>({
|
||||||
|
url: '/system/cdr/pageHistory',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** Get bill list */
|
||||||
|
export function fetchBillList(params: Api.Auth.BillParams) {
|
||||||
|
return request<Api.Auth.BillResponse>({
|
||||||
|
url: '/system/order/page',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取AP设备列表 */
|
||||||
|
export function fetchApDeviceList(siteId: string, params: Omit<Api.Device.ApDeviceParams, 'siteId'>) {
|
||||||
|
return request<Api.Device.ApDeviceResponse>({
|
||||||
|
url: `/system/device/page/${siteId}`,
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 删除AP设备 */
|
||||||
|
export function deleteApDevices(ids: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/device/${ids}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取终端设备列表 */
|
||||||
|
export function fetchTerminalList(params: Api.Device.TerminalDeviceParams) {
|
||||||
|
return request<Api.Device.TerminalDeviceResponse>({
|
||||||
|
url: '/system/client/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取计费规则列表 */
|
||||||
|
export function fetchBillRuleList() {
|
||||||
|
return request<Api.Billing.BillRuleResponse>({
|
||||||
|
url: '/system/billRule/list',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新计费规则 */
|
||||||
|
export function updateBillRule(data: Api.Billing.BillRuleUpdate) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/billRule',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取仪表盘概览数据 */
|
||||||
|
export function getDashboardOverview() {
|
||||||
|
return request<Api.DashboardOverview>({
|
||||||
|
url: '/system/dashboard/overview',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取仪表盘站点列表 */
|
||||||
|
export function getDashboardSiteList(params: { pageNum: number; pageSize: number; searchKey?: string }) {
|
||||||
|
return request<Api.DashboardSiteResponse>({
|
||||||
|
url: '/system/dashboard/page',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取KYC审核列表 */
|
||||||
|
export function fetchKycList(params: Api.Kyc.KycParams) {
|
||||||
|
return request<Api.Kyc.KycResponse>({
|
||||||
|
url: '/system/kyc/page',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** KYC审核通过 */
|
||||||
|
export function approveKyc(id: string, userId: number) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/kyc/approve`,
|
||||||
|
method: 'put',
|
||||||
|
data: { id, userId }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** KYC审核拒绝 */
|
||||||
|
export function rejectKyc(id: string, userId: number, reason: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/kyc/reject`,
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
id,
|
||||||
|
userId,
|
||||||
|
description: reason
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 忘记 AP 设备 */
|
||||||
|
export function forgetApDevice(siteId: string, deviceMac: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/device/forget/${siteId}/${deviceMac}`,
|
||||||
|
method: 'post'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 添加 AP 设备 */
|
||||||
|
export function addApDevice(siteId: string, params: Api.Device.AddApDeviceItem) {
|
||||||
|
// 确保始终发送包含 devices 数组的请求体
|
||||||
|
const requestData: Api.Device.AddApDeviceParams = {
|
||||||
|
devices: [params] // 即使 params 是空对象,也会发送 { devices: [{}] }
|
||||||
|
};
|
||||||
|
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/device/add/${siteId}`,
|
||||||
|
method: 'post',
|
||||||
|
data: requestData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 重启 AP 设备 */
|
||||||
|
export function rebootApDevice(siteId: string, deviceMac: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/device/reboot/${siteId}/${deviceMac}`,
|
||||||
|
method: 'post'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取站点列表 */
|
||||||
|
export function fetchSiteList(params: Api.Site.SiteParams) {
|
||||||
|
return request<Api.Site.SiteResponse>({
|
||||||
|
url: '/system/site/page',
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
pageNum: params.pageNum,
|
||||||
|
pageSize: params.pageSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 更新 AP 设备配置 */
|
||||||
|
export function updateApDeviceConfig(siteId: string, mac: string, config: Api.Device.ApDeviceConfigUpdate) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/device/updateConfig/${siteId}/${mac}`,
|
||||||
|
method: 'post',
|
||||||
|
data: config
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取 AP 设备配置 */
|
||||||
|
export function getApDeviceConfig(siteId: string, deviceMac: string) {
|
||||||
|
return request<Api.Device.ApDeviceConfigResponse>({
|
||||||
|
url: `/system/device/getConfig/${siteId}/${deviceMac}`,
|
||||||
|
method: 'post'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 纳管 AP 设备 */
|
||||||
|
export function adoptApDevice(siteId: string, deviceMac: string, params?: { username?: string; password?: string }) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/device/startAdopt/${siteId}/${deviceMac}`,
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取 WLAN 群组列表 */
|
||||||
|
export function fetchWlanGroups(siteId: string) {
|
||||||
|
return request<Api.Wlan.WlanGroupResponse>({
|
||||||
|
url: `/system/wlan/group/${siteId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取无线网络列表 */
|
||||||
|
export function fetchWlanSsidList(siteId: string, wlanId: string, params: { pageNum: number; pageSize: number }) {
|
||||||
|
return request<Api.Wlan.WlanSsidResponse>({
|
||||||
|
url: `/system/wlan/ssid/${siteId}/${wlanId}`,
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
pageNum: params.pageNum,
|
||||||
|
pageSize: params.pageSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 添加无线网络 */
|
||||||
|
export function addWlanSsid(siteId: string, wlanId: string, params: Api.Wlan.AddWlanSsidParams) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/wlan/ssid/${siteId}/${wlanId}`,
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 删除无线网络 */
|
||||||
|
export function deleteWlanSsid(siteId: string, wlanId: string, ssidId: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/wlan/ssid/${siteId}/${wlanId}/${ssidId}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取无线网络配置 */
|
||||||
|
export function getWlanSsidConfig(siteId: string, wlanId: string, ssidId: string) {
|
||||||
|
return request<Api.Wlan.WlanSsidConfigResponse>({
|
||||||
|
url: `/system/wlan/ssid/${siteId}/${wlanId}/${ssidId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 修改无线网络配置 */
|
||||||
|
export function updateWlanSsid(siteId: string, wlanId: string, ssidId: string, params: Api.Wlan.AddWlanSsidParams) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/wlan/ssid/${siteId}/${wlanId}/${ssidId}`,
|
||||||
|
method: 'put',
|
||||||
|
data: params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取门户列表 */
|
||||||
|
export function fetchPortalList(siteId: string, params: { pageNum: number; pageSize: number }) {
|
||||||
|
return request<Api.Portal.PortalResponse>({
|
||||||
|
url: `/system/portal/${siteId}`,
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
pageNum: params.pageNum,
|
||||||
|
pageSize: params.pageSize
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取 SSID 列表 */
|
||||||
|
export function fetchSsidList(siteId: string) {
|
||||||
|
return request<Api.Portal.SsidListResponse>({
|
||||||
|
url: `/system/wlan/ssids/${siteId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 添加门户 */
|
||||||
|
export function addPortal(siteId: string, params: Api.Portal.AddPortalParams) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/portal/${siteId}`,
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取门户配置 */
|
||||||
|
export function getPortalConfig(siteId: string, portalId: string) {
|
||||||
|
return request<Api.Portal.AddPortalParams>({
|
||||||
|
url: `/system/portal/${siteId}/${portalId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新门户配置 */
|
||||||
|
export function updatePortalConfig(siteId: string, portalId: string, params: Api.Portal.AddPortalParams) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/portal/${siteId}/${portalId}`,
|
||||||
|
method: 'put',
|
||||||
|
data: params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 删除门户 */
|
||||||
|
export function deletePortal(siteId: string, portalId: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/portal/${siteId}/${portalId}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 首页邮箱重置密码 */
|
||||||
|
export function fetcodeReset(data:any) {
|
||||||
|
return request({
|
||||||
|
url: '/system/user/profile/forgotPwd',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取邮箱验证码 */
|
||||||
|
export function getEmailCode(email: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/email/code`,
|
||||||
|
method: 'get',
|
||||||
|
params: { email }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置密码 */
|
||||||
|
export function resetPassword(data: { email: string; code: string; password: string }) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/user/profile/forgotPwd',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 通过原密码修改密码 */
|
||||||
|
export function updatePasswordByOld(params: { oldPassword: string; newPassword: string }) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/user/profile/updatePwd',
|
||||||
|
method: 'put',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 添加站点 */
|
||||||
|
export function addSite(data: Api.Site.AddSiteParams) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/site',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除站点 */
|
||||||
|
export function deleteSite(siteId: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/site/${siteId}`,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取站点配置 */
|
||||||
|
export function getSiteConfig(siteId: string) {
|
||||||
|
return request<Api.Site.SiteConfig>({
|
||||||
|
url: `/system/site/${siteId}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** 更新站点配置 */
|
||||||
|
export function updateSite(siteId: string, data: Api.Site.UpdateSiteParams) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/site/${siteId}`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取用户信息 */
|
||||||
|
export function getUserProfile() {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新用户信息 */
|
||||||
|
export function updateUserProfile(data: { email: string; code: string }) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/user/profile',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 更新支付配置 */
|
||||||
|
export function updatePaymentConfig(data: {
|
||||||
|
currency: string;
|
||||||
|
currencySymbol: string;
|
||||||
|
paymentMethods: string[];
|
||||||
|
}) {
|
||||||
|
return request<any>({
|
||||||
|
url: '/system/config/pay',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** 获取支付配置 */
|
||||||
|
export function getPaymentConfig() {
|
||||||
|
return request<{
|
||||||
|
currency: string;
|
||||||
|
currencySymbol: string;
|
||||||
|
paymentMethods: string[];
|
||||||
|
}>({
|
||||||
|
url: '/system/config/pay',
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取告警数据
|
||||||
|
export function fetchAlertList(siteId: string, params: {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
filters: {
|
||||||
|
timeStart?: string;
|
||||||
|
timeEnd?: string;
|
||||||
|
module?: string;
|
||||||
|
resolved?: boolean;
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/log/alerts/${siteId}`,
|
||||||
|
method: 'get',
|
||||||
|
params: {
|
||||||
|
pageNum: params.pageNum,
|
||||||
|
pageSize: params.pageSize,
|
||||||
|
'filters.timeStart': params.filters.timeStart,
|
||||||
|
'filters.timeEnd': params.filters.timeEnd,
|
||||||
|
'filters.module': params.filters.module,
|
||||||
|
'filters.resolved': params.filters.resolved,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 删除告警
|
||||||
|
export function deleteAlerts(siteId: string, data: {
|
||||||
|
selectType: 'include' | 'exclude' | 'all';
|
||||||
|
startTime: number;
|
||||||
|
endTime: number;
|
||||||
|
logs: number[];
|
||||||
|
}) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/log/alerts/${siteId}`,
|
||||||
|
method: 'delete',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 标记告警为已解决
|
||||||
|
export function markAlertsResolved(siteId: string, data: {
|
||||||
|
selectType: 'unresolved' | 'resolved' | 'all';
|
||||||
|
startTime: number;
|
||||||
|
endTime: number;
|
||||||
|
logs: string[];
|
||||||
|
}) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/log/alerts/${siteId}`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取白名单配置
|
||||||
|
export function fetchAccessControl(siteId: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/access-control/${siteId}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 更新白名单配置
|
||||||
|
export function updateAccessControl(siteId: string, data: {
|
||||||
|
preAuthAccessEnable: boolean;
|
||||||
|
freeAuthClientEnable: boolean;
|
||||||
|
preAuthAccessPolicies: Array<{
|
||||||
|
type: number;
|
||||||
|
ip?: string;
|
||||||
|
url?: string;
|
||||||
|
}>;
|
||||||
|
freeAuthClientPolicies: Array<{
|
||||||
|
type: number;
|
||||||
|
clientIp?: string;
|
||||||
|
clientMac?: string;
|
||||||
|
}>;
|
||||||
|
}) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/access-control/${siteId}`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 获取 Mesh 配置
|
||||||
|
export function getMeshConfig(siteId: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/site/${siteId}/mesh`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 更新 Mesh 配置
|
||||||
|
export function updateMeshConfig(siteId: string, data: { meshEnable: boolean; autoFailoverEnable?: boolean }) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/site/${siteId}/mesh`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 获取 Roaming 配置
|
||||||
|
export function getRoamingConfig(siteId: string) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/site/${siteId}/roaming`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 更新 Roaming 配置
|
||||||
|
export function updateRoamingConfig(siteId: string, data: { fastRoamingEnable: boolean; noStickRoamingEnable?: boolean; aiRoamingEnable?: boolean }) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/system/site/${siteId}/roaming`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ export type DeptFormType = Pick<
|
|||||||
/** 获取部门列表 */
|
/** 获取部门列表 */
|
||||||
export function doGetDeptList(params: Api.SystemManage.DeptSearchParams) {
|
export function doGetDeptList(params: Api.SystemManage.DeptSearchParams) {
|
||||||
return request<Api.SystemManage.DeptList>({
|
return request<Api.SystemManage.DeptList>({
|
||||||
url: '/u/dept/list',
|
url: '/system/dept/list',
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ export function doGetDeptList(params: Api.SystemManage.DeptSearchParams) {
|
|||||||
*/
|
*/
|
||||||
export function doGetDeptInfo(deptId: number) {
|
export function doGetDeptInfo(deptId: number) {
|
||||||
return request<Api.SystemManage.Dept>({
|
return request<Api.SystemManage.Dept>({
|
||||||
url: `/u/dept/${deptId}`
|
url: `/system/dept/${deptId}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ export function doGetDeptInfo(deptId: number) {
|
|||||||
*/
|
*/
|
||||||
export function doAddDept(body: DeptFormType) {
|
export function doAddDept(body: DeptFormType) {
|
||||||
return request({
|
return request({
|
||||||
url: '/u/dept',
|
url: '/system/dept',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: body
|
data: body
|
||||||
});
|
});
|
||||||
@@ -44,7 +44,7 @@ export function doAddDept(body: DeptFormType) {
|
|||||||
*/
|
*/
|
||||||
export function doEditDept(body: DeptFormType & { deptId: number }) {
|
export function doEditDept(body: DeptFormType & { deptId: number }) {
|
||||||
return request({
|
return request({
|
||||||
url: '/u/dept',
|
url: '/system/dept',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data: body
|
data: body
|
||||||
});
|
});
|
||||||
@@ -57,7 +57,7 @@ export function doEditDept(body: DeptFormType & { deptId: number }) {
|
|||||||
*/
|
*/
|
||||||
export function doDeleteDept(deptId: string | number) {
|
export function doDeleteDept(deptId: string | number) {
|
||||||
return request({
|
return request({
|
||||||
url: `/u/dept/${deptId}`,
|
url: `/system/dept/${deptId}`,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
+43
-5
@@ -6,7 +6,7 @@ export type DictSubmitModel = Partial<
|
|||||||
|
|
||||||
export const doGetDictList = (params: Api.SystemManage.DictSearchParams) => {
|
export const doGetDictList = (params: Api.SystemManage.DictSearchParams) => {
|
||||||
return request<Api.SystemManage.DictList>({
|
return request<Api.SystemManage.DictList>({
|
||||||
url: '/u/dict/type/list',
|
url: '/system/dict/type/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
@@ -14,7 +14,7 @@ export const doGetDictList = (params: Api.SystemManage.DictSearchParams) => {
|
|||||||
|
|
||||||
export const doAddDict = (data: DictSubmitModel) => {
|
export const doAddDict = (data: DictSubmitModel) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/u/dict/type',
|
url: '/system/dict/type',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
@@ -22,7 +22,7 @@ export const doAddDict = (data: DictSubmitModel) => {
|
|||||||
|
|
||||||
export const doEditDict = (data: DictSubmitModel) => {
|
export const doEditDict = (data: DictSubmitModel) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/u/dict/type',
|
url: '/system/dict/type',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
@@ -30,7 +30,45 @@ export const doEditDict = (data: DictSubmitModel) => {
|
|||||||
|
|
||||||
export const doDeleteDict = (dictId: string | number) => {
|
export const doDeleteDict = (dictId: string | number) => {
|
||||||
return request({
|
return request({
|
||||||
url: `/u/dict/type/${dictId}`,
|
url: `/system/dict/type/${dictId}`,
|
||||||
method: 'post'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询字典类型详细
|
||||||
|
* @param dictId 字典编号
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function doGetType(dictId: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/system/dict/type/${dictId}`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典数据列表(指定字典类型)
|
||||||
|
* @param dictType 字典类型
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function getDictDataType(dictType: string) {
|
||||||
|
return request({
|
||||||
|
url: `/system/dict/data/type/${dictType}`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取字典选择框列表
|
||||||
|
* @param data 字典数据对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function getDictOptionselect() {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/type/optionselect',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { request } from '../request';
|
||||||
|
|
||||||
|
export type DictSubmitModel = Partial<
|
||||||
|
Pick<Api.SystemManage.Dict, 'dictName' | 'dictType' | 'status' | 'remark' | 'dictId'>
|
||||||
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字典数据列表导出
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns bolb
|
||||||
|
*/
|
||||||
|
export function exportData(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/export',
|
||||||
|
method: 'post',
|
||||||
|
data: query,
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询字典数据列表
|
||||||
|
* @param query 查询值
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function doGetdictDataList(query: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询字典数据详细
|
||||||
|
* @param dictCode 字典代码值
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function doGetDataInfo(dictCode: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/system/dict/data/${dictCode}`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增字典数据
|
||||||
|
* @param data 字典数据对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function addData(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改字典数据
|
||||||
|
* @param data 字典数据对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function updateData(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/system/dict/data',
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除字典数据
|
||||||
|
* @param dictCode 字典代码值
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function delData(dictCode: string | number) {
|
||||||
|
return request({
|
||||||
|
url: `/system/dict/data/${dictCode}`,
|
||||||
|
method: 'delete',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import { request } from '../request';
|
||||||
|
|
||||||
|
|
||||||
|
export function doGetjobList(params?: Api.SystemManage.UserSearchParams) {
|
||||||
|
return request<Api.SystemManage.UserList>({
|
||||||
|
url: '/schedule/job/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function doGetjobInfo(paramsId: any) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/schedule/job/${paramsId}`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增定时任务调度
|
||||||
|
* @param data 任务对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function addJob(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/job',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改定时任务调度
|
||||||
|
* @param data 任务对象
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function updateJob(data: Record<string, any>) {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/job',
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除调度日志
|
||||||
|
* @param jobIds 任务日志Id
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function delJobLog(jobIds: string) {
|
||||||
|
return request({
|
||||||
|
url: `/schedule/job/${jobIds}`,
|
||||||
|
method: 'delete',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务立即执行一次
|
||||||
|
* @param jobId 任务ID
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function runJob(jobId: string) {
|
||||||
|
return request({
|
||||||
|
url: `/schedule/job/run`,
|
||||||
|
method: 'put',
|
||||||
|
data: {jobId},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务状态修改
|
||||||
|
* @param jobId 任务ID
|
||||||
|
* @param status 变更状态值
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function changeJobStatus(
|
||||||
|
jobId: string | number,
|
||||||
|
status: string | number
|
||||||
|
) {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/job/changeStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: {
|
||||||
|
jobId,
|
||||||
|
status,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务调度列表导出
|
||||||
|
* @param query 查询参数
|
||||||
|
* @returns bolb
|
||||||
|
*/
|
||||||
|
export function exportJob() {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/job/export',
|
||||||
|
method: 'post',
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { request } from '../request';
|
||||||
|
|
||||||
|
|
||||||
|
export function doGetjobLogList(params?: any) {
|
||||||
|
return request<Api.SystemManage.UserList>({
|
||||||
|
url: '/schedule/job/log/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doGetjobLogInfo(paramsId: any) {
|
||||||
|
return request<any>({
|
||||||
|
url: `/schedule/job/log/${paramsId}`,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDeleteJobLog(jobLogId: any) {
|
||||||
|
return request({ url: `/schedule/job/log/${jobLogId.join(',')}`, method: 'delete' });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空调度日志
|
||||||
|
* @returns object
|
||||||
|
*/
|
||||||
|
export function doCleanJobLog() {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/job/log/clean',
|
||||||
|
method: 'delete',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时任务调度日志列表导出
|
||||||
|
* @returns bolb
|
||||||
|
*/
|
||||||
|
export function exportJobLog(
|
||||||
|
) {
|
||||||
|
return request({
|
||||||
|
url: '/schedule/job/log/export',
|
||||||
|
method: 'post',
|
||||||
|
responseType: 'blob',
|
||||||
|
headers: {
|
||||||
|
"Authorization": "Bearer your_token_here",
|
||||||
|
"Accept": "application/json, text/plain, */*",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { request } from '../request';
|
||||||
|
|
||||||
|
|
||||||
|
export function doGetlogList(params?: Api.SystemManage.UserSearchParams) {
|
||||||
|
return request<Api.SystemManage.UserList>({
|
||||||
|
url: '/system/operlog/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDeleteLog(userId: any) {
|
||||||
|
return request({ url: `/system/operlog/${userId.join(',')}`, method: 'delete' });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function doExportLog() {
|
||||||
|
return request({ url: `/system/operlog/export`, method: 'post', responseType: 'blob'});
|
||||||
|
}
|
||||||
@@ -7,13 +7,13 @@ export type MenuListQuery = Partial<
|
|||||||
Api.SystemManage.CommonSearchParams;
|
Api.SystemManage.CommonSearchParams;
|
||||||
|
|
||||||
export function doGetMenuList(params: MenuListQuery) {
|
export function doGetMenuList(params: MenuListQuery) {
|
||||||
return request<Api.SystemManage.MenuList>({ url: '/u/menu/list', method: 'get', params });
|
return request<Api.SystemManage.MenuList>({ url: '/system/menu/list', method: 'get', params });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** get all pages */
|
/** get all pages */
|
||||||
export function fetchGetAllPages() {
|
export function fetchGetAllPages() {
|
||||||
return request<Pick<Api.SystemManage.Menu, 'menuId' | 'menuName' | 'path'>[]>({
|
return request<Pick<Api.SystemManage.Menu, 'menuId' | 'menuName' | 'path'>[]>({
|
||||||
url: '/u/menu/list',
|
url: '/system/menu/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: {
|
params: {
|
||||||
menuType: 'C'
|
menuType: 'C'
|
||||||
@@ -24,7 +24,7 @@ export function fetchGetAllPages() {
|
|||||||
/** get menu tree */
|
/** get menu tree */
|
||||||
export function fetchGetMenuTree() {
|
export function fetchGetMenuTree() {
|
||||||
return request<Api.SystemManage.MenuTree[]>({
|
return request<Api.SystemManage.MenuTree[]>({
|
||||||
url: '/u/menu/treeselect',
|
url: '/system/menu/treeselect',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -35,27 +35,27 @@ export function doGetRoleMenuList(roleId: number) {
|
|||||||
checkedKeys: number[];
|
checkedKeys: number[];
|
||||||
menus: Api.SystemManage.MenuTree[];
|
menus: Api.SystemManage.MenuTree[];
|
||||||
}>({
|
}>({
|
||||||
url: `/u/menu/roleMenuTreeselect/${roleId}`,
|
url: `/system/menu/roleMenuTreeselect/${roleId}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** add menu */
|
/** add menu */
|
||||||
export function doAddMenu(data: MenuModelType) {
|
export function doAddMenu(data: MenuModelType) {
|
||||||
return request({ url: '/u/menu', method: 'post', data });
|
return request({ url: '/system/menu', method: 'post', data });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** delete menu */
|
/** delete menu */
|
||||||
export function doDeleteMenu(menuId: number) {
|
export function doDeleteMenu(menuId: number) {
|
||||||
return request({ url: `/u/menu/${menuId}`, method: 'delete' });
|
return request({ url: `/system/menu/${menuId}`, method: 'delete' });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** get menu detail */
|
/** get menu detail */
|
||||||
export function doGetMenuDetail(menuId: number) {
|
export function doGetMenuDetail(menuId: number) {
|
||||||
return request<MenuModelType>({ url: `/u/menu/${menuId}`, method: 'get' });
|
return request<MenuModelType>({ url: `/system/menu/${menuId}`, method: 'get' });
|
||||||
}
|
}
|
||||||
|
|
||||||
/** edit menu */
|
/** edit menu */
|
||||||
export function doEditMenu(data: MenuModelType) {
|
export function doEditMenu(data: MenuModelType) {
|
||||||
return request({ url: '/u/menu', method: 'put', data });
|
return request({ url: '/system/menu', method: 'put', data });
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ export type PostSubmitModel = Partial<
|
|||||||
|
|
||||||
export function doGetPostList(params: Api.SystemManage.PostSearchParams) {
|
export function doGetPostList(params: Api.SystemManage.PostSearchParams) {
|
||||||
return request<Api.SystemManage.PostList>({
|
return request<Api.SystemManage.PostList>({
|
||||||
url: '/u/post/list',
|
url: '/system/post/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
@@ -14,14 +14,14 @@ export function doGetPostList(params: Api.SystemManage.PostSearchParams) {
|
|||||||
|
|
||||||
export function doGetPostDetail(postId: number) {
|
export function doGetPostDetail(postId: number) {
|
||||||
return request({
|
return request({
|
||||||
url: `/u/post/${postId}`,
|
url: `/system/post/${postId}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doAddPost(data: PostSubmitModel) {
|
export function doAddPost(data: PostSubmitModel) {
|
||||||
return request({
|
return request({
|
||||||
url: '/u/post',
|
url: '/system/post',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
@@ -29,7 +29,7 @@ export function doAddPost(data: PostSubmitModel) {
|
|||||||
|
|
||||||
export function doEditPost(data: PostSubmitModel) {
|
export function doEditPost(data: PostSubmitModel) {
|
||||||
return request({
|
return request({
|
||||||
url: '/u/post',
|
url: '/system/post',
|
||||||
method: 'put',
|
method: 'put',
|
||||||
data
|
data
|
||||||
});
|
});
|
||||||
@@ -37,7 +37,7 @@ export function doEditPost(data: PostSubmitModel) {
|
|||||||
|
|
||||||
export function doDeletePost(postId: string | number) {
|
export function doDeletePost(postId: string | number) {
|
||||||
return request({
|
return request({
|
||||||
url: `/u/post/${postId}`,
|
url: `/system/post/${postId}`,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,7 @@ import { request } from '../request';
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function doPutRole(role: Api.SystemManage.Role) {
|
export function doPutRole(role: Api.SystemManage.Role) {
|
||||||
return request({ url: '/u/role', method: 'put', data: role });
|
return request({ url: '/system/role', method: 'put', data: role });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -17,7 +17,7 @@ export function doPutRole(role: Api.SystemManage.Role) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function doPostRole(role: Api.SystemManage.Role) {
|
export function doPostRole(role: Api.SystemManage.Role) {
|
||||||
return request({ url: '/u/role', method: 'post', data: role });
|
return request({ url: '/system/role', method: 'post', data: role });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,12 +27,12 @@ export function doPostRole(role: Api.SystemManage.Role) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function doDeleteRole(roleId: number | string) {
|
export function doDeleteRole(roleId: number | string) {
|
||||||
return request({ url: `/u/role/${roleId}`, method: 'delete' });
|
return request({ url: `/system/role/${roleId}`, method: 'delete' });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doGetRoleList(params?: Api.SystemManage.RoleSearchParams) {
|
export function doGetRoleList(params?: Api.SystemManage.RoleSearchParams) {
|
||||||
return request<Api.SystemManage.RoleList>({
|
return request<Api.SystemManage.RoleList>({
|
||||||
url: '/u/role/list',
|
url: '/system/role/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export function fetchGetConstantRoutes() {
|
|||||||
|
|
||||||
/** get user routes */
|
/** get user routes */
|
||||||
export function doGetUserRoutes() {
|
export function doGetUserRoutes() {
|
||||||
return request<Api.Route.MenuRoute[]>({ url: '/u/menu/getRouters' });
|
return request<Api.Route.MenuRoute[]>({ url: '/system/menu/getRouters' });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+26
-11
@@ -2,20 +2,28 @@ import { request } from '../request';
|
|||||||
|
|
||||||
// user api
|
// user api
|
||||||
export function doPutUser(user: Api.Auth.User) {
|
export function doPutUser(user: Api.Auth.User) {
|
||||||
return request({ url: '/u/user', method: 'put', data: user });
|
return request({ url: '/system/user', method: 'put', data: user });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doPostUser(user: Api.Auth.User) {
|
export function doPostUser(user: Api.Auth.User) {
|
||||||
return request({ url: '/u/user', method: 'post', data: user });
|
return request({ url: '/system/user', method: 'post', data: user });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doDeleteUser(userId: number | string) {
|
export function doDeleteUser(userId: number | string) {
|
||||||
return request({ url: `/u/user/${userId}`, method: 'delete' });
|
return request({ url: `/system/user/${userId}`, method: 'delete' });
|
||||||
}
|
}
|
||||||
|
//系统管理查看客户
|
||||||
export function doGetUserList(params?: Api.SystemManage.UserSearchParams) {
|
export function doGetsysUserList(params?: { userName?: string; email?: string }) {
|
||||||
return request<Api.SystemManage.UserList>({
|
return request<Api.Common.PaginatingQueryRecord<Api.Auth.User>>({
|
||||||
url: '/u/user/list',
|
url: '/system/user/list',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//系统管理查看用户
|
||||||
|
export function doGetUserList(params?: { userName?: string; email?: string }) {
|
||||||
|
return request<Api.Common.PaginatingQueryRecord<Api.Auth.User>>({
|
||||||
|
url: '/system/user/listUser',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
});
|
});
|
||||||
@@ -29,26 +37,33 @@ export function doGetUserList(params?: Api.SystemManage.UserSearchParams) {
|
|||||||
export function doGetUserPostsAndRoles(userId: number | string | undefined) {
|
export function doGetUserPostsAndRoles(userId: number | string | undefined) {
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return request<Api.SystemManage.UserPostsAndRoles>({
|
return request<Api.SystemManage.UserPostsAndRoles>({
|
||||||
url: '/u/user/',
|
url: '/system/user/',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return request<Api.SystemManage.UserPostsAndRoles>({
|
return request<Api.SystemManage.UserPostsAndRoles>({
|
||||||
url: `/u/user/${userId}`,
|
url: `/system/user/${userId}`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doGetAdminUserPostsAndRoles() {
|
export function doGetAdminUserPostsAndRoles() {
|
||||||
return request<Api.SystemManage.UserPostsAndRoles>({
|
return request<Api.SystemManage.UserPostsAndRoles>({
|
||||||
url: `/u/user`,
|
url: `/system/user`,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doGetUserDeptTree() {
|
export function doGetUserDeptTree() {
|
||||||
return request<Api.Common.CommonTree>({
|
return request<Api.Common.CommonTree>({
|
||||||
url: '/u/user/deptTree',
|
url: '/system/user/deptTree',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doUpdatePwd(pwdJson: any) {
|
||||||
|
var url= `/system/user/resetPwd`;
|
||||||
|
return request({ url, method: 'put',data:pwdJson });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -25,11 +25,11 @@ export const request = createFlatRequest<App.Service.Response, InstanceState>(
|
|||||||
const { headers } = config;
|
const { headers } = config;
|
||||||
|
|
||||||
// set token
|
// set token
|
||||||
const token = localStg.get('token');
|
const token = localStg.get('tokenSys');
|
||||||
const Authorization = token ? `Bearer ${token}` : null;
|
const Authorization = token ? `Bearer ${token}` : null;
|
||||||
|
|
||||||
// set language
|
// set language
|
||||||
const ContentLanguage = localStg.get('lang') || 'zh-CN';
|
const ContentLanguage = localStg.get('lang') || 'en-US';
|
||||||
Object.assign(headers, { Authorization, "Content-Language": ContentLanguage });
|
Object.assign(headers, { Authorization, "Content-Language": ContentLanguage });
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import { fetchRefreshToken } from '../api/auth';
|
|||||||
export async function handleRefreshToken(axiosConfig: AxiosRequestConfig) {
|
export async function handleRefreshToken(axiosConfig: AxiosRequestConfig) {
|
||||||
const { resetStore } = useAuthStore();
|
const { resetStore } = useAuthStore();
|
||||||
|
|
||||||
const refreshToken = localStg.get('refreshToken') || '';
|
const refreshToken = localStg.get('refreshTokenSys') || '';
|
||||||
const { error, data } = await fetchRefreshToken(refreshToken);
|
const { error, data } = await fetchRefreshToken(refreshToken);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
localStg.set('token', data.access_token);
|
localStg.set('tokenSys', data.access_token);
|
||||||
localStg.set('refreshToken', data.refreshToken);
|
localStg.set('refreshTokenSys', data.refreshToken);
|
||||||
|
|
||||||
const config = { ...axiosConfig };
|
const config = { ...axiosConfig };
|
||||||
if (config.headers) {
|
if (config.headers) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { useRouteStore } from '../route';
|
|||||||
import { useTabStore } from '../tab';
|
import { useTabStore } from '../tab';
|
||||||
import { useThemeStore } from '../theme';
|
import { useThemeStore } from '../theme';
|
||||||
|
|
||||||
|
|
||||||
export const useAppStore = defineStore(SetupStoreId.App, () => {
|
export const useAppStore = defineStore(SetupStoreId.App, () => {
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
@@ -44,7 +45,7 @@ export const useAppStore = defineStore(SetupStoreId.App, () => {
|
|||||||
setReloadFlag(true);
|
setReloadFlag(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const locale = ref<App.I18n.LangType>(localStg.get('lang') || 'zh-CN');
|
const locale = ref<App.I18n.LangType>(localStg.get('lang') || 'en-US');
|
||||||
|
|
||||||
const localeOptions: App.I18n.LangOption[] = [
|
const localeOptions: App.I18n.LangOption[] = [
|
||||||
{
|
{
|
||||||
@@ -58,9 +59,16 @@ export const useAppStore = defineStore(SetupStoreId.App, () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
function changeLocale(lang: App.I18n.LangType) {
|
function changeLocale(lang: App.I18n.LangType) {
|
||||||
|
if (locale.value === lang) return;
|
||||||
|
|
||||||
locale.value = lang;
|
locale.value = lang;
|
||||||
setLocale(lang);
|
setLocale(lang);
|
||||||
localStg.set('lang', lang);
|
localStg.set('lang', lang);
|
||||||
|
|
||||||
|
//routeStore.updateGlobalMenusByLocale();
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update document title by locale */
|
/** Update document title by locale */
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { localStg } from '@/utils/storage';
|
|||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
import { useRouteStore } from '../route';
|
import { useRouteStore } from '../route';
|
||||||
import { clearAuthStorage, emptyInfo, getToken } from './shared';
|
import { clearAuthStorage, emptyInfo, getToken } from './shared';
|
||||||
import {sendCaptcha} from "@/service/api/auth";
|
import { doCheckUserRepeat, sendCaptcha } from '@/service/api/auth';
|
||||||
|
|
||||||
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
||||||
const routeStore = useRouteStore();
|
const routeStore = useRouteStore();
|
||||||
@@ -31,13 +31,6 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
/** is super role in static route */
|
|
||||||
const isStaticSuper = computed(() => {
|
|
||||||
const { VITE_AUTH_ROUTE_MODE, VITE_STATIC_SUPER_ROLE } = import.meta.env;
|
|
||||||
|
|
||||||
return VITE_AUTH_ROUTE_MODE === 'static' && userInfo.roles?.includes(VITE_STATIC_SUPER_ROLE);
|
|
||||||
});
|
|
||||||
|
|
||||||
/** Is login */
|
/** Is login */
|
||||||
const isLogin = computed(() => Boolean(token.value));
|
const isLogin = computed(() => Boolean(token.value));
|
||||||
|
|
||||||
@@ -48,7 +41,7 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
*/
|
*/
|
||||||
async function resetStore(isMe = false) {
|
async function resetStore(isMe = false) {
|
||||||
if (isMe) {
|
if (isMe) {
|
||||||
doDeleteLogout();
|
await doDeleteLogout();
|
||||||
}
|
}
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
@@ -77,10 +70,10 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
startLoading();
|
startLoading();
|
||||||
|
|
||||||
const { data: loginToken, error } = await fetchLogin(loginForm);
|
const { data: loginToken, error } = await fetchLogin(loginForm);
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
const pass = await loginByToken(loginToken);
|
const pass = await loginByToken(loginToken);
|
||||||
onSuccess && onSuccess();
|
onSuccess && onSuccess();
|
||||||
|
|
||||||
if (pass) {
|
if (pass) {
|
||||||
await routeStore.initAuthRoute();
|
await routeStore.initAuthRoute();
|
||||||
|
|
||||||
@@ -105,8 +98,8 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
|
|
||||||
async function loginByToken(loginToken: Api.Auth.LoginToken) {
|
async function loginByToken(loginToken: Api.Auth.LoginToken) {
|
||||||
// 1. stored in the localStorage, the later requests need it in headers
|
// 1. stored in the localStorage, the later requests need it in headers
|
||||||
localStg.set('token', loginToken.access_token);
|
localStg.set('tokenSys', loginToken.access_token);
|
||||||
localStg.set('refreshToken', loginToken.refreshToken);
|
localStg.set('refreshTokenSys', loginToken.refreshToken);
|
||||||
token.value = loginToken.access_token;
|
token.value = loginToken.access_token;
|
||||||
|
|
||||||
const isSuccess = await refreshUserInfo();
|
const isSuccess = await refreshUserInfo();
|
||||||
@@ -122,6 +115,15 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查用户信息是否已存在
|
||||||
|
*/
|
||||||
|
async function checkUserRepeat(checkForm: Api.Auth.CheckBody) {
|
||||||
|
const { data, error } = await doCheckUserRepeat(checkForm);
|
||||||
|
return { exists: data, error };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register new user
|
* Register new user
|
||||||
*/
|
*/
|
||||||
@@ -139,22 +141,18 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
endLoading();
|
endLoading();
|
||||||
return !error;
|
return !error;
|
||||||
}
|
}
|
||||||
async function captcha(email:string){
|
|
||||||
|
async function captcha(email: string) {
|
||||||
if (!email) {
|
if (!email) {
|
||||||
return;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await sendCaptcha({ email }); // 这里调用后端接口发送验证码
|
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
const { data, error } = await sendCaptcha({ email }); // 这里调用后端接口发送验证码
|
||||||
|
return { data, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
token,
|
token,
|
||||||
userInfo,
|
userInfo,
|
||||||
isStaticSuper,
|
|
||||||
isLogin,
|
isLogin,
|
||||||
loginLoading,
|
loginLoading,
|
||||||
resetStore,
|
resetStore,
|
||||||
@@ -163,5 +161,6 @@ export const useAuthStore = defineStore(SetupStoreId.Auth, () => {
|
|||||||
refreshUserInfo,
|
refreshUserInfo,
|
||||||
register,
|
register,
|
||||||
captcha,
|
captcha,
|
||||||
|
checkUserRepeat
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -2,18 +2,17 @@ import { localStg } from '@/utils/storage';
|
|||||||
|
|
||||||
/** Get token */
|
/** Get token */
|
||||||
export function getToken() {
|
export function getToken() {
|
||||||
return localStg.get('token') || '';
|
return localStg.get('tokenSys') || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export const emptyInfo: Api.Auth.UserInfo = {
|
export const emptyInfo: Api.Auth.UserInfo = {
|
||||||
roles: [],
|
roles: [],
|
||||||
buttons: [],
|
|
||||||
permissions: [],
|
permissions: [],
|
||||||
user: null
|
user: null
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Clear auth storage */
|
/** Clear auth storage */
|
||||||
export function clearAuthStorage() {
|
export function clearAuthStorage() {
|
||||||
localStg.remove('token');
|
localStg.remove('tokenSys');
|
||||||
localStg.remove('refreshToken');
|
localStg.remove('refreshTokenSys');
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
/**字典参数类型 */
|
||||||
|
type DictStore = {
|
||||||
|
/**字典数据 */
|
||||||
|
dicts: Map<string, DictType[]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useDictStore = defineStore('dict', {
|
||||||
|
state: (): DictStore => ({
|
||||||
|
dicts: new Map(),
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
/**清空字典 */
|
||||||
|
clearDict() {
|
||||||
|
this.dicts.clear();
|
||||||
|
},
|
||||||
|
/**删除字典 */
|
||||||
|
removeDict(key: string) {
|
||||||
|
if (!key) return;
|
||||||
|
return this.dicts.delete(key);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 处理字典数据对象用于回显标签
|
||||||
|
* @param data 字典数据项
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
parseDataDict(data: Record<string, any>) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: data.dictLabel,
|
||||||
|
value: data.dictValue,
|
||||||
|
tagType: data.tagType,
|
||||||
|
tagClass: data.tagClass,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
/**获取字典 */
|
||||||
|
async getDict(key: string) {
|
||||||
|
if (!key) return [];
|
||||||
|
let disct = this.dicts.get(key);
|
||||||
|
if (disct === undefined || disct.length === 0) {
|
||||||
|
const res = await getDictDataType(key);
|
||||||
|
if (!res.error && Array.isArray(res.data)) {
|
||||||
|
const dictData: DictType[] = res.data.map((d:any) => ({
|
||||||
|
label: d.dictLabel,
|
||||||
|
value: d.dictValue,
|
||||||
|
tagType: d.tagType,
|
||||||
|
tagClass: d.tagClass,
|
||||||
|
}));
|
||||||
|
this.dicts.set(key, dictData);
|
||||||
|
disct = dictData;
|
||||||
|
} else {
|
||||||
|
disct = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return disct;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default useDictStore;
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
import { computed, ref, shallowRef } from 'vue';
|
import {computed, ref, shallowRef} from 'vue';
|
||||||
import type { RouteRecordRaw } from 'vue-router';
|
import type {RouteRecordRaw} from 'vue-router';
|
||||||
import { defineStore } from 'pinia';
|
import {defineStore} from 'pinia';
|
||||||
import { useBoolean } from '@sa/hooks';
|
import {useBoolean} from '@sa/hooks';
|
||||||
import type { CustomRoute, ElegantConstRoute, LastLevelRouteKey, RouteKey } from '@elegant-router/types';
|
import type {CustomRoute, ElegantConstRoute, LastLevelRouteKey, RouteKey} from '@elegant-router/types';
|
||||||
import { SetupStoreId } from '@/enum';
|
import {SetupStoreId} from '@/enum';
|
||||||
import { router } from '@/router';
|
import {router} from '@/router';
|
||||||
import { createStaticRoutes, getAuthVueRoutes } from '@/router/routes';
|
import {createStaticRoutes, getAuthVueRoutes} from '@/router/routes';
|
||||||
import { ROOT_ROUTE } from '@/router/routes/builtin';
|
import {ROOT_ROUTE} from '@/router/routes/builtin';
|
||||||
import { getRoutePath } from '@/router/elegant/transform';
|
import {getRoutePath} from '@/router/elegant/transform';
|
||||||
import { useAppStore } from '../app';
|
import {useAppStore} from '../app';
|
||||||
import { useAuthStore } from '../auth';
|
import {useAuthStore} from '../auth';
|
||||||
import { useTabStore } from '../tab';
|
import {useTabStore} from '../tab';
|
||||||
import {
|
import {
|
||||||
filterAuthRoutesByRoles,
|
filterAuthRoutesByRoles,
|
||||||
getBreadcrumbsByRoute,
|
getBreadcrumbsByRoute,
|
||||||
@@ -26,12 +26,12 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
|
|||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const tabStore = useTabStore();
|
const tabStore = useTabStore();
|
||||||
const { bool: isInitConstantRoute, setBool: setIsInitConstantRoute } = useBoolean();
|
const {bool: isInitConstantRoute, setBool: setIsInitConstantRoute} = useBoolean();
|
||||||
const { bool: isInitAuthRoute, setBool: setIsInitAuthRoute } = useBoolean();
|
const {bool: isInitAuthRoute, setBool: setIsInitAuthRoute} = useBoolean();
|
||||||
|
|
||||||
|
|
||||||
/** Home route key */
|
/** Home route key */
|
||||||
const routeHome = ref('home');
|
const routeHome = ref('dashboard');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set route home
|
* Set route home
|
||||||
@@ -46,7 +46,9 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
|
|||||||
const authRoutes = shallowRef<ElegantConstRoute[]>([]);
|
const authRoutes = shallowRef<ElegantConstRoute[]>([]);
|
||||||
|
|
||||||
function addAuthRoutes(routes: ElegantConstRoute[]) {
|
function addAuthRoutes(routes: ElegantConstRoute[]) {
|
||||||
const authRoutesMap = new Map(authRoutes.value.map(route => [route.name, route]));
|
const {constantRoutes} = createStaticRoutes();
|
||||||
|
|
||||||
|
const authRoutesMap = new Map(constantRoutes.map(route => [route.name, route]));
|
||||||
|
|
||||||
routes.forEach(route => {
|
routes.forEach(route => {
|
||||||
authRoutesMap.set(route.name, route);
|
authRoutesMap.set(route.name, route);
|
||||||
@@ -146,17 +148,9 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
|
|||||||
async function initConstantRoute() {
|
async function initConstantRoute() {
|
||||||
if (isInitConstantRoute.value) return;
|
if (isInitConstantRoute.value) return;
|
||||||
|
|
||||||
// if (authRouteMode.value === 'static') {
|
const {constantRoutes} = createStaticRoutes();
|
||||||
const { constantRoutes } = createStaticRoutes();
|
|
||||||
|
|
||||||
addAuthRoutes(constantRoutes);
|
addAuthRoutes(constantRoutes);
|
||||||
// } else {
|
|
||||||
// const { data, error } = await fetchGetConstantRoutes();
|
|
||||||
|
|
||||||
// if (!error) {
|
|
||||||
// addAuthRoutes(data);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
handleAuthRoutes();
|
handleAuthRoutes();
|
||||||
|
|
||||||
@@ -165,43 +159,24 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
|
|||||||
|
|
||||||
/** Init auth route */
|
/** Init auth route */
|
||||||
async function initAuthRoute() {
|
async function initAuthRoute() {
|
||||||
await initStaticAuthRoute();
|
|
||||||
await initDynamicAuthRoute();
|
|
||||||
tabStore.initHomeTab();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Init static auth route */
|
const {data: routes, error} = await doGetUserRoutes();
|
||||||
async function initStaticAuthRoute() {
|
|
||||||
const { authRoutes: staticAuthRoutes } = createStaticRoutes();
|
|
||||||
if (authStore.isStaticSuper) {
|
|
||||||
addAuthRoutes(staticAuthRoutes);
|
|
||||||
} else {
|
|
||||||
const filteredAuthRoutes = filterAuthRoutesByRoles(staticAuthRoutes, authStore.userInfo.roles ?? []);
|
|
||||||
|
|
||||||
addAuthRoutes(filteredAuthRoutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAuthRoutes();
|
|
||||||
|
|
||||||
setIsInitAuthRoute(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Init dynamic auth route */
|
|
||||||
async function initDynamicAuthRoute() {
|
|
||||||
const { data: routes, error } = await doGetUserRoutes();
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
addAuthRoutes(routes);
|
const {authRoutes: staticAuthRoutes} = createStaticRoutes();
|
||||||
|
const filteredAuthRoutes = filterAuthRoutesByRoles(staticAuthRoutes, authStore.userInfo.roles ?? []);
|
||||||
|
addAuthRoutes(filteredAuthRoutes.concat(routes));
|
||||||
|
|
||||||
handleAuthRoutes();
|
handleAuthRoutes();
|
||||||
|
|
||||||
setRouteHome('home');
|
setRouteHome('dashboard');
|
||||||
|
|
||||||
handleUpdateRootRouteRedirect('manage_role');
|
handleUpdateRootRouteRedirect('dashboard');
|
||||||
|
|
||||||
setIsInitAuthRoute(true);
|
setIsInitAuthRoute(true);
|
||||||
} else {
|
} else {
|
||||||
await authStore.resetStore();
|
await authStore.resetStore();
|
||||||
}
|
}
|
||||||
|
tabStore.initHomeTab();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** handle auth routes */
|
/** handle auth routes */
|
||||||
@@ -249,7 +224,7 @@ export const useRouteStore = defineStore(SetupStoreId.Route, () => {
|
|||||||
const redirect = getRoutePath(redirectKey);
|
const redirect = getRoutePath(redirectKey);
|
||||||
|
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
const rootRoute: CustomRoute = { ...ROOT_ROUTE, redirect };
|
const rootRoute: CustomRoute = {...ROOT_ROUTE, redirect};
|
||||||
|
|
||||||
router.removeRoute(rootRoute.name);
|
router.removeRoute(rootRoute.name);
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ function sortRouteByOrder(route: ElegantConstRoute) {
|
|||||||
* @param routes routes
|
* @param routes routes
|
||||||
*/
|
*/
|
||||||
export function sortRoutesByOrder(routes: ElegantConstRoute[]) {
|
export function sortRoutesByOrder(routes: ElegantConstRoute[]) {
|
||||||
routes.sort((next, prev) => (Number(next.meta?.order) || 0) - (Number(prev.meta?.order) || 0));
|
routes.sort((next, prev) => (Number(next.meta?.order) || 1) - (Number(prev.meta?.order) || 1));
|
||||||
routes.forEach(sortRouteByOrder);
|
routes.forEach(sortRouteByOrder);
|
||||||
|
|
||||||
return routes;
|
return routes;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { computed, effectScope, onScopeDispose, ref, toRefs, watch } from 'vue';
|
import { computed, effectScope, onScopeDispose, ref, toRefs, watch } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { useEventListener, usePreferredColorScheme } from '@vueuse/core';
|
import { usePreferredColorScheme } from '@vueuse/core';
|
||||||
import { SetupStoreId } from '@/enum';
|
import { SetupStoreId } from '@/enum';
|
||||||
import { localStg } from '@/utils/storage';
|
import { localStg } from '@/utils/storage';
|
||||||
import { addThemeVarsToHtml, createThemeToken, getAntdTheme, initThemeSettings, toggleCssDarkMode } from './shared';
|
import { addThemeVarsToHtml, createThemeToken, getAntdTheme, initThemeSettings, toggleCssDarkMode } from './shared';
|
||||||
@@ -102,18 +102,18 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Cache theme settings */
|
/** Cache theme settings */
|
||||||
function cacheThemeSettings() {
|
// function cacheThemeSettings() {
|
||||||
const isProd = import.meta.env.PROD;
|
// const isProd = import.meta.env.PROD;
|
||||||
|
//
|
||||||
if (!isProd) return;
|
// if (!isProd) return;
|
||||||
|
//
|
||||||
localStg.set('themeSettings', settings.value);
|
// localStg.set('themeSettings', settings.value);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// cache theme settings when page is closed or refreshed
|
// // cache theme settings when page is closed or refreshed
|
||||||
useEventListener(window, 'beforeunload', () => {
|
// useEventListener(window, 'beforeunload', () => {
|
||||||
cacheThemeSettings();
|
// cacheThemeSettings();
|
||||||
});
|
// });
|
||||||
|
|
||||||
// watch store
|
// watch store
|
||||||
scope.run(() => {
|
scope.run(() => {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ const DARK_CLASS = 'dark';
|
|||||||
|
|
||||||
/** Init theme settings */
|
/** Init theme settings */
|
||||||
export function initThemeSettings() {
|
export function initThemeSettings() {
|
||||||
|
return themeSettings; // 直接使用默认设置 src/store/modules/theme/index.ts 注释104行Cache theme settings相关
|
||||||
|
|
||||||
const isProd = import.meta.env.PROD;
|
const isProd = import.meta.env.PROD;
|
||||||
|
|
||||||
// if it is development mode, the theme settings will not be cached, by update `themeSettings` in `src/theme/settings.ts` to update theme settings
|
// if it is development mode, the theme settings will not be cached, by update `themeSettings` in `src/theme/settings.ts` to update theme settings
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/** Default theme settings */
|
/** Default theme settings */
|
||||||
export const themeSettings: App.Theme.ThemeSetting = {
|
export const themeSettings: App.Theme.ThemeSetting = {
|
||||||
themeScheme: 'light',
|
themeScheme: 'auto',
|
||||||
themeColor: '#646cff',
|
themeColor: '#3B82F6',
|
||||||
otherColor: { info: '#2080f0', success: '#52c41a', warning: '#faad14', error: '#f5222d' },
|
otherColor: { info: '#3B82F6', success: '#52c41a', warning: '#faad14', error: '#f5222d' },
|
||||||
isInfoFollowPrimary: true,
|
isInfoFollowPrimary: true,
|
||||||
layout: { mode: 'horizontal-mix', scrollMode: 'content' },
|
layout: { mode: 'horizontal-mix', scrollMode: 'content' },
|
||||||
page: { animate: true, animateMode: 'fade-slide' },
|
page: { animate: true, animateMode: 'fade-slide' },
|
||||||
|
|||||||
Vendored
+590
-1
@@ -81,7 +81,6 @@ declare namespace Api {
|
|||||||
interface UserInfo {
|
interface UserInfo {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
roles: string[];
|
roles: string[];
|
||||||
buttons: string[];
|
|
||||||
/** permissions */
|
/** permissions */
|
||||||
permissions: string[];
|
permissions: string[];
|
||||||
}
|
}
|
||||||
@@ -152,6 +151,126 @@ declare namespace Api {
|
|||||||
interface EmailCaptcha{
|
interface EmailCaptcha{
|
||||||
email:string;
|
email:string;
|
||||||
}
|
}
|
||||||
|
interface CheckBody{
|
||||||
|
username?: string;
|
||||||
|
email?: string;
|
||||||
|
phonenumber?:string;
|
||||||
|
authType: string;
|
||||||
|
}
|
||||||
|
interface RateLimit {
|
||||||
|
id: number;
|
||||||
|
rateLimitName: string;
|
||||||
|
upLimit: number;
|
||||||
|
downLimit: number;
|
||||||
|
upLimitEnable: boolean;
|
||||||
|
downLimitEnable: boolean;
|
||||||
|
createBy: number;
|
||||||
|
createTime: string;
|
||||||
|
updateBy: number;
|
||||||
|
updateTime: string;
|
||||||
|
delFlag: boolean;
|
||||||
|
}
|
||||||
|
interface RateLimitAdd {
|
||||||
|
rateLimitName: string;
|
||||||
|
upLimitEnable: boolean;
|
||||||
|
downLimitEnable: boolean;
|
||||||
|
upLimit: number;
|
||||||
|
downLimit: number;
|
||||||
|
}
|
||||||
|
interface Package {
|
||||||
|
id: string;
|
||||||
|
packageName: string;
|
||||||
|
periodNum: number;
|
||||||
|
periodType: number;
|
||||||
|
price: string;
|
||||||
|
trafficEnable: boolean;
|
||||||
|
traffic: number;
|
||||||
|
rateLimitEnable: boolean;
|
||||||
|
rateLimitId?: number;
|
||||||
|
durationEnable: boolean;
|
||||||
|
duration: number;
|
||||||
|
clientNumEnable: boolean;
|
||||||
|
clientNum: number;
|
||||||
|
packageEnable: boolean;
|
||||||
|
createBy: number;
|
||||||
|
createTime: string;
|
||||||
|
updateBy: number;
|
||||||
|
updateTime: string;
|
||||||
|
delFlag: boolean;
|
||||||
|
}
|
||||||
|
interface PackageAdd {
|
||||||
|
packageName: string;
|
||||||
|
periodNum: number;
|
||||||
|
periodType: number;
|
||||||
|
price: string;
|
||||||
|
trafficEnable: boolean;
|
||||||
|
traffic: number;
|
||||||
|
rateLimitEnable: boolean;
|
||||||
|
rateLimitId?: number;
|
||||||
|
durationEnable: boolean;
|
||||||
|
duration: number;
|
||||||
|
clientNumEnable: boolean;
|
||||||
|
clientNum: number;
|
||||||
|
packageEnable: boolean;
|
||||||
|
}
|
||||||
|
// CDR 话单查询参数
|
||||||
|
interface CdrHistoryParams {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
userName?: string;
|
||||||
|
clientName?: string;
|
||||||
|
clientMac?: string;
|
||||||
|
startTime?: string;
|
||||||
|
endTime?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CDR 话单信息
|
||||||
|
interface CdrHistory {
|
||||||
|
id: string;
|
||||||
|
userId: number;
|
||||||
|
userName: string;
|
||||||
|
clientName: string;
|
||||||
|
clientMac: string;
|
||||||
|
trafficUp: number;
|
||||||
|
trafficDown: number;
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
duration: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CDR 话单响应
|
||||||
|
interface CdrHistoryResponse {
|
||||||
|
rows: CdrHistory[];
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账单查询参数
|
||||||
|
interface BillParams {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
userName?: string;
|
||||||
|
type?: number;
|
||||||
|
status?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账单信息
|
||||||
|
interface BillInfo {
|
||||||
|
id: string;
|
||||||
|
userId: number;
|
||||||
|
userName: string;
|
||||||
|
type: number;
|
||||||
|
packageName: string;
|
||||||
|
orderAmount: number;
|
||||||
|
status: number;
|
||||||
|
createTime: string;
|
||||||
|
updateTime: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 账单响应
|
||||||
|
interface BillResponse {
|
||||||
|
rows: BillInfo[];
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -418,4 +537,474 @@ declare namespace Api {
|
|||||||
|
|
||||||
type DictList = Common.PaginatingQueryRecord<Dict>;
|
type DictList = Common.PaginatingQueryRecord<Dict>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
interface ApDevice {
|
||||||
|
mac: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
subtype: string | null;
|
||||||
|
deviceSeriesType: number;
|
||||||
|
model: string;
|
||||||
|
ip: string;
|
||||||
|
ipv6: string | null;
|
||||||
|
uptime: string;
|
||||||
|
status: number;
|
||||||
|
lastSeen: number;
|
||||||
|
cpuUtil: number;
|
||||||
|
memUtil: number;
|
||||||
|
sn: string;
|
||||||
|
licenseStatus: number;
|
||||||
|
tagName: string | null;
|
||||||
|
uplinkDeviceMac: string | null;
|
||||||
|
uplinkDeviceName: string | null;
|
||||||
|
uplinkDevicePort: string | null;
|
||||||
|
linkSpeed: string | null;
|
||||||
|
duplex: string | null;
|
||||||
|
switchConsistent: boolean;
|
||||||
|
publicIp: string;
|
||||||
|
firmwareVersion: string;
|
||||||
|
}
|
||||||
|
interface ApDeviceListData {
|
||||||
|
total: number;
|
||||||
|
rows: ApDevice[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApDeviceResponse {
|
||||||
|
code: number;
|
||||||
|
msg: string;
|
||||||
|
data: ApDeviceListData;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApDeviceParams {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
name?: string;
|
||||||
|
mac?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface TerminalDevice {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
ip: string;
|
||||||
|
authStatus: number;
|
||||||
|
ssid: string;
|
||||||
|
apName: string;
|
||||||
|
activity: number;
|
||||||
|
trafficDown: number;
|
||||||
|
trafficUp: number;
|
||||||
|
uptime: number;
|
||||||
|
mac:string;
|
||||||
|
createBy: string | null;
|
||||||
|
createTime: string;
|
||||||
|
updateBy: string | null;
|
||||||
|
updateTime: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type TerminalDeviceResponse = App.Service.Response<TerminalDevice[]>;
|
||||||
|
|
||||||
|
interface TerminalDeviceParams {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
clientName?: string;
|
||||||
|
clientDeviceType?: string;
|
||||||
|
clientMac?: string;
|
||||||
|
}
|
||||||
|
/** AP设备添加参数 */
|
||||||
|
interface AddApDeviceItem {
|
||||||
|
sn?: string;
|
||||||
|
name?: string;
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
|
}
|
||||||
|
interface AddApDeviceParams {
|
||||||
|
devices: AddApDeviceItem[];
|
||||||
|
}
|
||||||
|
interface ApDeviceLocation {
|
||||||
|
longitude: number;
|
||||||
|
latitude: number;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApDeviceConfigData {
|
||||||
|
name: string;
|
||||||
|
ledSetting: number;
|
||||||
|
tagIds: string[];
|
||||||
|
location: ApDeviceLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApDeviceConfigResponse {
|
||||||
|
code: number;
|
||||||
|
msg: string;
|
||||||
|
data: {
|
||||||
|
name: string;
|
||||||
|
ledSetting: number;
|
||||||
|
tagIds: string[];
|
||||||
|
location: {
|
||||||
|
longitude: number;
|
||||||
|
latitude: number;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
}|null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ApDeviceConfigUpdate {
|
||||||
|
name?: string;
|
||||||
|
ledSetting?: number;
|
||||||
|
tagIds?: string[];
|
||||||
|
location?: {
|
||||||
|
longitude?: number;
|
||||||
|
latitude?: number;
|
||||||
|
address?: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interface ApDeviceConfigForm {
|
||||||
|
name: string;
|
||||||
|
ledSetting: number;
|
||||||
|
tagIds?: string[];
|
||||||
|
longitude?: number;
|
||||||
|
latitude?: number;
|
||||||
|
address?: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Billing {
|
||||||
|
interface BillRule {
|
||||||
|
id: number;
|
||||||
|
traffic: number;
|
||||||
|
price: number;
|
||||||
|
unit: number;
|
||||||
|
enable: boolean;
|
||||||
|
createBy: string | null;
|
||||||
|
createTime: string;
|
||||||
|
updateBy: string | null;
|
||||||
|
updateTime: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type BillRuleResponse = App.Service.Response<BillRule[]>;
|
||||||
|
|
||||||
|
interface BillRuleUpdate {
|
||||||
|
traffic: number;
|
||||||
|
price: number;
|
||||||
|
unit: number;
|
||||||
|
enable: boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface DashboardOverview {
|
||||||
|
cloud: {
|
||||||
|
connected: boolean;
|
||||||
|
};
|
||||||
|
siteNum: number;
|
||||||
|
totalGatewayNum: number;
|
||||||
|
connectedGatewayNum: number;
|
||||||
|
disconnectedGatewayNum: number;
|
||||||
|
totalSwitchNum: number;
|
||||||
|
connectedSwitchNum: number;
|
||||||
|
disconnectedSwitchNum: number;
|
||||||
|
totalApNum: number;
|
||||||
|
connectedApNum: number;
|
||||||
|
disconnectedApNum: number;
|
||||||
|
isolatedApNum: number;
|
||||||
|
totalClientNum: number;
|
||||||
|
wiredClientNum: number;
|
||||||
|
wirelessClientNum: number;
|
||||||
|
guestNum: number;
|
||||||
|
registerUserNum: number;
|
||||||
|
onlineUserNum: number;
|
||||||
|
}
|
||||||
|
interface DashboardSite {
|
||||||
|
siteId: string;
|
||||||
|
name: string;
|
||||||
|
region: string;
|
||||||
|
tagIds: string[];
|
||||||
|
timeZone: string;
|
||||||
|
scenario: string;
|
||||||
|
totalGatewayNum: number;
|
||||||
|
connectedGatewayNum: number;
|
||||||
|
disconnectedGatewayNum: number;
|
||||||
|
totalSwitchNum: number;
|
||||||
|
connectedSwitchNum: number;
|
||||||
|
disconnectedSwitchNum: number;
|
||||||
|
totalApNum: number;
|
||||||
|
connectedApNum: number;
|
||||||
|
disconnectedApNum: number;
|
||||||
|
isolatedApNum: number;
|
||||||
|
totalClientNum: number;
|
||||||
|
wiredClientNum: number;
|
||||||
|
wirelessClientNum: number;
|
||||||
|
guestNum: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface DashboardSiteResponse {
|
||||||
|
rows: DashboardSite[];
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
namespace Kyc {
|
||||||
|
interface KycInfo {
|
||||||
|
id: string;
|
||||||
|
userId: number;
|
||||||
|
userName: string;
|
||||||
|
realName: string;
|
||||||
|
idType: string;
|
||||||
|
idFile: string;
|
||||||
|
identifyPicture: string;
|
||||||
|
status: string;
|
||||||
|
reason?: string;
|
||||||
|
createTime: string;
|
||||||
|
updateTime: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KycParams {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
userName?: string;
|
||||||
|
status?: string;
|
||||||
|
createTimeStart?: string;
|
||||||
|
createTimeEnd?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KycResponse {
|
||||||
|
rows: KycInfo[];
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace Site {
|
||||||
|
interface SiteInfo {
|
||||||
|
siteId: string;
|
||||||
|
name: string;
|
||||||
|
tagIds: string[];
|
||||||
|
region: string;
|
||||||
|
timeZone: string;
|
||||||
|
scenario: string;
|
||||||
|
longitude: number | null;
|
||||||
|
latitude: number | null;
|
||||||
|
address: string | null;
|
||||||
|
type: number;
|
||||||
|
supportES: boolean;
|
||||||
|
supportL2: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddSiteParams {
|
||||||
|
name: string;
|
||||||
|
region: string;
|
||||||
|
timeZone: string;
|
||||||
|
scenario: string;
|
||||||
|
deviceAccountSetting: {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface SiteConfig {
|
||||||
|
name: string;
|
||||||
|
region: string;
|
||||||
|
timeZone: string;
|
||||||
|
scenario: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSiteParams {
|
||||||
|
name: string;
|
||||||
|
region: string;
|
||||||
|
timeZone: string;
|
||||||
|
scenario: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SiteParams {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SiteListData {
|
||||||
|
total: number;
|
||||||
|
rows: SiteInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type SiteResponse = App.Service.ApiResponse<{
|
||||||
|
rows: SiteInfo[];
|
||||||
|
total: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Wlan {
|
||||||
|
interface WlanGroup {
|
||||||
|
wlanId: string;
|
||||||
|
wlanName: string;
|
||||||
|
ssidList: SsidInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type WlanGroupResponse = App.Service.ApiResponse<WlanGroup[]>;
|
||||||
|
|
||||||
|
interface WlanSsid {
|
||||||
|
ssidId: string;
|
||||||
|
name: string;
|
||||||
|
deviceType: number;
|
||||||
|
band: number;
|
||||||
|
guestNetEnable: boolean;
|
||||||
|
security: number;
|
||||||
|
broadcast: boolean;
|
||||||
|
vlanEnable: boolean;
|
||||||
|
vlanId: number | null;
|
||||||
|
mloEnable?: boolean;
|
||||||
|
pmfMode?: number;
|
||||||
|
enable11r?: boolean;
|
||||||
|
hidePwd?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WlanSsidConfigResponse extends App.Service.ApiResponse<WlanSsid> {}
|
||||||
|
|
||||||
|
interface WlanSsidResponse extends App.Service.ApiResponse<{
|
||||||
|
rows: WlanSsid[];
|
||||||
|
total: number;
|
||||||
|
}>{}
|
||||||
|
|
||||||
|
interface WlanSsidParams {
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
}
|
||||||
|
interface AddWlanSsidParams {
|
||||||
|
name: string;
|
||||||
|
deviceType: number;
|
||||||
|
band: number;
|
||||||
|
guestNetEnable: boolean;
|
||||||
|
security: number;
|
||||||
|
broadcast: boolean;
|
||||||
|
vlanEnable: boolean;
|
||||||
|
vlanId?: number;
|
||||||
|
pskSetting:{
|
||||||
|
securityKey:string;
|
||||||
|
versionPsk:number;
|
||||||
|
encryptionPsk:number;
|
||||||
|
gikRekeyPskEnable:boolean;
|
||||||
|
};
|
||||||
|
// 固定值字段
|
||||||
|
mloEnable: false;
|
||||||
|
pmfMode: 1;
|
||||||
|
enable11r: false;
|
||||||
|
hidePwd: false;
|
||||||
|
greEnable: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单数据类型
|
||||||
|
interface WlanSsidForm {
|
||||||
|
name: string;
|
||||||
|
deviceType: {
|
||||||
|
eap: boolean;
|
||||||
|
gateway: boolean;
|
||||||
|
};
|
||||||
|
band: {
|
||||||
|
band24G: boolean;
|
||||||
|
band5G: boolean;
|
||||||
|
band6G: boolean;
|
||||||
|
};
|
||||||
|
password:string;
|
||||||
|
guestNetEnable: boolean;
|
||||||
|
security: number;
|
||||||
|
pskSetting:{
|
||||||
|
securityKey:string;
|
||||||
|
versionPsk:number;
|
||||||
|
encryptionPsk:number;
|
||||||
|
gikRekeyPskEnable:boolean;
|
||||||
|
};
|
||||||
|
broadcast: boolean;
|
||||||
|
vlanEnable: boolean;
|
||||||
|
vlanId?: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
namespace Portal {
|
||||||
|
interface Portal {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
enable: boolean;
|
||||||
|
ssidNames: string[];
|
||||||
|
ssidList: string[];
|
||||||
|
networkList: string[];
|
||||||
|
authType: number;
|
||||||
|
hotspotTypes: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface PortalResponse extends App.Service.ApiResponse<{
|
||||||
|
rows: Portal[];
|
||||||
|
total: number;
|
||||||
|
}> {}
|
||||||
|
}
|
||||||
|
namespace Portal {
|
||||||
|
// 先定义基础类型
|
||||||
|
interface SsidInfo {
|
||||||
|
ssidId: string;
|
||||||
|
ssidName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WlanGroup {
|
||||||
|
wlanId: string;
|
||||||
|
wlanName: string;
|
||||||
|
ssidList: SsidInfo[];
|
||||||
|
}
|
||||||
|
interface Portal {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
enable: boolean;
|
||||||
|
ssidNames: string[];
|
||||||
|
ssidList: string[];
|
||||||
|
networkList: string[];
|
||||||
|
authType: number;
|
||||||
|
hotspotTypes: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface PortalResponse extends App.Service.ApiResponse<{
|
||||||
|
rows: Portal[];
|
||||||
|
total: number;
|
||||||
|
}> {}
|
||||||
|
|
||||||
|
|
||||||
|
interface SsidListResponse extends App.Service.ApiResponse<WlanGroup[]> {}
|
||||||
|
|
||||||
|
interface AuthTimeout {
|
||||||
|
customTimeout: number;
|
||||||
|
customTimeoutUnit: 1 | 2 | 3; // 1:分钟 2:小时 3:天
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NoAuth {
|
||||||
|
dailyLimitEnable: boolean;
|
||||||
|
}
|
||||||
|
interface ExternalPortal {
|
||||||
|
hostType: 1 | 2; // 1: IP地址 2: URL
|
||||||
|
serverUrl: string; // IP地址或URL值
|
||||||
|
serverUrlScheme?: string; // URL时的协议类型
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportedPortalPage {
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AddPortalParams {
|
||||||
|
name: string;
|
||||||
|
enable: boolean;
|
||||||
|
ssidList: string[];
|
||||||
|
authType: number;
|
||||||
|
authTimeout: AuthTimeout;
|
||||||
|
noAuth: NoAuth;
|
||||||
|
httpsRedirectEnable: boolean;
|
||||||
|
landingPage: 1 | 2 | 3;
|
||||||
|
landingUrlScheme?: string;
|
||||||
|
landingUrl?: string;
|
||||||
|
externalPortal?: ExternalPortal; // 添加外部Portal配置
|
||||||
|
pageType: number;
|
||||||
|
importedPortalPage: ImportedPortalPage;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare namespace App {
|
||||||
|
namespace Service {
|
||||||
|
interface ApiResponse<T = any> {
|
||||||
|
data: T;
|
||||||
|
error: any;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Vendored
+1
-402
@@ -243,408 +243,7 @@ declare namespace App {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type Schema = {
|
type Schema = {
|
||||||
system: {
|
[key: string]: string;
|
||||||
title: string;
|
|
||||||
};
|
|
||||||
common: {
|
|
||||||
action: string;
|
|
||||||
add: string;
|
|
||||||
addSuccess: string;
|
|
||||||
backToHome: string;
|
|
||||||
batchDelete: string;
|
|
||||||
cancel: string;
|
|
||||||
close: string;
|
|
||||||
check: string;
|
|
||||||
columnSetting: string;
|
|
||||||
config: string;
|
|
||||||
confirm: string;
|
|
||||||
delete: string;
|
|
||||||
deleteSuccess: string;
|
|
||||||
confirmDelete: string;
|
|
||||||
edit: string;
|
|
||||||
index: string;
|
|
||||||
keywordSearch: string;
|
|
||||||
logout: string;
|
|
||||||
logoutConfirm: string;
|
|
||||||
lookForward: string;
|
|
||||||
modify: string;
|
|
||||||
modifySuccess: string;
|
|
||||||
noData: string;
|
|
||||||
operate: string;
|
|
||||||
pleaseCheckValue: string;
|
|
||||||
refresh: string;
|
|
||||||
reset: string;
|
|
||||||
search: string;
|
|
||||||
switch: string;
|
|
||||||
tip: string;
|
|
||||||
trigger: string;
|
|
||||||
update: string;
|
|
||||||
updateSuccess: string;
|
|
||||||
userCenter: string;
|
|
||||||
yesOrNo: {
|
|
||||||
yes: string;
|
|
||||||
no: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
request: {
|
|
||||||
logout: string;
|
|
||||||
logoutMsg: string;
|
|
||||||
logoutWithModal: string;
|
|
||||||
logoutWithModalMsg: string;
|
|
||||||
refreshToken: string;
|
|
||||||
tokenExpired: string;
|
|
||||||
};
|
|
||||||
theme: {
|
|
||||||
themeSchema: { title: string } & Record<UnionKey.ThemeScheme, string>;
|
|
||||||
layoutMode: { title: string } & Record<UnionKey.ThemeLayoutMode, string>;
|
|
||||||
themeColor: {
|
|
||||||
title: string;
|
|
||||||
followPrimary: string;
|
|
||||||
} & Theme.ThemeColor;
|
|
||||||
scrollMode: { title: string } & Record<UnionKey.ThemeScrollMode, string>;
|
|
||||||
page: {
|
|
||||||
animate: string;
|
|
||||||
mode: { title: string } & Record<UnionKey.ThemePageAnimateMode, string>;
|
|
||||||
};
|
|
||||||
fixedHeaderAndTab: string;
|
|
||||||
header: {
|
|
||||||
height: string;
|
|
||||||
breadcrumb: {
|
|
||||||
visible: string;
|
|
||||||
showIcon: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
tab: {
|
|
||||||
visible: string;
|
|
||||||
cache: string;
|
|
||||||
height: string;
|
|
||||||
mode: { title: string } & Record<UnionKey.ThemeTabMode, string>;
|
|
||||||
};
|
|
||||||
sider: {
|
|
||||||
inverted: string;
|
|
||||||
width: string;
|
|
||||||
collapsedWidth: string;
|
|
||||||
mixWidth: string;
|
|
||||||
mixCollapsedWidth: string;
|
|
||||||
mixChildMenuWidth: string;
|
|
||||||
};
|
|
||||||
footer: {
|
|
||||||
visible: string;
|
|
||||||
fixed: string;
|
|
||||||
height: string;
|
|
||||||
right: string;
|
|
||||||
};
|
|
||||||
themeDrawerTitle: string;
|
|
||||||
pageFunTitle: string;
|
|
||||||
configOperation: {
|
|
||||||
copyConfig: string;
|
|
||||||
copySuccessMsg: string;
|
|
||||||
resetConfig: string;
|
|
||||||
resetSuccessMsg: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
route: Record<I18nRouteKey, string>;
|
|
||||||
page: {
|
|
||||||
login: {
|
|
||||||
common: {
|
|
||||||
loginOrRegister: string;
|
|
||||||
userNamePlaceholder: string;
|
|
||||||
phonePlaceholder: string;
|
|
||||||
codePlaceholder: string;
|
|
||||||
passwordPlaceholder: string;
|
|
||||||
confirmPasswordPlaceholder: string;
|
|
||||||
codeLogin: string;
|
|
||||||
confirm: string;
|
|
||||||
back: string;
|
|
||||||
validateSuccess: string;
|
|
||||||
loginSuccess: string;
|
|
||||||
registerSuccess: string;
|
|
||||||
welcomeBack: string;
|
|
||||||
checkCode: string;
|
|
||||||
};
|
|
||||||
pwdLogin: {
|
|
||||||
title: string;
|
|
||||||
rememberMe: string;
|
|
||||||
forgetPassword: string;
|
|
||||||
register: string;
|
|
||||||
otherAccountLogin: string;
|
|
||||||
otherLoginMode: string;
|
|
||||||
superAdmin: string;
|
|
||||||
admin: string;
|
|
||||||
user: string;
|
|
||||||
};
|
|
||||||
codeLogin: {
|
|
||||||
title: string;
|
|
||||||
getCode: string;
|
|
||||||
reGetCode: string;
|
|
||||||
sendCodeSuccess: string;
|
|
||||||
imageCodePlaceholder: string;
|
|
||||||
};
|
|
||||||
register: {
|
|
||||||
title: string;
|
|
||||||
agreement: string;
|
|
||||||
protocol: string;
|
|
||||||
policy: string;
|
|
||||||
};
|
|
||||||
resetPwd: {
|
|
||||||
title: string;
|
|
||||||
};
|
|
||||||
bindWeChat: {
|
|
||||||
title: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
about: {
|
|
||||||
title: string;
|
|
||||||
introduction: string;
|
|
||||||
projectInfo: {
|
|
||||||
title: string;
|
|
||||||
version: string;
|
|
||||||
latestBuildTime: string;
|
|
||||||
githubLink: string;
|
|
||||||
previewLink: string;
|
|
||||||
};
|
|
||||||
prdDep: string;
|
|
||||||
devDep: string;
|
|
||||||
};
|
|
||||||
home: {
|
|
||||||
greeting: string;
|
|
||||||
weatherDesc: string;
|
|
||||||
projectCount: string;
|
|
||||||
todo: string;
|
|
||||||
message: string;
|
|
||||||
downloadCount: string;
|
|
||||||
registerCount: string;
|
|
||||||
schedule: string;
|
|
||||||
study: string;
|
|
||||||
work: string;
|
|
||||||
rest: string;
|
|
||||||
entertainment: string;
|
|
||||||
visitCount: string;
|
|
||||||
turnover: string;
|
|
||||||
dealCount: string;
|
|
||||||
projectNews: {
|
|
||||||
title: string;
|
|
||||||
moreNews: string;
|
|
||||||
desc1: string;
|
|
||||||
desc2: string;
|
|
||||||
desc3: string;
|
|
||||||
desc4: string;
|
|
||||||
desc5: string;
|
|
||||||
};
|
|
||||||
creativity: string;
|
|
||||||
};
|
|
||||||
function: {
|
|
||||||
tab: {
|
|
||||||
tabOperate: {
|
|
||||||
title: string;
|
|
||||||
addTab: string;
|
|
||||||
addTabDesc: string;
|
|
||||||
closeTab: string;
|
|
||||||
closeCurrentTab: string;
|
|
||||||
closeAboutTab: string;
|
|
||||||
addMultiTab: string;
|
|
||||||
addMultiTabDesc1: string;
|
|
||||||
addMultiTabDesc2: string;
|
|
||||||
};
|
|
||||||
tabTitle: {
|
|
||||||
title: string;
|
|
||||||
changeTitle: string;
|
|
||||||
change: string;
|
|
||||||
resetTitle: string;
|
|
||||||
reset: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
multiTab: {
|
|
||||||
routeParam: string;
|
|
||||||
backTab: string;
|
|
||||||
};
|
|
||||||
toggleAuth: {
|
|
||||||
toggleAccount: string;
|
|
||||||
authHook: string;
|
|
||||||
superAdminVisible: string;
|
|
||||||
adminVisible: string;
|
|
||||||
adminOrUserVisible: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
manage: {
|
|
||||||
common: {
|
|
||||||
status: {
|
|
||||||
enable: string;
|
|
||||||
disable: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
role: {
|
|
||||||
title: string;
|
|
||||||
roleName: string;
|
|
||||||
roleCode: string;
|
|
||||||
roleStatus: string;
|
|
||||||
roleDesc: string;
|
|
||||||
form: {
|
|
||||||
roleName: string;
|
|
||||||
roleCode: string;
|
|
||||||
roleStatus: string;
|
|
||||||
roleDesc: string;
|
|
||||||
};
|
|
||||||
addRole: string;
|
|
||||||
editRole: string;
|
|
||||||
menuAuth: string;
|
|
||||||
buttonAuth: string;
|
|
||||||
};
|
|
||||||
user: {
|
|
||||||
userName: string;
|
|
||||||
nickName: string;
|
|
||||||
email: string;
|
|
||||||
phonenumber: string;
|
|
||||||
status: string;
|
|
||||||
dept: string;
|
|
||||||
title: string;
|
|
||||||
addUser: string;
|
|
||||||
remark: string;
|
|
||||||
editUser: string;
|
|
||||||
post: string;
|
|
||||||
role: string;
|
|
||||||
password: string;
|
|
||||||
form: {
|
|
||||||
userName: string;
|
|
||||||
email: string;
|
|
||||||
status: string;
|
|
||||||
nickName: string;
|
|
||||||
phonenumber: string;
|
|
||||||
remark: string;
|
|
||||||
password: string;
|
|
||||||
dept: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
menu: {
|
|
||||||
home: string;
|
|
||||||
title: string;
|
|
||||||
id: string;
|
|
||||||
parentId: string;
|
|
||||||
menuType: string;
|
|
||||||
menuName: string;
|
|
||||||
routeName: string;
|
|
||||||
routePath: string;
|
|
||||||
routeParams: string;
|
|
||||||
layout: string;
|
|
||||||
page: string;
|
|
||||||
i18nKey: string;
|
|
||||||
icon: string;
|
|
||||||
localIcon: string;
|
|
||||||
iconTypeTitle: string;
|
|
||||||
order: string;
|
|
||||||
keepAlive: string;
|
|
||||||
href: string;
|
|
||||||
hideInMenu: string;
|
|
||||||
activeMenu: string;
|
|
||||||
multiTab: string;
|
|
||||||
fixedIndexInTab: string;
|
|
||||||
button: string;
|
|
||||||
buttonCode: string;
|
|
||||||
buttonDesc: string;
|
|
||||||
menuStatus: string;
|
|
||||||
form: {
|
|
||||||
home: string;
|
|
||||||
menuType: string;
|
|
||||||
menuName: string;
|
|
||||||
routeName: string;
|
|
||||||
routePath: string;
|
|
||||||
layout: string;
|
|
||||||
page: string;
|
|
||||||
i18nKey: string;
|
|
||||||
icon: string;
|
|
||||||
localIcon: string;
|
|
||||||
order: string;
|
|
||||||
keepAlive: string;
|
|
||||||
href: string;
|
|
||||||
hideInMenu: string;
|
|
||||||
activeMenu: string;
|
|
||||||
multiTab: string;
|
|
||||||
fixedInTab: string;
|
|
||||||
fixedIndexInTab: string;
|
|
||||||
button: string;
|
|
||||||
buttonCode: string;
|
|
||||||
buttonDesc: string;
|
|
||||||
menuStatus: string;
|
|
||||||
};
|
|
||||||
addMenu: string;
|
|
||||||
editMenu: string;
|
|
||||||
addChildMenu: string;
|
|
||||||
type: {
|
|
||||||
directory: string;
|
|
||||||
menu: string;
|
|
||||||
};
|
|
||||||
iconType: {
|
|
||||||
iconify: string;
|
|
||||||
local: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
dept: {
|
|
||||||
deptName: string;
|
|
||||||
leader: string;
|
|
||||||
status: string;
|
|
||||||
form: {
|
|
||||||
deptName: string;
|
|
||||||
leader: string;
|
|
||||||
status: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
post: {
|
|
||||||
addPost: string;
|
|
||||||
editPost: string;
|
|
||||||
postName: string;
|
|
||||||
postCode: string;
|
|
||||||
postSort: string;
|
|
||||||
status: string;
|
|
||||||
remark: string;
|
|
||||||
title: string;
|
|
||||||
form: {
|
|
||||||
postName: string;
|
|
||||||
postCode: string;
|
|
||||||
postSort: string;
|
|
||||||
remark: string;
|
|
||||||
status: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
dict: {
|
|
||||||
title: string;
|
|
||||||
dictName: string;
|
|
||||||
dictType: string;
|
|
||||||
status: string;
|
|
||||||
remark: string;
|
|
||||||
form: {
|
|
||||||
dictName: string;
|
|
||||||
dictType: string;
|
|
||||||
status: string;
|
|
||||||
remark: string;
|
|
||||||
};
|
|
||||||
addDict: string;
|
|
||||||
editDict: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
form: {
|
|
||||||
required: string;
|
|
||||||
username: FormMsg;
|
|
||||||
phone: FormMsg;
|
|
||||||
pwd: FormMsg;
|
|
||||||
confirmPwd: FormMsg;
|
|
||||||
code: FormMsg;
|
|
||||||
email: FormMsg;
|
|
||||||
};
|
|
||||||
dropdown: Record<Global.DropdownKey, string>;
|
|
||||||
icon: {
|
|
||||||
themeConfig: string;
|
|
||||||
themeSchema: string;
|
|
||||||
lang: string;
|
|
||||||
fullscreen: string;
|
|
||||||
fullscreenExit: string;
|
|
||||||
reload: string;
|
|
||||||
collapse: string;
|
|
||||||
expand: string;
|
|
||||||
pin: string;
|
|
||||||
unpin: string;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type GetI18nKey<T extends Record<string, unknown>, K extends keyof T = keyof T> = K extends string
|
type GetI18nKey<T extends Record<string, unknown>, K extends keyof T = keyof T> = K extends string
|
||||||
|
|||||||
Vendored
+112
-1
@@ -10,17 +10,30 @@ declare global {
|
|||||||
const $notification: typeof import('ant-design-vue')['notification']
|
const $notification: typeof import('ant-design-vue')['notification']
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
const EffectScope: typeof import('vue')['EffectScope']
|
||||||
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
||||||
|
const addApDevice: typeof import('../service/api/auth')['addApDevice']
|
||||||
|
const addData: typeof import('../service/api/dictData')['addData']
|
||||||
|
const addJob: typeof import('../service/api/job')['addJob']
|
||||||
|
const addPackage: typeof import('../service/api/auth')['addPackage']
|
||||||
|
const addPortal: typeof import('../service/api/auth')['addPortal']
|
||||||
|
const addRateLimit: typeof import('../service/api/auth')['addRateLimit']
|
||||||
|
const addSite: typeof import('../service/api/auth')['addSite']
|
||||||
const addThemeVarsToHtml: typeof import('../store/modules/theme/shared')['addThemeVarsToHtml']
|
const addThemeVarsToHtml: typeof import('../store/modules/theme/shared')['addThemeVarsToHtml']
|
||||||
|
const addWlanSsid: typeof import('../service/api/auth')['addWlanSsid']
|
||||||
|
const adoptApDevice: typeof import('../service/api/auth')['adoptApDevice']
|
||||||
const afterAll: typeof import('vitest')['afterAll']
|
const afterAll: typeof import('vitest')['afterAll']
|
||||||
const afterEach: typeof import('vitest')['afterEach']
|
const afterEach: typeof import('vitest')['afterEach']
|
||||||
|
const approveKyc: typeof import('../service/api/auth')['approveKyc']
|
||||||
const assert: typeof import('vitest')['assert']
|
const assert: typeof import('vitest')['assert']
|
||||||
const assign: typeof import('lodash-es')['assign']
|
const assign: typeof import('lodash-es')['assign']
|
||||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
||||||
|
const bandwidthFactors: typeof import('../utils/units')['bandwidthFactors']
|
||||||
|
const bandwidthUnits: typeof import('../utils/units')['bandwidthUnits']
|
||||||
const beforeAll: typeof import('vitest')['beforeAll']
|
const beforeAll: typeof import('vitest')['beforeAll']
|
||||||
const beforeEach: typeof import('vitest')['beforeEach']
|
const beforeEach: typeof import('vitest')['beforeEach']
|
||||||
const chai: typeof import('vitest')['chai']
|
const chai: typeof import('vitest')['chai']
|
||||||
const checkReport: typeof import('../service/api/auth')['checkReport']
|
const changeJobStatus: typeof import('../service/api/job')['changeJobStatus']
|
||||||
|
const cleanJobLog: typeof import('../service/api/jobLog')['cleanJobLog']
|
||||||
const clearAuthStorage: typeof import('../store/modules/auth/shared')['clearAuthStorage']
|
const clearAuthStorage: typeof import('../store/modules/auth/shared')['clearAuthStorage']
|
||||||
const cloneDeep: typeof import('lodash-es')['cloneDeep']
|
const cloneDeep: typeof import('lodash-es')['cloneDeep']
|
||||||
const computed: typeof import('vue')['computed']
|
const computed: typeof import('vue')['computed']
|
||||||
@@ -30,6 +43,9 @@ declare global {
|
|||||||
const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
|
const computedWithControl: typeof import('@vueuse/core')['computedWithControl']
|
||||||
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
|
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
|
||||||
const controlledRef: typeof import('@vueuse/core')['controlledRef']
|
const controlledRef: typeof import('@vueuse/core')['controlledRef']
|
||||||
|
const convertBandwidth: typeof import('../utils/units')['convertBandwidth']
|
||||||
|
const convertStorage: typeof import('../utils/units')['convertStorage']
|
||||||
|
const convertTime: typeof import('../utils/units')['convertTime']
|
||||||
const createApp: typeof import('vue')['createApp']
|
const createApp: typeof import('vue')['createApp']
|
||||||
const createEventHook: typeof import('@vueuse/core')['createEventHook']
|
const createEventHook: typeof import('@vueuse/core')['createEventHook']
|
||||||
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
|
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
|
||||||
@@ -48,13 +64,26 @@ declare global {
|
|||||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||||
const defineComponent: typeof import('vue')['defineComponent']
|
const defineComponent: typeof import('vue')['defineComponent']
|
||||||
const defineStore: typeof import('pinia')['defineStore']
|
const defineStore: typeof import('pinia')['defineStore']
|
||||||
|
const delData: typeof import('../service/api/dictData')['delData']
|
||||||
|
const delJobLog: typeof import('../service/api/job')['delJobLog']
|
||||||
|
const deleteAlerts: typeof import('../service/api/auth')['deleteAlerts']
|
||||||
|
const deleteApDevices: typeof import('../service/api/auth')['deleteApDevices']
|
||||||
|
const deletePackage: typeof import('../service/api/auth')['deletePackage']
|
||||||
|
const deletePortal: typeof import('../service/api/auth')['deletePortal']
|
||||||
|
const deleteSite: typeof import('../service/api/auth')['deleteSite']
|
||||||
|
const deleteWlanSsid: typeof import('../service/api/auth')['deleteWlanSsid']
|
||||||
const describe: typeof import('vitest')['describe']
|
const describe: typeof import('vitest')['describe']
|
||||||
|
const dict: typeof import('../store/modules/dict/index')['default']
|
||||||
const doAddDept: typeof import('../service/api/dept')['doAddDept']
|
const doAddDept: typeof import('../service/api/dept')['doAddDept']
|
||||||
const doAddDict: typeof import('../service/api/dict')['doAddDict']
|
const doAddDict: typeof import('../service/api/dict')['doAddDict']
|
||||||
const doAddMenu: typeof import('../service/api/menu')['doAddMenu']
|
const doAddMenu: typeof import('../service/api/menu')['doAddMenu']
|
||||||
const doAddPost: typeof import('../service/api/post')['doAddPost']
|
const doAddPost: typeof import('../service/api/post')['doAddPost']
|
||||||
|
const doCheckUserRepeat: typeof import('../service/api/auth')['doCheckUserRepeat']
|
||||||
|
const doCleanJobLog: typeof import('../service/api/jobLog')['doCleanJobLog']
|
||||||
const doDeleteDept: typeof import('../service/api/dept')['doDeleteDept']
|
const doDeleteDept: typeof import('../service/api/dept')['doDeleteDept']
|
||||||
const doDeleteDict: typeof import('../service/api/dict')['doDeleteDict']
|
const doDeleteDict: typeof import('../service/api/dict')['doDeleteDict']
|
||||||
|
const doDeleteJobLog: typeof import('../service/api/jobLog')['doDeleteJobLog']
|
||||||
|
const doDeleteLog: typeof import('../service/api/log')['doDeleteLog']
|
||||||
const doDeleteLogout: typeof import('../service/api/auth')['doDeleteLogout']
|
const doDeleteLogout: typeof import('../service/api/auth')['doDeleteLogout']
|
||||||
const doDeleteMenu: typeof import('../service/api/menu')['doDeleteMenu']
|
const doDeleteMenu: typeof import('../service/api/menu')['doDeleteMenu']
|
||||||
const doDeletePost: typeof import('../service/api/post')['doDeletePost']
|
const doDeletePost: typeof import('../service/api/post')['doDeletePost']
|
||||||
@@ -64,8 +93,10 @@ declare global {
|
|||||||
const doEditDict: typeof import('../service/api/dict')['doEditDict']
|
const doEditDict: typeof import('../service/api/dict')['doEditDict']
|
||||||
const doEditMenu: typeof import('../service/api/menu')['doEditMenu']
|
const doEditMenu: typeof import('../service/api/menu')['doEditMenu']
|
||||||
const doEditPost: typeof import('../service/api/post')['doEditPost']
|
const doEditPost: typeof import('../service/api/post')['doEditPost']
|
||||||
|
const doExportLog: typeof import('../service/api/log')['doExportLog']
|
||||||
const doGetAdminUserPostsAndRoles: typeof import('../service/api/user')['doGetAdminUserPostsAndRoles']
|
const doGetAdminUserPostsAndRoles: typeof import('../service/api/user')['doGetAdminUserPostsAndRoles']
|
||||||
const doGetCheckCode: typeof import('../service/api/auth')['doGetCheckCode']
|
const doGetCheckCode: typeof import('../service/api/auth')['doGetCheckCode']
|
||||||
|
const doGetDataInfo: typeof import('../service/api/dictData')['doGetDataInfo']
|
||||||
const doGetDeptInfo: typeof import('../service/api/dept')['doGetDeptInfo']
|
const doGetDeptInfo: typeof import('../service/api/dept')['doGetDeptInfo']
|
||||||
const doGetDeptList: typeof import('../service/api/dept')['doGetDeptList']
|
const doGetDeptList: typeof import('../service/api/dept')['doGetDeptList']
|
||||||
const doGetDictList: typeof import('../service/api/dict')['doGetDictList']
|
const doGetDictList: typeof import('../service/api/dict')['doGetDictList']
|
||||||
@@ -75,50 +106,99 @@ declare global {
|
|||||||
const doGetPostList: typeof import('../service/api/post')['doGetPostList']
|
const doGetPostList: typeof import('../service/api/post')['doGetPostList']
|
||||||
const doGetRoleList: typeof import('../service/api/role')['doGetRoleList']
|
const doGetRoleList: typeof import('../service/api/role')['doGetRoleList']
|
||||||
const doGetRoleMenuList: typeof import('../service/api/menu')['doGetRoleMenuList']
|
const doGetRoleMenuList: typeof import('../service/api/menu')['doGetRoleMenuList']
|
||||||
|
const doGetType: typeof import('../service/api/dict')['doGetType']
|
||||||
const doGetUserDeptTree: typeof import('../service/api/user')['doGetUserDeptTree']
|
const doGetUserDeptTree: typeof import('../service/api/user')['doGetUserDeptTree']
|
||||||
const doGetUserInfo: typeof import('../service/api/auth')['doGetUserInfo']
|
const doGetUserInfo: typeof import('../service/api/auth')['doGetUserInfo']
|
||||||
const doGetUserList: typeof import('../service/api/user')['doGetUserList']
|
const doGetUserList: typeof import('../service/api/user')['doGetUserList']
|
||||||
const doGetUserPostsAndRoles: typeof import('../service/api/user')['doGetUserPostsAndRoles']
|
const doGetUserPostsAndRoles: typeof import('../service/api/user')['doGetUserPostsAndRoles']
|
||||||
const doGetUserRoutes: typeof import('../service/api/route')['doGetUserRoutes']
|
const doGetUserRoutes: typeof import('../service/api/route')['doGetUserRoutes']
|
||||||
|
const doGetdictDataList: typeof import('../service/api/dictData')['doGetdictDataList']
|
||||||
|
const doGetjobInfo: typeof import('../service/api/job')['doGetjobInfo']
|
||||||
|
const doGetjobList: typeof import('../service/api/job')['doGetjobList']
|
||||||
|
const doGetjobLogInfo: typeof import('../service/api/jobLog')['doGetjobLogInfo']
|
||||||
|
const doGetjobLogList: typeof import('../service/api/jobLog')['doGetjobLogList']
|
||||||
|
const doGetlogList: typeof import('../service/api/log')['doGetlogList']
|
||||||
|
const doGetsysUserList: typeof import('../service/api/user')['doGetsysUserList']
|
||||||
const doPostRole: typeof import('../service/api/role')['doPostRole']
|
const doPostRole: typeof import('../service/api/role')['doPostRole']
|
||||||
const doPostUser: typeof import('../service/api/user')['doPostUser']
|
const doPostUser: typeof import('../service/api/user')['doPostUser']
|
||||||
const doPutRole: typeof import('../service/api/role')['doPutRole']
|
const doPutRole: typeof import('../service/api/role')['doPutRole']
|
||||||
const doPutUser: typeof import('../service/api/user')['doPutUser']
|
const doPutUser: typeof import('../service/api/user')['doPutUser']
|
||||||
|
const doUpdatePwd: typeof import('../service/api/user')['doUpdatePwd']
|
||||||
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
|
||||||
|
const editRateLimit: typeof import('../service/api/auth')['editRateLimit']
|
||||||
const effectScope: typeof import('vue')['effectScope']
|
const effectScope: typeof import('vue')['effectScope']
|
||||||
const emptyInfo: typeof import('../store/modules/auth/shared')['emptyInfo']
|
const emptyInfo: typeof import('../store/modules/auth/shared')['emptyInfo']
|
||||||
const expect: typeof import('vitest')['expect']
|
const expect: typeof import('vitest')['expect']
|
||||||
|
const exportData: typeof import('../service/api/dictData')['exportData']
|
||||||
|
const exportJob: typeof import('../service/api/job')['exportJob']
|
||||||
|
const exportJobLog: typeof import('../service/api/jobLog')['exportJobLog']
|
||||||
const extendRef: typeof import('@vueuse/core')['extendRef']
|
const extendRef: typeof import('@vueuse/core')['extendRef']
|
||||||
const extractTabsByAllRoutes: typeof import('../store/modules/tab/shared')['extractTabsByAllRoutes']
|
const extractTabsByAllRoutes: typeof import('../store/modules/tab/shared')['extractTabsByAllRoutes']
|
||||||
|
const fetchAccessControl: typeof import('../service/api/auth')['fetchAccessControl']
|
||||||
|
const fetchAlertList: typeof import('../service/api/auth')['fetchAlertList']
|
||||||
|
const fetchApDeviceList: typeof import('../service/api/auth')['fetchApDeviceList']
|
||||||
|
const fetchBillList: typeof import('../service/api/auth')['fetchBillList']
|
||||||
|
const fetchBillRuleList: typeof import('../service/api/auth')['fetchBillRuleList']
|
||||||
|
const fetchCdrHistory: typeof import('../service/api/auth')['fetchCdrHistory']
|
||||||
const fetchCustomBackendError: typeof import('../service/api/auth')['fetchCustomBackendError']
|
const fetchCustomBackendError: typeof import('../service/api/auth')['fetchCustomBackendError']
|
||||||
const fetchGetAllPages: typeof import('../service/api/menu')['fetchGetAllPages']
|
const fetchGetAllPages: typeof import('../service/api/menu')['fetchGetAllPages']
|
||||||
const fetchGetConstantRoutes: typeof import('../service/api/route')['fetchGetConstantRoutes']
|
const fetchGetConstantRoutes: typeof import('../service/api/route')['fetchGetConstantRoutes']
|
||||||
const fetchGetMenuTree: typeof import('../service/api/menu')['fetchGetMenuTree']
|
const fetchGetMenuTree: typeof import('../service/api/menu')['fetchGetMenuTree']
|
||||||
const fetchIsRouteExist: typeof import('../service/api/route')['fetchIsRouteExist']
|
const fetchIsRouteExist: typeof import('../service/api/route')['fetchIsRouteExist']
|
||||||
|
const fetchKycImg: typeof import('../service/api/auth')['fetchKycImg']
|
||||||
|
const fetchKycList: typeof import('../service/api/auth')['fetchKycList']
|
||||||
const fetchLogin: typeof import('../service/api/auth')['fetchLogin']
|
const fetchLogin: typeof import('../service/api/auth')['fetchLogin']
|
||||||
|
const fetchPackageList: typeof import('../service/api/auth')['fetchPackageList']
|
||||||
|
const fetchPortalList: typeof import('../service/api/auth')['fetchPortalList']
|
||||||
|
const fetchRateLimitList: typeof import('../service/api/auth')['fetchRateLimitList']
|
||||||
const fetchRefreshToken: typeof import('../service/api/auth')['fetchRefreshToken']
|
const fetchRefreshToken: typeof import('../service/api/auth')['fetchRefreshToken']
|
||||||
const fetchRegister: typeof import('../service/api/auth')['fetchRegister']
|
const fetchRegister: typeof import('../service/api/auth')['fetchRegister']
|
||||||
|
const fetchSiteList: typeof import('../service/api/auth')['fetchSiteList']
|
||||||
|
const fetchSsidList: typeof import('../service/api/auth')['fetchSsidList']
|
||||||
|
const fetchTerminalList: typeof import('../service/api/auth')['fetchTerminalList']
|
||||||
|
const fetchWlanGroups: typeof import('../service/api/auth')['fetchWlanGroups']
|
||||||
|
const fetchWlanSsidList: typeof import('../service/api/auth')['fetchWlanSsidList']
|
||||||
|
const fetcodeReset: typeof import('../service/api/auth')['fetcodeReset']
|
||||||
const filterAuthRoutesByRoles: typeof import('../store/modules/route/shared')['filterAuthRoutesByRoles']
|
const filterAuthRoutesByRoles: typeof import('../store/modules/route/shared')['filterAuthRoutesByRoles']
|
||||||
const filterTabsById: typeof import('../store/modules/tab/shared')['filterTabsById']
|
const filterTabsById: typeof import('../store/modules/tab/shared')['filterTabsById']
|
||||||
const filterTabsByIds: typeof import('../store/modules/tab/shared')['filterTabsByIds']
|
const filterTabsByIds: typeof import('../store/modules/tab/shared')['filterTabsByIds']
|
||||||
const findTabByRouteName: typeof import('../store/modules/tab/shared')['findTabByRouteName']
|
const findTabByRouteName: typeof import('../store/modules/tab/shared')['findTabByRouteName']
|
||||||
|
const forgetApDevice: typeof import('../service/api/auth')['forgetApDevice']
|
||||||
|
const formatBandwidth: typeof import('../utils/units')['formatBandwidth']
|
||||||
|
const formatStorage: typeof import('../utils/units')['formatStorage']
|
||||||
|
const formatTime: typeof import('../utils/units')['formatTime']
|
||||||
const getActivePinia: typeof import('pinia')['getActivePinia']
|
const getActivePinia: typeof import('pinia')['getActivePinia']
|
||||||
const getAllTabs: typeof import('../store/modules/tab/shared')['getAllTabs']
|
const getAllTabs: typeof import('../store/modules/tab/shared')['getAllTabs']
|
||||||
const getAntdTheme: typeof import('../store/modules/theme/shared')['getAntdTheme']
|
const getAntdTheme: typeof import('../store/modules/theme/shared')['getAntdTheme']
|
||||||
|
const getApDeviceConfig: typeof import('../service/api/auth')['getApDeviceConfig']
|
||||||
const getBreadcrumbsByRoute: typeof import('../store/modules/route/shared')['getBreadcrumbsByRoute']
|
const getBreadcrumbsByRoute: typeof import('../store/modules/route/shared')['getBreadcrumbsByRoute']
|
||||||
const getCacheRouteNames: typeof import('../store/modules/route/shared')['getCacheRouteNames']
|
const getCacheRouteNames: typeof import('../store/modules/route/shared')['getCacheRouteNames']
|
||||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||||
|
const getDashboardOverview: typeof import('../service/api/auth')['getDashboardOverview']
|
||||||
|
const getDashboardSiteList: typeof import('../service/api/auth')['getDashboardSiteList']
|
||||||
|
const getData: typeof import('../service/api/dictData')['getData']
|
||||||
const getDefaultHomeTab: typeof import('../store/modules/tab/shared')['getDefaultHomeTab']
|
const getDefaultHomeTab: typeof import('../store/modules/tab/shared')['getDefaultHomeTab']
|
||||||
|
const getDictDataType: typeof import('../service/api/dict')['getDictDataType']
|
||||||
|
const getDictOptionselect: typeof import('../service/api/dict')['getDictOptionselect']
|
||||||
|
const getEmailCode: typeof import('../service/api/auth')['getEmailCode']
|
||||||
const getFixedTabIds: typeof import('../store/modules/tab/shared')['getFixedTabIds']
|
const getFixedTabIds: typeof import('../store/modules/tab/shared')['getFixedTabIds']
|
||||||
const getFixedTabs: typeof import('../store/modules/tab/shared')['getFixedTabs']
|
const getFixedTabs: typeof import('../store/modules/tab/shared')['getFixedTabs']
|
||||||
const getGlobalMenusByAuthRoutes: typeof import('../store/modules/route/shared')['getGlobalMenusByAuthRoutes']
|
const getGlobalMenusByAuthRoutes: typeof import('../store/modules/route/shared')['getGlobalMenusByAuthRoutes']
|
||||||
|
const getLocalizedTimeUnit: typeof import('../utils/units')['getLocalizedTimeUnit']
|
||||||
|
const getMeshConfig: typeof import('../service/api/auth')['getMeshConfig']
|
||||||
|
const getPaymentConfig: typeof import('../service/api/auth')['getPaymentConfig']
|
||||||
|
const getPortalConfig: typeof import('../service/api/auth')['getPortalConfig']
|
||||||
|
const getRoamingConfig: typeof import('../service/api/auth')['getRoamingConfig']
|
||||||
const getRouteIcons: typeof import('../store/modules/tab/shared')['getRouteIcons']
|
const getRouteIcons: typeof import('../store/modules/tab/shared')['getRouteIcons']
|
||||||
const getSelectedMenuKeyPathByKey: typeof import('../store/modules/route/shared')['getSelectedMenuKeyPathByKey']
|
const getSelectedMenuKeyPathByKey: typeof import('../store/modules/route/shared')['getSelectedMenuKeyPathByKey']
|
||||||
const getServiceBaseURL: typeof import('../utils/service')['getServiceBaseURL']
|
const getServiceBaseURL: typeof import('../utils/service')['getServiceBaseURL']
|
||||||
|
const getSiteConfig: typeof import('../service/api/auth')['getSiteConfig']
|
||||||
const getTabByRoute: typeof import('../store/modules/tab/shared')['getTabByRoute']
|
const getTabByRoute: typeof import('../store/modules/tab/shared')['getTabByRoute']
|
||||||
const getTabIdByRoute: typeof import('../store/modules/tab/shared')['getTabIdByRoute']
|
const getTabIdByRoute: typeof import('../store/modules/tab/shared')['getTabIdByRoute']
|
||||||
const getToken: typeof import('../store/modules/auth/shared')['getToken']
|
const getToken: typeof import('../store/modules/auth/shared')['getToken']
|
||||||
|
const getUserProfile: typeof import('../service/api/auth')['getUserProfile']
|
||||||
|
const getWlanSsidConfig: typeof import('../service/api/auth')['getWlanSsidConfig']
|
||||||
const h: typeof import('vue')['h']
|
const h: typeof import('vue')['h']
|
||||||
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
|
||||||
const initThemeSettings: typeof import('../store/modules/theme/shared')['initThemeSettings']
|
const initThemeSettings: typeof import('../store/modules/theme/shared')['initThemeSettings']
|
||||||
@@ -141,6 +221,7 @@ declare global {
|
|||||||
const mapState: typeof import('pinia')['mapState']
|
const mapState: typeof import('pinia')['mapState']
|
||||||
const mapStores: typeof import('pinia')['mapStores']
|
const mapStores: typeof import('pinia')['mapStores']
|
||||||
const mapWritableState: typeof import('pinia')['mapWritableState']
|
const mapWritableState: typeof import('pinia')['mapWritableState']
|
||||||
|
const markAlertsResolved: typeof import('../service/api/auth')['markAlertsResolved']
|
||||||
const markRaw: typeof import('vue')['markRaw']
|
const markRaw: typeof import('vue')['markRaw']
|
||||||
const nextTick: typeof import('vue')['nextTick']
|
const nextTick: typeof import('vue')['nextTick']
|
||||||
const omit: typeof import('lodash-es')['omit']
|
const omit: typeof import('lodash-es')['omit']
|
||||||
@@ -173,17 +254,24 @@ declare global {
|
|||||||
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
|
const reactiveComputed: typeof import('@vueuse/core')['reactiveComputed']
|
||||||
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
|
const reactiveOmit: typeof import('@vueuse/core')['reactiveOmit']
|
||||||
const reactivePick: typeof import('@vueuse/core')['reactivePick']
|
const reactivePick: typeof import('@vueuse/core')['reactivePick']
|
||||||
|
const readLoalXlsx: typeof import('../utils/execl-utils')['readLoalXlsx']
|
||||||
|
const readSheet: typeof import('../utils/execl-utils')['readSheet']
|
||||||
const readonly: typeof import('vue')['readonly']
|
const readonly: typeof import('vue')['readonly']
|
||||||
|
const rebootApDevice: typeof import('../service/api/auth')['rebootApDevice']
|
||||||
const ref: typeof import('vue')['ref']
|
const ref: typeof import('vue')['ref']
|
||||||
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
|
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
|
||||||
const refDebounced: typeof import('@vueuse/core')['refDebounced']
|
const refDebounced: typeof import('@vueuse/core')['refDebounced']
|
||||||
const refDefault: typeof import('@vueuse/core')['refDefault']
|
const refDefault: typeof import('@vueuse/core')['refDefault']
|
||||||
const refThrottled: typeof import('@vueuse/core')['refThrottled']
|
const refThrottled: typeof import('@vueuse/core')['refThrottled']
|
||||||
const refWithControl: typeof import('@vueuse/core')['refWithControl']
|
const refWithControl: typeof import('@vueuse/core')['refWithControl']
|
||||||
|
const rejectKyc: typeof import('../service/api/auth')['rejectKyc']
|
||||||
const removeEmptyChildren: typeof import('../utils/menu')['removeEmptyChildren']
|
const removeEmptyChildren: typeof import('../utils/menu')['removeEmptyChildren']
|
||||||
|
const removeRateLimit: typeof import('../service/api/auth')['removeRateLimit']
|
||||||
|
const resetPassword: typeof import('../service/api/auth')['resetPassword']
|
||||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||||
const resolveRef: typeof import('@vueuse/core')['resolveRef']
|
const resolveRef: typeof import('@vueuse/core')['resolveRef']
|
||||||
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
|
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
|
||||||
|
const runJob: typeof import('../service/api/job')['runJob']
|
||||||
const sendCaptcha: typeof import('../service/api/auth')['sendCaptcha']
|
const sendCaptcha: typeof import('../service/api/auth')['sendCaptcha']
|
||||||
const sessionStg: typeof import('../utils/storage')['sessionStg']
|
const sessionStg: typeof import('../utils/storage')['sessionStg']
|
||||||
const setActivePinia: typeof import('pinia')['setActivePinia']
|
const setActivePinia: typeof import('pinia')['setActivePinia']
|
||||||
@@ -192,6 +280,8 @@ declare global {
|
|||||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||||
const shallowRef: typeof import('vue')['shallowRef']
|
const shallowRef: typeof import('vue')['shallowRef']
|
||||||
const sortRoutesByOrder: typeof import('../store/modules/route/shared')['sortRoutesByOrder']
|
const sortRoutesByOrder: typeof import('../store/modules/route/shared')['sortRoutesByOrder']
|
||||||
|
const storageFactors: typeof import('../utils/units')['storageFactors']
|
||||||
|
const storageUnits: typeof import('../utils/units')['storageUnits']
|
||||||
const storeToRefs: typeof import('pinia')['storeToRefs']
|
const storeToRefs: typeof import('pinia')['storeToRefs']
|
||||||
const suite: typeof import('vitest')['suite']
|
const suite: typeof import('vitest')['suite']
|
||||||
const syncRef: typeof import('@vueuse/core')['syncRef']
|
const syncRef: typeof import('@vueuse/core')['syncRef']
|
||||||
@@ -200,6 +290,8 @@ declare global {
|
|||||||
const test: typeof import('vitest')['test']
|
const test: typeof import('vitest')['test']
|
||||||
const throttledRef: typeof import('@vueuse/core')['throttledRef']
|
const throttledRef: typeof import('@vueuse/core')['throttledRef']
|
||||||
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
|
const throttledWatch: typeof import('@vueuse/core')['throttledWatch']
|
||||||
|
const timeFactors: typeof import('../utils/units')['timeFactors']
|
||||||
|
const timeUnits: typeof import('../utils/units')['timeUnits']
|
||||||
const toRaw: typeof import('vue')['toRaw']
|
const toRaw: typeof import('vue')['toRaw']
|
||||||
const toReactive: typeof import('@vueuse/core')['toReactive']
|
const toReactive: typeof import('@vueuse/core')['toReactive']
|
||||||
const toRef: typeof import('vue')['toRef']
|
const toRef: typeof import('vue')['toRef']
|
||||||
@@ -217,12 +309,27 @@ declare global {
|
|||||||
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
|
const tryOnMounted: typeof import('@vueuse/core')['tryOnMounted']
|
||||||
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
|
const tryOnScopeDispose: typeof import('@vueuse/core')['tryOnScopeDispose']
|
||||||
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
|
const tryOnUnmounted: typeof import('@vueuse/core')['tryOnUnmounted']
|
||||||
|
const unitFactors: typeof import('../utils/bandwidth')['unitFactors']
|
||||||
const unref: typeof import('vue')['unref']
|
const unref: typeof import('vue')['unref']
|
||||||
const unrefElement: typeof import('@vueuse/core')['unrefElement']
|
const unrefElement: typeof import('@vueuse/core')['unrefElement']
|
||||||
const until: typeof import('@vueuse/core')['until']
|
const until: typeof import('@vueuse/core')['until']
|
||||||
|
const updateAccessControl: typeof import('../service/api/auth')['updateAccessControl']
|
||||||
|
const updateApDeviceConfig: typeof import('../service/api/auth')['updateApDeviceConfig']
|
||||||
|
const updateBillRule: typeof import('../service/api/auth')['updateBillRule']
|
||||||
|
const updateData: typeof import('../service/api/dictData')['updateData']
|
||||||
|
const updateJob: typeof import('../service/api/job')['updateJob']
|
||||||
const updateLocaleOfGlobalMenus: typeof import('../store/modules/route/shared')['updateLocaleOfGlobalMenus']
|
const updateLocaleOfGlobalMenus: typeof import('../store/modules/route/shared')['updateLocaleOfGlobalMenus']
|
||||||
|
const updateMeshConfig: typeof import('../service/api/auth')['updateMeshConfig']
|
||||||
|
const updatePackage: typeof import('../service/api/auth')['updatePackage']
|
||||||
|
const updatePasswordByOld: typeof import('../service/api/auth')['updatePasswordByOld']
|
||||||
|
const updatePaymentConfig: typeof import('../service/api/auth')['updatePaymentConfig']
|
||||||
|
const updatePortalConfig: typeof import('../service/api/auth')['updatePortalConfig']
|
||||||
|
const updateRoamingConfig: typeof import('../service/api/auth')['updateRoamingConfig']
|
||||||
|
const updateSite: typeof import('../service/api/auth')['updateSite']
|
||||||
const updateTabByI18nKey: typeof import('../store/modules/tab/shared')['updateTabByI18nKey']
|
const updateTabByI18nKey: typeof import('../store/modules/tab/shared')['updateTabByI18nKey']
|
||||||
const updateTabsByI18nKey: typeof import('../store/modules/tab/shared')['updateTabsByI18nKey']
|
const updateTabsByI18nKey: typeof import('../store/modules/tab/shared')['updateTabsByI18nKey']
|
||||||
|
const updateUserProfile: typeof import('../service/api/auth')['updateUserProfile']
|
||||||
|
const updateWlanSsid: typeof import('../service/api/auth')['updateWlanSsid']
|
||||||
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
const useActiveElement: typeof import('@vueuse/core')['useActiveElement']
|
||||||
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
const useAnimate: typeof import('@vueuse/core')['useAnimate']
|
||||||
const useAntdForm: typeof import('../hooks/common/form')['useAntdForm']
|
const useAntdForm: typeof import('../hooks/common/form')['useAntdForm']
|
||||||
@@ -291,6 +398,7 @@ declare global {
|
|||||||
const useFocus: typeof import('@vueuse/core')['useFocus']
|
const useFocus: typeof import('@vueuse/core')['useFocus']
|
||||||
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
|
const useFocusWithin: typeof import('@vueuse/core')['useFocusWithin']
|
||||||
const useFormRules: typeof import('../hooks/common/form')['useFormRules']
|
const useFormRules: typeof import('../hooks/common/form')['useFormRules']
|
||||||
|
const useFormatTime: typeof import('../utils/units')['useFormatTime']
|
||||||
const useFps: typeof import('@vueuse/core')['useFps']
|
const useFps: typeof import('@vueuse/core')['useFps']
|
||||||
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
|
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
|
||||||
const useGamepad: typeof import('@vueuse/core')['useGamepad']
|
const useGamepad: typeof import('@vueuse/core')['useGamepad']
|
||||||
@@ -373,6 +481,7 @@ declare global {
|
|||||||
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
|
const useThrottleFn: typeof import('@vueuse/core')['useThrottleFn']
|
||||||
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
|
const useThrottledRefHistory: typeof import('@vueuse/core')['useThrottledRefHistory']
|
||||||
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
|
const useTimeAgo: typeof import('@vueuse/core')['useTimeAgo']
|
||||||
|
const useTimeUnits: typeof import('../utils/units')['useTimeUnits']
|
||||||
const useTimeout: typeof import('@vueuse/core')['useTimeout']
|
const useTimeout: typeof import('@vueuse/core')['useTimeout']
|
||||||
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
|
const useTimeoutFn: typeof import('@vueuse/core')['useTimeoutFn']
|
||||||
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
|
const useTimeoutPoll: typeof import('@vueuse/core')['useTimeoutPoll']
|
||||||
@@ -414,6 +523,8 @@ declare global {
|
|||||||
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
|
const watchTriggerable: typeof import('@vueuse/core')['watchTriggerable']
|
||||||
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
|
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
|
||||||
const whenever: typeof import('@vueuse/core')['whenever']
|
const whenever: typeof import('@vueuse/core')['whenever']
|
||||||
|
const writeSheet: typeof import('../utils/execl-utils')['writeSheet']
|
||||||
|
const xlsxUrl: typeof import('../utils/execl-utils')['xlsxUrl']
|
||||||
}
|
}
|
||||||
// for type re-export
|
// for type re-export
|
||||||
declare global {
|
declare global {
|
||||||
|
|||||||
Vendored
-91
@@ -1,91 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
// @ts-nocheck
|
|
||||||
// Generated by unplugin-vue-components
|
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
|
||||||
export {}
|
|
||||||
|
|
||||||
/* prettier-ignore */
|
|
||||||
declare module 'vue' {
|
|
||||||
export interface GlobalComponents {
|
|
||||||
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
|
|
||||||
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
|
|
||||||
AButton: typeof import('ant-design-vue/es')['Button']
|
|
||||||
ACard: typeof import('ant-design-vue/es')['Card']
|
|
||||||
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
|
|
||||||
ACol: typeof import('ant-design-vue/es')['Col']
|
|
||||||
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
|
|
||||||
ADescriptions: typeof import('ant-design-vue/es')['Descriptions']
|
|
||||||
ADescriptionsItem: typeof import('ant-design-vue/es')['DescriptionsItem']
|
|
||||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
|
||||||
ADrawer: typeof import('ant-design-vue/es')['Drawer']
|
|
||||||
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
|
|
||||||
AForm: typeof import('ant-design-vue/es')['Form']
|
|
||||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
|
||||||
AImage: typeof import('ant-design-vue/es')['Image']
|
|
||||||
AInput: typeof import('ant-design-vue/es')['Input']
|
|
||||||
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
|
|
||||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
|
||||||
AInputSearch: typeof import('ant-design-vue/es')['InputSearch']
|
|
||||||
AList: typeof import('ant-design-vue/es')['List']
|
|
||||||
AListItem: typeof import('ant-design-vue/es')['ListItem']
|
|
||||||
AListItemMeta: typeof import('ant-design-vue/es')['ListItemMeta']
|
|
||||||
AMenu: typeof import('ant-design-vue/es')['Menu']
|
|
||||||
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
|
|
||||||
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
|
|
||||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
|
||||||
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
|
||||||
APopover: typeof import('ant-design-vue/es')['Popover']
|
|
||||||
AppLoading: typeof import('./../components/common/app-loading.vue')['default']
|
|
||||||
AppProvider: typeof import('./../components/common/app-provider.vue')['default']
|
|
||||||
ARadio: typeof import('ant-design-vue/es')['Radio']
|
|
||||||
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
|
||||||
ARow: typeof import('ant-design-vue/es')['Row']
|
|
||||||
ASegmented: typeof import('ant-design-vue/es')['Segmented']
|
|
||||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
|
||||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
|
||||||
ASpace: typeof import('ant-design-vue/es')['Space']
|
|
||||||
ASpin: typeof import('ant-design-vue/es')['Spin']
|
|
||||||
AStatistic: typeof import('ant-design-vue/es')['Statistic']
|
|
||||||
AStep: typeof import('ant-design-vue/es')['Step']
|
|
||||||
ASteps: typeof import('ant-design-vue/es')['Steps']
|
|
||||||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
|
||||||
ATable: typeof import('ant-design-vue/es')['Table']
|
|
||||||
ATag: typeof import('ant-design-vue/es')['Tag']
|
|
||||||
ATextarea: typeof import('ant-design-vue/es')['Textarea']
|
|
||||||
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
|
|
||||||
ATree: typeof import('ant-design-vue/es')['Tree']
|
|
||||||
ATreeSelect: typeof import('ant-design-vue/es')['TreeSelect']
|
|
||||||
BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default']
|
|
||||||
ButtonIcon: typeof import('./../components/custom/button-icon.vue')['default']
|
|
||||||
CountTo: typeof import('./../components/custom/count-to.vue')['default']
|
|
||||||
DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default']
|
|
||||||
ExceptionBase: typeof import('./../components/common/exception-base.vue')['default']
|
|
||||||
FullScreen: typeof import('./../components/common/full-screen.vue')['default']
|
|
||||||
IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
|
|
||||||
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
|
|
||||||
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
|
|
||||||
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
|
|
||||||
IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
|
|
||||||
IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default']
|
|
||||||
IconIcRoundRefresh: typeof import('~icons/ic/round-refresh')['default']
|
|
||||||
IconIcRoundSearch: typeof import('~icons/ic/round-search')['default']
|
|
||||||
IconLocalBanner: typeof import('~icons/local/banner')['default']
|
|
||||||
IconLocalLogo: typeof import('~icons/local/logo')['default']
|
|
||||||
IconMdiDrag: typeof import('~icons/mdi/drag')['default']
|
|
||||||
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
|
|
||||||
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
|
|
||||||
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
|
|
||||||
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']
|
|
||||||
PinToggler: typeof import('./../components/common/pin-toggler.vue')['default']
|
|
||||||
ReloadButton: typeof import('./../components/common/reload-button.vue')['default']
|
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
|
||||||
SoybeanAvatar: typeof import('./../components/custom/soybean-avatar.vue')['default']
|
|
||||||
SvgIcon: typeof import('./../components/custom/svg-icon.vue')['default']
|
|
||||||
SystemLogo: typeof import('./../components/common/system-logo.vue')['default']
|
|
||||||
TableColumnSetting: typeof import('./../components/advanced/table-column-setting.vue')['default']
|
|
||||||
TableHeaderOperation: typeof import('./../components/advanced/table-header-operation.vue')['default']
|
|
||||||
ThemeSchemaSwitch: typeof import('./../components/common/theme-schema-switch.vue')['default']
|
|
||||||
WaveBg: typeof import('./../components/custom/wave-bg.vue')['default']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
/**字段类型 */
|
||||||
|
type DictType = {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
tagType?: string;
|
||||||
|
tagClass?: string;
|
||||||
|
};
|
||||||
Vendored
+1
-2
@@ -55,8 +55,7 @@ declare namespace Env {
|
|||||||
* use "," to separate multiple codes
|
* use "," to separate multiple codes
|
||||||
*/
|
*/
|
||||||
readonly VITE_SERVICE_EXPIRED_TOKEN_CODES: string;
|
readonly VITE_SERVICE_EXPIRED_TOKEN_CODES: string;
|
||||||
/** when the route mode is static, the defined super role */
|
|
||||||
readonly VITE_STATIC_SUPER_ROLE: string;
|
|
||||||
/**
|
/**
|
||||||
* other backend service base url
|
* other backend service base url
|
||||||
*
|
*
|
||||||
|
|||||||
Vendored
+2
-2
@@ -13,9 +13,9 @@ declare namespace StorageType {
|
|||||||
/** The i18n language */
|
/** The i18n language */
|
||||||
lang: App.I18n.LangType;
|
lang: App.I18n.LangType;
|
||||||
/** The token */
|
/** The token */
|
||||||
token: string;
|
tokenSys: string;
|
||||||
/** The refresh token */
|
/** The refresh token */
|
||||||
refreshToken: string;
|
refreshTokenSys: string;
|
||||||
/** The user info */
|
/** The user info */
|
||||||
userInfo: Api.Auth.UserInfo;
|
userInfo: Api.Auth.UserInfo;
|
||||||
/** The theme color */
|
/** The theme color */
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { JSON2SheetOpts, read, utils, write } from 'xlsx';
|
||||||
|
|
||||||
|
// 静态资源路径
|
||||||
|
const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL;
|
||||||
|
export const xlsxUrl = `${
|
||||||
|
baseUrl.length === 1 && baseUrl.indexOf('/') === 0
|
||||||
|
? ''
|
||||||
|
: baseUrl.indexOf('/') === -1
|
||||||
|
? '/' + baseUrl
|
||||||
|
: baseUrl
|
||||||
|
}/alarmHelp`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取本地文件
|
||||||
|
* @param id 表格ID
|
||||||
|
* @returns 数据数组
|
||||||
|
* @example
|
||||||
|
* readLoalXlsx('20001').then(res=>{
|
||||||
|
* console.log(res)
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export async function readLoalXlsx(
|
||||||
|
lang: string,
|
||||||
|
id: string
|
||||||
|
): Promise<Record<string, any>[]> {
|
||||||
|
let result = await fetch(`${xlsxUrl}/${lang}/${id}.xlsx`);
|
||||||
|
let fileBuffer = await result.arrayBuffer();
|
||||||
|
// 判断是否xlsx文件
|
||||||
|
const data = new Uint8Array(fileBuffer);
|
||||||
|
const isXlsxFile =
|
||||||
|
data[0] === 0x50 &&
|
||||||
|
data[1] === 0x4b &&
|
||||||
|
data[2] === 0x03 &&
|
||||||
|
data[3] === 0x04;
|
||||||
|
if (!isXlsxFile) {
|
||||||
|
result = await fetch(`${xlsxUrl}/${lang}/all.xlsx`);
|
||||||
|
fileBuffer = await result.arrayBuffer();
|
||||||
|
}
|
||||||
|
return readSheet(fileBuffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取表格数据 工作表
|
||||||
|
* @param fileBolb 文件对象
|
||||||
|
* @param index 文件保存路径
|
||||||
|
* @return 表格对象列表
|
||||||
|
*/
|
||||||
|
export async function readSheet(
|
||||||
|
fileBolb: Blob | ArrayBuffer,
|
||||||
|
index: number = 0
|
||||||
|
): Promise<Record<string, string>[]> {
|
||||||
|
const workBook = read(fileBolb);
|
||||||
|
let workSheet = workBook.Sheets[workBook.SheetNames[index]];
|
||||||
|
return utils.sheet_to_json<Record<string, string>>(workSheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入表格数据,一般用于导出
|
||||||
|
* @param filePath 文件路径
|
||||||
|
* @param sheetName 工作表名称
|
||||||
|
* @return xlsx文件流, 使用saveAs函数保存
|
||||||
|
* @example
|
||||||
|
* writeSheet(res.data, from.logType).then(fileBlob =>
|
||||||
|
* saveAs(fileBlob, `${from.logType}_${Date.now()}.xlsx`)
|
||||||
|
* );
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export async function writeSheet(
|
||||||
|
data: any[],
|
||||||
|
sheetName: string,
|
||||||
|
opts?: JSON2SheetOpts
|
||||||
|
) {
|
||||||
|
if (data.length === 0) {
|
||||||
|
return new Blob([], { type: 'application/octet-stream' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const workSheet = utils.json_to_sheet(data, opts);
|
||||||
|
|
||||||
|
// 设置列宽度,单位厘米
|
||||||
|
workSheet['!cols'] = Object.keys(data[0]).map(() => {
|
||||||
|
return { wch: 20 };
|
||||||
|
});
|
||||||
|
const workBook = utils.book_new();
|
||||||
|
utils.book_append_sheet(workBook, workSheet, sheetName);
|
||||||
|
const excelBuffer = write(workBook, { type: 'array', bookType: 'xlsx' });
|
||||||
|
return new Blob([excelBuffer], { type: 'application/octet-stream' });
|
||||||
|
}
|
||||||
+16
-7
@@ -11,16 +11,25 @@ import type { DataNode } from 'ant-design-vue/es/tree';
|
|||||||
export function transformMenuChildWithRootIds(menuList: DataNode[], checkedKeys: number[]): number[] {
|
export function transformMenuChildWithRootIds(menuList: DataNode[], checkedKeys: number[]): number[] {
|
||||||
const checkedKeysSet = new Set(checkedKeys);
|
const checkedKeysSet = new Set(checkedKeys);
|
||||||
|
|
||||||
function changeCheckedKeys(menus: DataNode[]) {
|
function changeCheckedKeys(menus: DataNode[], checkedKey: number): boolean {
|
||||||
menus.forEach(menu => {
|
for (let menu of menus) {
|
||||||
if (menu.children) {
|
if (menu.key === checkedKey) {
|
||||||
changeCheckedKeys(menu.children);
|
|
||||||
checkedKeysSet.add(menu.key as number);
|
checkedKeysSet.add(menu.key as number);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
});
|
if (menu.children && menu.children.length > 0) {
|
||||||
|
let isFind = changeCheckedKeys(menu.children, checkedKey);
|
||||||
|
if (isFind) {
|
||||||
|
checkedKeysSet.add(menu.key as number);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
changeCheckedKeys(menuList);
|
};
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
checkedKeys.forEach(checkedKey => {
|
||||||
|
changeCheckedKeys(menuList, checkedKey);
|
||||||
|
})
|
||||||
|
|
||||||
return Array.from(checkedKeysSet);
|
return Array.from(checkedKeysSet);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ import { useAuthStore } from '@/store/modules/auth';
|
|||||||
export function isShowBtn(permission: string) {
|
export function isShowBtn(permission: string) {
|
||||||
const { permissions, userInfo } = storeToRefs(useAuthStore());
|
const { permissions, userInfo } = storeToRefs(useAuthStore());
|
||||||
|
|
||||||
return userInfo.value.roles.includes('admin') || permissions.value.includes(permission);
|
return userInfo.value.roles.some(role => ['admin', 'super'].includes(role)) || permissions.value.includes(permission);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
// 带宽单位转换
|
||||||
|
export type BandwidthUnit = 'Kbps' | 'Mbps' | 'Gbps';
|
||||||
|
|
||||||
|
export const bandwidthUnits: BandwidthUnit[] = ['Kbps', 'Mbps', 'Gbps'];
|
||||||
|
|
||||||
|
export const bandwidthFactors: Record<BandwidthUnit, number> = {
|
||||||
|
Kbps: 1,
|
||||||
|
Mbps: 1024,
|
||||||
|
Gbps: 1048576
|
||||||
|
};
|
||||||
|
|
||||||
|
export function convertBandwidth(value: number, fromUnit: BandwidthUnit, toUnit: BandwidthUnit): number {
|
||||||
|
const fromFactor = bandwidthFactors[fromUnit];
|
||||||
|
const toFactor = bandwidthFactors[toUnit];
|
||||||
|
return (value * fromFactor) / toFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatBandwidth(kbpsValue: number): { value: number; unit: BandwidthUnit } {
|
||||||
|
if (kbpsValue >= 1048576) {
|
||||||
|
return { value: kbpsValue / 1048576, unit: 'Gbps' };
|
||||||
|
} else if (kbpsValue >= 1024) {
|
||||||
|
return { value: kbpsValue / 1024, unit: 'Mbps' };
|
||||||
|
}
|
||||||
|
return { value: kbpsValue, unit: 'Kbps' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 流量单位转换
|
||||||
|
export type StorageUnit = 'B' | 'KB' | 'MB' | 'GB' | 'TB';
|
||||||
|
|
||||||
|
export const storageUnits: StorageUnit[] = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||||
|
|
||||||
|
export const storageFactors: Record<StorageUnit, number> = {
|
||||||
|
B: 1,
|
||||||
|
KB: 1024,
|
||||||
|
MB: 1024 * 1024,
|
||||||
|
GB: 1024 * 1024 * 1024,
|
||||||
|
TB: 1024 * 1024 * 1024 * 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
export function convertStorage(value: number, fromUnit: StorageUnit, toUnit: StorageUnit): number {
|
||||||
|
const fromFactor = storageFactors[fromUnit];
|
||||||
|
const toFactor = storageFactors[toUnit];
|
||||||
|
return (value * fromFactor) / toFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatStorage(byteValue: number): { value: number; unit: StorageUnit } {
|
||||||
|
if (byteValue >= 1024 * 1024 * 1024 * 1024) {
|
||||||
|
return { value: byteValue / (1024 * 1024 * 1024 * 1024), unit: 'TB' };
|
||||||
|
} else if (byteValue >= 1024 * 1024 * 1024) {
|
||||||
|
return { value: byteValue / (1024 * 1024 * 1024), unit: 'GB' };
|
||||||
|
} else if (byteValue >= 1024 * 1024) {
|
||||||
|
return { value: byteValue / (1024 * 1024), unit: 'MB' };
|
||||||
|
} else if (byteValue >= 1024) {
|
||||||
|
return { value: byteValue / 1024, unit: 'KB' };
|
||||||
|
}
|
||||||
|
return { value: byteValue, unit: 'B' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 时间单位转换
|
||||||
|
export type TimeUnit = 'second' | 'minute' | 'hour' | 'day';
|
||||||
|
|
||||||
|
export const useTimeUnits = () => {
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
return computed(() => ([
|
||||||
|
{ key: 'second', label: t('common.time.second') },
|
||||||
|
{ key: 'minute', label: t('common.time.minute') },
|
||||||
|
{ key: 'hour', label: t('common.time.hour') },
|
||||||
|
{ key: 'day', label: t('common.time.day') }
|
||||||
|
]));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const timeFactors: Record<TimeUnit, number> = {
|
||||||
|
'second': 1,
|
||||||
|
'minute': 60,
|
||||||
|
'hour': 3600,
|
||||||
|
'day': 86400
|
||||||
|
};
|
||||||
|
|
||||||
|
export function convertTime(value: number, fromUnit: TimeUnit, toUnit: TimeUnit): number {
|
||||||
|
const fromFactor = timeFactors[fromUnit];
|
||||||
|
const toFactor = timeFactors[toUnit];
|
||||||
|
return (value * fromFactor) / toFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useFormatTime = () => {
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
return (secondsValue: number): { value: number; unit: TimeUnit; display: string } => {
|
||||||
|
let result: { value: number; unit: TimeUnit };
|
||||||
|
|
||||||
|
if (secondsValue >= 86400) {
|
||||||
|
result = { value: secondsValue / 86400, unit: 'day' };
|
||||||
|
} else if (secondsValue >= 3600) {
|
||||||
|
result = { value: secondsValue / 3600, unit: 'hour' };
|
||||||
|
} else if (secondsValue >= 60) {
|
||||||
|
result = { value: secondsValue / 60, unit: 'minute' };
|
||||||
|
} else {
|
||||||
|
result = { value: secondsValue, unit: 'second' };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...result,
|
||||||
|
display: `${result.value} ${t(`common.time.${result.unit}`)}`
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -11,6 +11,8 @@ import ResetPwd from './modules/reset-pwd.vue';
|
|||||||
import BindWechat from './modules/bind-wechat.vue';
|
import BindWechat from './modules/bind-wechat.vue';
|
||||||
import { WifiOutlined } from '@ant-design/icons-vue';
|
import { WifiOutlined } from '@ant-design/icons-vue';
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
|
import { useAppStore } from '@/store/modules/app';
|
||||||
|
const appStore = useAppStore();
|
||||||
//import { $t } from '@/locales';
|
//import { $t } from '@/locales';
|
||||||
interface Props {
|
interface Props {
|
||||||
/** The login module */
|
/** The login module */
|
||||||
@@ -58,9 +60,12 @@ const bgColor = computed(() => {
|
|||||||
<WifiOutlined class="text-64px text-primary lt-sm:text-48px" style="margin-left: 9px"/>
|
<WifiOutlined class="text-64px text-primary lt-sm:text-48px" style="margin-left: 9px"/>
|
||||||
<h3 class="text-18px text-primary font-medium">{{ t(activeModule.label) }}</h3>
|
<h3 class="text-18px text-primary font-medium">{{ t(activeModule.label) }}</h3>
|
||||||
</header>
|
</header>
|
||||||
<main >
|
<main>
|
||||||
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ "WANFi" }}</h3>
|
<div class="flex justify-between items-center">
|
||||||
<div class="animation-slide-in-left ">
|
<h3 class="text-28px text-primary font-500 lt-sm:text-22px">{{ $t('system.title') }}</h3>
|
||||||
|
<LangSwitch :lang="appStore.locale" :lang-options="appStore.localeOptions" @change-lang="appStore.changeLocale" />
|
||||||
|
</div>
|
||||||
|
<div class="animation-slide-in-left">
|
||||||
<Transition :name="themeStore.page.animateMode" mode="out-in" appear>
|
<Transition :name="themeStore.page.animateMode" mode="out-in" appear>
|
||||||
<component :is="activeModule.component" />
|
<component :is="activeModule.component" />
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|||||||
@@ -20,16 +20,15 @@ const codeImg = ref('');
|
|||||||
getCheckCode();
|
getCheckCode();
|
||||||
|
|
||||||
const model = reactive({
|
const model = reactive({
|
||||||
username: '123456',
|
username: '',
|
||||||
password: '123456',
|
password: '',
|
||||||
code: '',
|
code: '',
|
||||||
uuid: '',
|
uuid: '',
|
||||||
authType: 'u'
|
authType: 'sys'
|
||||||
});
|
});
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
username: patternRules.username,
|
username: patternRules.username,
|
||||||
password: patternRules.pwd
|
|
||||||
};
|
};
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
@@ -77,21 +76,21 @@ async function getCheckCode() {
|
|||||||
|
|
||||||
<ASpace direction="vertical" size="large" class="w-full">
|
<ASpace direction="vertical" size="large" class="w-full">
|
||||||
<div class="flex-y-center justify-between">
|
<div class="flex-y-center justify-between">
|
||||||
<ACheckbox>{{ $t('page.login.pwdLogin.rememberMe') }}</ACheckbox>
|
<span></span>
|
||||||
<AButton type="text" @click="toggleLoginModule('reset-pwd')">{{ t('page.login.pwdLogin.forgetPassword') }}</AButton>
|
<AButton type="text" @click="toggleLoginModule('reset-pwd')">{{ t('page.login.pwdLogin.forgetPassword') }}</AButton>
|
||||||
</div>
|
</div>
|
||||||
<AButton type="primary" block size="large" shape="round" :loading="authStore.loginLoading" @click="handleSubmit">
|
<AButton type="primary" block size="large" shape="round" :loading="authStore.loginLoading" @click="handleSubmit">
|
||||||
{{ $t('common.confirm') }}
|
{{ $t('common.confirm') }}
|
||||||
</AButton>
|
</AButton>
|
||||||
<div class="flex-y-center justify-between">
|
<!-- <div class="flex-y-center justify-between">-->
|
||||||
<!-- <AButton class="h-34px flex-1" block @click="toggleLoginModule('code-login')">-->
|
<!-- <AButton class="h-34px flex-1" block @click="toggleLoginModule('code-login')">-->
|
||||||
<!-- {{ t(loginModuleRecord['code-login']) }}-->
|
<!-- {{ t(loginModuleRecord['code-login']) }}-->
|
||||||
<!-- </AButton>-->
|
<!-- </AButton>-->
|
||||||
<div class="w-12px"></div>
|
<!-- <div class="w-12px"></div>-->
|
||||||
<AButton class="h-34px flex-1" block @click="toggleLoginModule('register')">
|
<!-- <AButton class="h-34px flex-1" block @click="toggleLoginModule('register')">-->
|
||||||
{{ t(loginModuleRecord.register) }}
|
<!-- {{ t(loginModuleRecord.register) }}-->
|
||||||
</AButton>
|
<!-- </AButton>-->
|
||||||
</div>
|
<!-- </div>-->
|
||||||
</ASpace>
|
</ASpace>
|
||||||
</AForm>
|
</AForm>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, reactive, ref} from 'vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
import {useI18n} from 'vue-i18n'; // 添加这行
|
import { useI18n } from 'vue-i18n';
|
||||||
import {useAuthStore} from '@/store/modules/auth';
|
import { useAuthStore } from '@/store/modules/auth';
|
||||||
import {useRouterPush} from '@/hooks/common/router';
|
import { useRouterPush } from '@/hooks/common/router';
|
||||||
import {useAntdForm, useFormRules} from '@/hooks/common/form';
|
import { useFormRules } from '@/hooks/common/form';
|
||||||
import {useCaptcha} from '@/hooks/business/captcha';
|
import { useCaptcha } from '@/hooks/business/captcha';
|
||||||
import {useWindowSize} from '@vueuse/core';
|
import { useWindowSize } from '@vueuse/core';
|
||||||
import {registerTerms} from '@/views/_builtin/login/modules/terms';
|
import { registerTerms } from '@/views/_builtin/login/modules/terms';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import type {Rule} from 'ant-design-vue/es/form';
|
import type { Rule } from 'ant-design-vue/es/form';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
// 添加两个表单引用
|
||||||
|
const basicFormRef = ref();
|
||||||
|
const securityFormRef = ref();
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'Register'
|
name: 'Register'
|
||||||
});
|
});
|
||||||
|
|
||||||
const { toggleLoginModule } = useRouterPush();
|
const { toggleLoginModule } = useRouterPush();
|
||||||
const { formRef, validate } = useAntdForm();
|
|
||||||
const { label, isCounting, loading, getCaptcha } = useCaptcha();
|
const { label, isCounting, loading, getCaptcha } = useCaptcha();
|
||||||
|
|
||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
@@ -29,17 +31,19 @@ const currentStep = ref(0);
|
|||||||
|
|
||||||
// 是否同意协议
|
// 是否同意协议
|
||||||
const agreeTerms = ref(false);
|
const agreeTerms = ref(false);
|
||||||
|
|
||||||
// 定义一个统一的数据模型
|
// 定义一个统一的数据模型
|
||||||
interface RegisterModel {
|
interface RegisterModel {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
email: string;
|
email: string;
|
||||||
fullName: string;
|
fullName: string;
|
||||||
age:0,
|
age: number;
|
||||||
gender: string;
|
gender: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
address: string;
|
address: string;
|
||||||
code: string;
|
code: string;
|
||||||
|
uuid: string;
|
||||||
authType: string;
|
authType: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,11 +53,12 @@ const model = reactive<RegisterModel>({
|
|||||||
password: '',
|
password: '',
|
||||||
email: '',
|
email: '',
|
||||||
fullName: '',
|
fullName: '',
|
||||||
age:0,
|
age: 0,
|
||||||
gender: '',
|
gender: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
address: '',
|
address: '',
|
||||||
code: '',
|
code: '',
|
||||||
|
uuid: '',
|
||||||
authType: 'u'
|
authType: 'u'
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -64,7 +69,6 @@ interface BasicFormModel {
|
|||||||
birthDate: string;
|
birthDate: string;
|
||||||
gender: string;
|
gender: string;
|
||||||
phone: string;
|
phone: string;
|
||||||
email: string;
|
|
||||||
address: string;
|
address: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +78,6 @@ const basicModel = reactive<BasicFormModel>({
|
|||||||
birthDate: '',
|
birthDate: '',
|
||||||
gender: '',
|
gender: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
email: '',
|
|
||||||
address: ''
|
address: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,6 +85,7 @@ const basicModel = reactive<BasicFormModel>({
|
|||||||
interface SecurityFormModel {
|
interface SecurityFormModel {
|
||||||
email: string;
|
email: string;
|
||||||
code: string;
|
code: string;
|
||||||
|
uuid: string;
|
||||||
password: string;
|
password: string;
|
||||||
confirmPassword: string;
|
confirmPassword: string;
|
||||||
}
|
}
|
||||||
@@ -89,27 +93,85 @@ interface SecurityFormModel {
|
|||||||
const securityModel = reactive<SecurityFormModel>({
|
const securityModel = reactive<SecurityFormModel>({
|
||||||
email: '',
|
email: '',
|
||||||
code: '',
|
code: '',
|
||||||
|
uuid: '',
|
||||||
password: '',
|
password: '',
|
||||||
confirmPassword: ''
|
confirmPassword: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
// 第一步表单验证规则
|
// 第一步表单验证规则
|
||||||
const basicRules = computed<Record<string, Rule | Rule[]>>(() => {
|
const basicRules = computed<Record<string, Rule | Rule[]>>(() => {
|
||||||
const { formRules } = useFormRules();
|
const validateUsername = async (_rule: Rule, value: string) => {
|
||||||
|
if (value && (value.length < 4 || value.length > 20)) {
|
||||||
|
return Promise.reject(t('page.login.register.usernameLengthLimit'));
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
const { exists } = await authStore.checkUserRepeat({ username: value, authType: 'u' });
|
||||||
|
if (exists) {
|
||||||
|
return Promise.reject(t('page.login.register.usernameExists'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
const validatePhone = async (_rule: Rule, value: string) => {
|
||||||
|
if (!value) return Promise.resolve();
|
||||||
|
|
||||||
|
const phonePattern = /^1[3-9]\d{9}$/;
|
||||||
|
|
||||||
|
if (!phonePattern.test(value)) {
|
||||||
|
return Promise.reject(t('page.login.register.phoneInvalid'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { exists } = await authStore.checkUserRepeat({ phonenumber: value, authType: 'u' });
|
||||||
|
if (exists) {
|
||||||
|
return Promise.reject(t('page.login.register.phoneExists'));
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
username: formRules.username,
|
username: [
|
||||||
email: formRules.email,
|
{ required: true, message: t('page.login.register.usernameRequired'), trigger: 'change' },
|
||||||
|
{ validator: validateUsername, trigger: 'blur' }
|
||||||
|
],
|
||||||
|
phone: [{ validator: validatePhone, trigger: 'blur' }],
|
||||||
birthDate: [{ required: true, message: t('page.login.register.birthDateRequired') }],
|
birthDate: [{ required: true, message: t('page.login.register.birthDateRequired') }],
|
||||||
phone: [{ pattern: /^1[3-9]\d{9}$/, message: t('form.phone.invalid'), trigger: 'blur' }]
|
fullName: []
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// 第三步表单验证规则
|
// 第三步表单验证规则
|
||||||
const securityRules = computed<Record<string, Rule | Rule[]>>(() => {
|
const securityRules = computed<Record<string, Rule | Rule[]>>(() => {
|
||||||
const { formRules, createConfirmPwdRule } = useFormRules();
|
const { createConfirmPwdRule } = useFormRules();
|
||||||
|
|
||||||
|
const validateEmail = async (_rule: Rule, value: string) => {
|
||||||
|
if (!value) {
|
||||||
|
return Promise.reject(t('page.login.register.emailRequired'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const emailPattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/;
|
||||||
|
|
||||||
|
if (!emailPattern.test(value)) {
|
||||||
|
return Promise.reject(t('page.login.register.emailInvalid'));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { exists } = await authStore.checkUserRepeat({ email: value, authType: 'u' });
|
||||||
|
if (exists) {
|
||||||
|
return Promise.reject(t('page.login.register.emailExists'));
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: formRules.code,
|
email: [
|
||||||
password: formRules.pwd,
|
{ required: true, message: t('page.login.register.emailRequired'), trigger: 'change' },
|
||||||
|
{ validator: validateEmail, trigger: 'blur' }
|
||||||
|
],
|
||||||
|
code: [{ required: true, message: t('page.login.register.codeRequired') }],
|
||||||
|
password: [
|
||||||
|
{ required: true, message: t('page.login.register.passwordRequired') },
|
||||||
|
{ min: 6, message: t('page.login.register.passwordLength') }
|
||||||
|
],
|
||||||
confirmPassword: createConfirmPwdRule(securityModel.password)
|
confirmPassword: createConfirmPwdRule(securityModel.password)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -122,10 +184,10 @@ const terms = computed(() => {
|
|||||||
|
|
||||||
// 步骤控制函数
|
// 步骤控制函数
|
||||||
async function nextStep() {
|
async function nextStep() {
|
||||||
|
try {
|
||||||
if (currentStep.value === 0) {
|
if (currentStep.value === 0) {
|
||||||
await validate();
|
// 验证第一步表单
|
||||||
// 复制电话号码到第三步
|
await basicFormRef.value?.validate();
|
||||||
securityModel.email = basicModel.email;
|
|
||||||
}
|
}
|
||||||
if (currentStep.value === 1) {
|
if (currentStep.value === 1) {
|
||||||
if (!agreeTerms.value) {
|
if (!agreeTerms.value) {
|
||||||
@@ -133,32 +195,50 @@ async function nextStep() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 验证通过后增加步骤
|
||||||
currentStep.value += 1;
|
currentStep.value += 1;
|
||||||
|
} catch (error) {
|
||||||
|
// 验证失败时不增加步骤
|
||||||
|
console.error('Validation failed:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 返回
|
||||||
function prevStep() {
|
function prevStep() {
|
||||||
currentStep.value -= 1;
|
currentStep.value -= 1;
|
||||||
}
|
}
|
||||||
//注册按钮
|
|
||||||
|
async function handleCaptcha() {
|
||||||
|
const res = await getCaptcha(securityModel.email);
|
||||||
|
if (res) {
|
||||||
|
securityModel.uuid = res.data.uuid;
|
||||||
|
if (res.data?.text) {
|
||||||
|
securityModel.code = res.data.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册按钮
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
try {
|
try {
|
||||||
await validate();
|
await securityFormRef.value?.validate();
|
||||||
|
|
||||||
// 整合表单数据
|
// 整合表单数据
|
||||||
model.username = basicModel.username;
|
model.username = basicModel.username;
|
||||||
model.password = securityModel.password;
|
model.password = securityModel.password;
|
||||||
model.email = securityModel.email;
|
model.email = securityModel.email; // 使用第三步的 email
|
||||||
model.fullName = basicModel.fullName;
|
model.fullName = basicModel.fullName;
|
||||||
model.gender = basicModel.gender; // 直接使用 gender 值
|
model.gender = basicModel.gender;
|
||||||
model.phone = basicModel.phone;
|
model.phone = basicModel.phone;
|
||||||
model.address = basicModel.address;
|
model.address = basicModel.address;
|
||||||
model.code = securityModel.code;
|
model.code = securityModel.code;
|
||||||
|
model.uuid = securityModel.uuid;
|
||||||
|
|
||||||
const success = await authStore.register({
|
const success = await authStore.register({
|
||||||
...model,
|
...model,
|
||||||
age: dayjs().diff(dayjs(basicModel.birthDate), 'year'),
|
age: dayjs().diff(dayjs(basicModel.birthDate), 'year'),
|
||||||
sex: model.gender, // 直接使用 gender 值,不需要转换
|
sex: model.gender,
|
||||||
phonenumber: model.phone,
|
phonenumber: model.phone
|
||||||
});
|
});
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
@@ -175,6 +255,7 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<div class="register-container">
|
||||||
<ASteps
|
<ASteps
|
||||||
v-if="showSteps"
|
v-if="showSteps"
|
||||||
:current="currentStep"
|
:current="currentStep"
|
||||||
@@ -200,9 +281,9 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
|
|
||||||
<div class="step-content">
|
<div class="step-content">
|
||||||
<!-- 第一步:基本信息 -->
|
<!-- 第一步:基本信息 -->
|
||||||
<div v-if="currentStep === 0">
|
<div v-show="currentStep === 0">
|
||||||
<AForm
|
<AForm
|
||||||
ref="formRef"
|
ref="basicFormRef"
|
||||||
:model="basicModel"
|
:model="basicModel"
|
||||||
:rules="basicRules"
|
:rules="basicRules"
|
||||||
:label-wrap="true"
|
:label-wrap="true"
|
||||||
@@ -233,8 +314,8 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
<ACol :xs="12" :sm="12" :lg="24">
|
<ACol :xs="12" :sm="12" :lg="24">
|
||||||
<AFormItem name="gender" :label="t('page.login.register.gender')">
|
<AFormItem name="gender" :label="t('page.login.register.gender')">
|
||||||
<ASelect v-model:value="basicModel.gender">
|
<ASelect v-model:value="basicModel.gender">
|
||||||
<ASelectOption value="male">{{ t('page.login.register.male') }}</ASelectOption>
|
<ASelectOption value="0">{{ t('page.login.register.male') }}</ASelectOption>
|
||||||
<ASelectOption value="female">{{ t('page.login.register.female') }}</ASelectOption>
|
<ASelectOption value="1">{{ t('page.login.register.female') }}</ASelectOption>
|
||||||
</ASelect>
|
</ASelect>
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
</ACol>
|
</ACol>
|
||||||
@@ -243,11 +324,6 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
<AInput v-model:value="basicModel.phone" />
|
<AInput v-model:value="basicModel.phone" />
|
||||||
</AFormItem>
|
</AFormItem>
|
||||||
</ACol>
|
</ACol>
|
||||||
<ACol :lg="24" :span="24">
|
|
||||||
<AFormItem name="email" :label="t('page.login.register.email')">
|
|
||||||
<AInput v-model:value="basicModel.email" />
|
|
||||||
</AFormItem>
|
|
||||||
</ACol>
|
|
||||||
<ACol :lg="24" :span="24">
|
<ACol :lg="24" :span="24">
|
||||||
<AFormItem name="address" :label="t('page.login.register.address')">
|
<AFormItem name="address" :label="t('page.login.register.address')">
|
||||||
<ATextarea v-model:value="basicModel.address" :rows="2" />
|
<ATextarea v-model:value="basicModel.address" :rows="2" />
|
||||||
@@ -268,7 +344,7 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 第二步:协议 -->
|
<!-- 第二步:协议 -->
|
||||||
<div v-if="currentStep === 1">
|
<div v-show="currentStep === 1">
|
||||||
<ATextarea
|
<ATextarea
|
||||||
:value="terms"
|
:value="terms"
|
||||||
:rows="12"
|
:rows="12"
|
||||||
@@ -296,9 +372,9 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 第三步:安全信息 -->
|
<!-- 第三步:安全信息 -->
|
||||||
<div v-if="currentStep === 2">
|
<div v-show="currentStep === 2">
|
||||||
<AForm
|
<AForm
|
||||||
ref="formRef"
|
ref="securityFormRef"
|
||||||
:model="securityModel"
|
:model="securityModel"
|
||||||
:rules="securityRules"
|
:rules="securityRules"
|
||||||
:label-wrap="true"
|
:label-wrap="true"
|
||||||
@@ -322,7 +398,7 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
size="small"
|
size="small"
|
||||||
:disabled="isCounting"
|
:disabled="isCounting"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@click="getCaptcha(securityModel.email)"
|
@click="handleCaptcha()"
|
||||||
>
|
>
|
||||||
{{ label }}
|
{{ label }}
|
||||||
</AButton>
|
</AButton>
|
||||||
@@ -353,9 +429,22 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
</AForm>
|
</AForm>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.register-container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-content {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-form {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
:deep(.ant-form) {
|
:deep(.ant-form) {
|
||||||
.ant-form-item {
|
.ant-form-item {
|
||||||
@@ -433,6 +522,7 @@ const showSteps = computed(() => !isMobile.value);
|
|||||||
:deep(.ant-form-item-label) {
|
:deep(.ant-form-item-label) {
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
> label {
|
> label {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
|
|||||||
@@ -36,15 +36,26 @@ const rules = computed<RuleRecord>(() => {
|
|||||||
//phone: formRules.phone,
|
//phone: formRules.phone,
|
||||||
email:formRules.email,
|
email:formRules.email,
|
||||||
code:formRules.code,
|
code:formRules.code,
|
||||||
password: formRules.pwd,
|
password: formRules.userPwd,
|
||||||
confirmPassword: createConfirmPwdRule(model.password)
|
confirmPassword: createConfirmPwdRule(model.password)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
await validate();
|
// await validate();
|
||||||
// request to reset password
|
// // request to reset password
|
||||||
|
// $message?.success(t('page.login.common.validateSuccess'));
|
||||||
|
await validate();//验证表单内容
|
||||||
|
const { error } = await fetcodeReset({
|
||||||
|
email: model.email,
|
||||||
|
code: model.code,
|
||||||
|
password: model.password
|
||||||
|
});
|
||||||
|
if(!error){
|
||||||
$message?.success(t('page.login.common.validateSuccess'));
|
$message?.success(t('page.login.common.validateSuccess'));
|
||||||
|
toggleLoginModule('pwd-login');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>历史账单</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -0,0 +1,594 @@
|
|||||||
|
<template>
|
||||||
|
<div class="h-full">
|
||||||
|
<SimpleScrollbar>
|
||||||
|
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||||
|
<ACard
|
||||||
|
:title="t('page.package.title')"
|
||||||
|
:bordered="false"
|
||||||
|
:body-style="{ flex: 1, overflow: 'hidden' }"
|
||||||
|
class="flex-col-stretch sm:flex-1-hidden card-wrapper"
|
||||||
|
>
|
||||||
|
<template #extra>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<TableHeaderOperation
|
||||||
|
v-model:columns="columnChecks"
|
||||||
|
:loading="loading"
|
||||||
|
:show-delete="false"
|
||||||
|
@add="handleAdd"
|
||||||
|
@refresh="getData"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<ATable
|
||||||
|
ref="wrapperEl"
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="data"
|
||||||
|
:loading="loading"
|
||||||
|
row-key="id"
|
||||||
|
size="small"
|
||||||
|
:pagination="mobilePagination"
|
||||||
|
:scroll="scrollConfig"
|
||||||
|
class="h-full"
|
||||||
|
/>
|
||||||
|
</ACard>
|
||||||
|
</div>
|
||||||
|
</SimpleScrollbar>
|
||||||
|
|
||||||
|
<!-- 新增套餐弹窗 -->
|
||||||
|
<AModal
|
||||||
|
v-model:open="showModal"
|
||||||
|
:title="t('page.package.title')"
|
||||||
|
@ok="handleOk"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
width="600px"
|
||||||
|
>
|
||||||
|
<AForm
|
||||||
|
ref="formRef"
|
||||||
|
:model="formState"
|
||||||
|
:rules="rules"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:wrapper-col="{ span: 16 }"
|
||||||
|
>
|
||||||
|
<AFormItem :label="t('page.package.packagename')" name="packageName">
|
||||||
|
<AInput v-model:value="formState.packageName" :placeholder="t('page.package.plepackagename')" />
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :label="t('page.package.period')" required>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<AFormItem name="periodNum" class="mb-0 flex-1">
|
||||||
|
<AInputNumber
|
||||||
|
v-model:value="formState.periodNum"
|
||||||
|
:placeholder="t('page.package.pleperiod')"
|
||||||
|
:min="1"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem name="periodType" class="mb-0 flex-1">
|
||||||
|
<ASelect v-model:value="formState.periodType" :options="periodOptions" />
|
||||||
|
</AFormItem>
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :label="t('page.package.price')" name="price" :rules="[{ required: true, message: t('page.package.pleprice') }]">
|
||||||
|
<AInputNumber
|
||||||
|
v-model:value="formState.price"
|
||||||
|
:placeholder="t('page.package.pleprice')"
|
||||||
|
:min="0.01"
|
||||||
|
:precision="2"
|
||||||
|
style="width: 100%"
|
||||||
|
:addon-before="currencyStore.symbol"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :label="t('page.package.traffic')" name="traffic">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<ASwitch v-model:checked="formState.trafficEnable" />
|
||||||
|
<div v-if="formState.trafficEnable" class="flex gap-2 flex-1">
|
||||||
|
<AInputNumber
|
||||||
|
v-model:value="formState.traffic"
|
||||||
|
:placeholder="t('page.package.pletraffic')"
|
||||||
|
:min="1"
|
||||||
|
:max="1024"
|
||||||
|
:precision="0"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formState.trafficUnit"
|
||||||
|
:options="storageUnits.map(unit => ({ label: unit, value: unit }))"
|
||||||
|
style="width: 100px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :label="t('page.package.limit')" name="rateLimitId">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<ASwitch v-model:checked="formState.rateLimitEnable" />
|
||||||
|
<ASelect
|
||||||
|
v-if="formState.rateLimitEnable"
|
||||||
|
v-model:value="formState.rateLimitId"
|
||||||
|
:placeholder="t('page.package.plelimit')"
|
||||||
|
:options="rateLimitOptions"
|
||||||
|
:loading="!rateLimitOptions.length"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :label="t('page.package.duration')" name="duration">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<ASwitch v-model:checked="formState.durationEnable" />
|
||||||
|
<div v-if="formState.durationEnable" class="flex gap-2 flex-1">
|
||||||
|
<AInputNumber
|
||||||
|
v-model:value="formState.duration"
|
||||||
|
:placeholder="t('page.package.pleduration')"
|
||||||
|
:min="1"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formState.durationUnit"
|
||||||
|
:options="timeUnits.map(item => ({
|
||||||
|
label: item.label,
|
||||||
|
value: item.key }))"
|
||||||
|
style="width: 100px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :label="t('page.package.client')" name="clientNum">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<ASwitch v-model:checked="formState.clientNumEnable" />
|
||||||
|
<AInputNumber
|
||||||
|
v-if="formState.clientNumEnable"
|
||||||
|
v-model:value="formState.clientNum"
|
||||||
|
:placeholder="t('page.package.pleclient')"
|
||||||
|
:min="1"
|
||||||
|
:addon-after="t('page.package.unit')"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :label="t('page.package.usepackage')">
|
||||||
|
<ASwitch v-model:checked="formState.packageEnable" />
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
</AModal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="tsx">
|
||||||
|
import { useTable } from '@/hooks/common/table';
|
||||||
|
import { SimpleScrollbar } from '~/packages/materials/src';
|
||||||
|
import { computed, shallowRef, ref, onMounted } from 'vue';
|
||||||
|
import { useElementSize } from '@vueuse/core';
|
||||||
|
import { fetchPackageList, addPackage, fetchRateLimitList, updatePackage, deletePackage } from '@/service/api/auth';
|
||||||
|
import { Button as AButton, message, Modal, Form as AForm, Input as AInput, InputNumber as AInputNumber, Select as ASelect, Switch as ASwitch, Tag as ATag } from 'ant-design-vue';
|
||||||
|
import type { Rule } from 'ant-design-vue/es/form';
|
||||||
|
import { useCurrencyStore } from '@/views/billing/rule/modules/currency';
|
||||||
|
import {
|
||||||
|
formatBandwidth,
|
||||||
|
formatStorage,
|
||||||
|
useFormatTime,
|
||||||
|
convertStorage,
|
||||||
|
convertTime,
|
||||||
|
storageUnits,
|
||||||
|
useTimeUnits,
|
||||||
|
type StorageUnit,
|
||||||
|
type TimeUnit
|
||||||
|
} from '@/utils/units';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const timeUnits = useTimeUnits();
|
||||||
|
const formatTime = useFormatTime();
|
||||||
|
const wrapperEl = shallowRef<HTMLElement | null>(null);
|
||||||
|
const { height: wrapperElHeight } = useElementSize(wrapperEl);
|
||||||
|
const currencyStore = useCurrencyStore();
|
||||||
|
|
||||||
|
const scrollConfig = computed(() => {
|
||||||
|
return {
|
||||||
|
y: wrapperElHeight.value - 72,
|
||||||
|
x: 1000
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const periodMap: Record<number, string> = {
|
||||||
|
1: t('page.package.day'),
|
||||||
|
2: t('page.package.month'),
|
||||||
|
3: t('page.package.year')
|
||||||
|
};
|
||||||
|
|
||||||
|
const { columns, columnChecks, data, loading, getData, mobilePagination } = useTable({
|
||||||
|
apiFn: async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetchPackageList();
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
rows: response.data || [],
|
||||||
|
total: response.data?.length || 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
rows: [],
|
||||||
|
total: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
rowKey: 'id',
|
||||||
|
columns: (): AntDesign.TableColumn<Api.Auth.Package>[] => [
|
||||||
|
{
|
||||||
|
key: 'packageName',
|
||||||
|
dataIndex: 'packageName',
|
||||||
|
title: t('page.package.packagename'),
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'periodNum',
|
||||||
|
dataIndex: 'periodNum',
|
||||||
|
title: t('page.package.period'),
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ record }) => {
|
||||||
|
const { periodNum, periodType } = record;
|
||||||
|
const unit = periodMap[periodType as number] || '';
|
||||||
|
return `${periodNum}${unit}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'price',
|
||||||
|
dataIndex: 'price',
|
||||||
|
title: t('page.package.price')+currencyStore.symbol,
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ text }) => `${Number(text).toFixed(2)} ${currencyStore.symbol}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'traffic',
|
||||||
|
dataIndex: 'traffic',
|
||||||
|
title: t('page.package.traffic'),
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ text, record }) => {
|
||||||
|
if (!record.trafficEnable) return t('page.package.unlimit');
|
||||||
|
const { value, unit } = formatStorage(text);
|
||||||
|
return `${value} ${unit}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'rateLimitId',
|
||||||
|
dataIndex: 'rateLimitId',
|
||||||
|
title: t('page.package.limit'),
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ record }) => {
|
||||||
|
if (!record.rateLimitEnable) return t('page.package.unlimit');
|
||||||
|
const rateLimit = rateLimitData.value.find(item => item.id === record.rateLimitId);
|
||||||
|
if (!rateLimit) return '-';
|
||||||
|
const upLimitText = rateLimit.upLimitEnable
|
||||||
|
? `${t('page.package.up')}:${formatBandwidth(rateLimit.upLimit).value} ${formatBandwidth(rateLimit.upLimit).unit}`
|
||||||
|
: `${t('page.package.up')}:${t('page.package.unlimit')}`;
|
||||||
|
const downLimitText = rateLimit.downLimitEnable
|
||||||
|
? `${t('page.package.down')}:${formatBandwidth(rateLimit.downLimit).value} ${formatBandwidth(rateLimit.downLimit).unit}`
|
||||||
|
: `${t('page.package.down')}:${t('page.package.unlimit')}`;
|
||||||
|
return `${rateLimit.rateLimitName} (${upLimitText}/${downLimitText})`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'duration',
|
||||||
|
dataIndex: 'duration',
|
||||||
|
title: t('page.package.duration'),
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ text, record }) => {
|
||||||
|
if (!record.durationEnable) return t('page.package.unlimit');
|
||||||
|
const { value, unit } = formatTime(text);
|
||||||
|
return `${value} ${unit}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'clientNum',
|
||||||
|
dataIndex: 'clientNum',
|
||||||
|
title: t('page.package.client'),
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ text, record }) => {
|
||||||
|
if (!record.clientNumEnable) return t('page.package.unlimit');
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'packageEnable',
|
||||||
|
dataIndex: 'packageEnable',
|
||||||
|
title: t('page.package.status'),
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ text }) => (
|
||||||
|
<ATag color={text ? 'success' : 'error'}>
|
||||||
|
{text ? t('page.package.use') : t('page.package.unuse')}
|
||||||
|
</ATag>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'operate',
|
||||||
|
title: t('page.package.operate'),
|
||||||
|
align: 'center',
|
||||||
|
width: 200,
|
||||||
|
customRender: ({ record }) => (
|
||||||
|
<div class="flex justify-center gap-2">
|
||||||
|
<AButton type="link" onClick={() => handleEdit(record)}>
|
||||||
|
{t('page.package.edit')}
|
||||||
|
</AButton>
|
||||||
|
<AButton type="link" danger onClick={() => handleDelete(record)}>
|
||||||
|
{t('page.package.delete')}
|
||||||
|
</AButton>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const showModal = ref(false);
|
||||||
|
const formRef = ref();
|
||||||
|
|
||||||
|
interface PackageForm {
|
||||||
|
id?: string;
|
||||||
|
packageName: string;
|
||||||
|
periodNum: number;
|
||||||
|
periodType: number;
|
||||||
|
price: string;
|
||||||
|
trafficEnable: boolean;
|
||||||
|
traffic: number;
|
||||||
|
trafficUnit: StorageUnit;
|
||||||
|
rateLimitEnable: boolean;
|
||||||
|
rateLimitId?: number;
|
||||||
|
durationEnable: boolean;
|
||||||
|
duration: number;
|
||||||
|
durationUnit: TimeUnit;
|
||||||
|
clientNumEnable: boolean;
|
||||||
|
clientNum: number;
|
||||||
|
packageEnable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formState = ref<PackageForm>({
|
||||||
|
packageName: '',
|
||||||
|
periodNum: 1,
|
||||||
|
periodType: 2,
|
||||||
|
price: '',
|
||||||
|
trafficEnable: false,
|
||||||
|
traffic: 0,
|
||||||
|
trafficUnit: 'GB',
|
||||||
|
rateLimitEnable: false,
|
||||||
|
rateLimitId: undefined,
|
||||||
|
durationEnable: false,
|
||||||
|
duration: 0,
|
||||||
|
durationUnit: 'hour',
|
||||||
|
clientNumEnable: false,
|
||||||
|
clientNum: 0,
|
||||||
|
packageEnable: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules: Record<string, Rule[]> = {
|
||||||
|
packageName: [{ required: true, message: t('page.package.plepackagename'), trigger: 'blur' }],
|
||||||
|
periodNum: [{ required: true, message: t('page.package.pleperiod'), trigger: 'blur' }],
|
||||||
|
periodType: [{ required: true, message: t('page.package.pleunit'), trigger: 'change' }],
|
||||||
|
price: [{ required: true, message: t('page.package.pleprice'), trigger: 'blur' }],
|
||||||
|
traffic: [
|
||||||
|
{
|
||||||
|
validator: (_rule: Rule, value: number) => {
|
||||||
|
if (!formState.value.trafficEnable) return Promise.resolve();
|
||||||
|
if (!value || value <= 0) return Promise.reject(t('page.package.rejtraffic'));
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
rateLimitId: [
|
||||||
|
{
|
||||||
|
validator: (_rule: Rule, value: number) => {
|
||||||
|
if (!formState.value.rateLimitEnable) return Promise.resolve();
|
||||||
|
if (!value) return Promise.reject(t('page.package.plelimit'));
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
duration: [
|
||||||
|
{
|
||||||
|
validator: (_rule: Rule, value: number) => {
|
||||||
|
if (!formState.value.durationEnable) return Promise.resolve();
|
||||||
|
if (!value || value <= 0) return Promise.reject(t('page.package.rejduration'));
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
clientNum: [
|
||||||
|
{
|
||||||
|
validator: (_rule: Rule, value: number) => {
|
||||||
|
if (!formState.value.clientNumEnable) return Promise.resolve();
|
||||||
|
if (!value || value <= 0) return Promise.reject(t('page.package.rejclient'));
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const periodOptions =computed(()=> [
|
||||||
|
{ label: t('page.package.hour'), value: 0 },
|
||||||
|
{ label: t('page.package.day'), value: 1 },
|
||||||
|
{ label: t('page.package.month'), value: 2 },
|
||||||
|
{ label: t('page.package.year'), value: 3 }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const rateLimitOptions = ref<{ label: string; value: number }[]>([]);
|
||||||
|
|
||||||
|
const rateLimitData = ref<Api.Auth.RateLimit[]>([]);
|
||||||
|
|
||||||
|
const getRateLimitData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetchRateLimitList();
|
||||||
|
rateLimitData.value = response.data || [];
|
||||||
|
rateLimitOptions.value = rateLimitData.value.map(item => {
|
||||||
|
const upLimitText = item.upLimitEnable
|
||||||
|
? `${t('page.package.up')}:${formatBandwidth(item.upLimit).value} ${formatBandwidth(item.upLimit).unit}`
|
||||||
|
: `${t('page.package.up')}:${t('page.package.unlimit')}`;
|
||||||
|
const downLimitText = item.downLimitEnable
|
||||||
|
? `${t('page.package.down')}:${formatBandwidth(item.downLimit).value} ${formatBandwidth(item.downLimit).unit}`
|
||||||
|
: `${t('page.package.down')}:${t('page.package.unlimit')}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: `${item.rateLimitName} (${upLimitText}/${downLimitText})`,
|
||||||
|
value: item.id
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// console.error('error:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 编辑状态
|
||||||
|
const isEdit = ref(false);
|
||||||
|
const editId = ref<string>();
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
isEdit.value = false;
|
||||||
|
editId.value = undefined;
|
||||||
|
showModal.value = true;
|
||||||
|
getRateLimitData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
showModal.value = false;
|
||||||
|
isEdit.value = false;
|
||||||
|
editId.value = undefined;
|
||||||
|
formState.value = {
|
||||||
|
packageName: '',
|
||||||
|
periodNum: 1,
|
||||||
|
periodType: 2,
|
||||||
|
price: '',
|
||||||
|
trafficEnable: false,
|
||||||
|
traffic: 0,
|
||||||
|
trafficUnit: 'GB',
|
||||||
|
rateLimitEnable: false,
|
||||||
|
rateLimitId: undefined,
|
||||||
|
durationEnable: false,
|
||||||
|
duration: 0,
|
||||||
|
durationUnit:'hour',
|
||||||
|
clientNumEnable: false,
|
||||||
|
clientNum: 0,
|
||||||
|
packageEnable: true
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOk = async () => {
|
||||||
|
try {
|
||||||
|
await formRef.value?.validate();
|
||||||
|
// 准备基础数据
|
||||||
|
const baseData = {
|
||||||
|
packageName: formState.value.packageName,
|
||||||
|
periodNum: formState.value.periodNum,
|
||||||
|
periodType: formState.value.periodType,
|
||||||
|
price: formState.value.price,
|
||||||
|
trafficEnable: formState.value.trafficEnable,
|
||||||
|
rateLimitEnable: formState.value.rateLimitEnable,
|
||||||
|
rateLimitId: formState.value.rateLimitId,
|
||||||
|
durationEnable: formState.value.durationEnable,
|
||||||
|
clientNumEnable: formState.value.clientNumEnable,
|
||||||
|
clientNum: formState.value.clientNum,
|
||||||
|
packageEnable: formState.value.packageEnable
|
||||||
|
};
|
||||||
|
|
||||||
|
// 计算流量和时长
|
||||||
|
const traffic = formState.value.trafficEnable
|
||||||
|
? Math.round(convertStorage(formState.value.traffic, formState.value.trafficUnit, 'B'))
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
const duration = formState.value.durationEnable
|
||||||
|
? Math.round(convertTime(formState.value.duration, formState.value.durationUnit, 'second'))
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
if (isEdit.value) {
|
||||||
|
if (!editId.value) {
|
||||||
|
message.error(t('page.package.isnull'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 编辑模式
|
||||||
|
await updatePackage({
|
||||||
|
...baseData,
|
||||||
|
id: editId.value,
|
||||||
|
traffic,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
message.success(t('page.package.editsuc'));
|
||||||
|
} else {
|
||||||
|
// 新增模式
|
||||||
|
await addPackage({
|
||||||
|
...baseData,
|
||||||
|
traffic,
|
||||||
|
duration
|
||||||
|
});
|
||||||
|
message.success(t('page.package.addsuc'));
|
||||||
|
}
|
||||||
|
handleCancel();
|
||||||
|
getData();
|
||||||
|
} catch (error) {
|
||||||
|
// message.error(isEdit.value ? t('page.package.editerr') : t('page.package.adderr'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = async (record: Api.Auth.Package) => {
|
||||||
|
isEdit.value = true;
|
||||||
|
editId.value = record.id;
|
||||||
|
showModal.value = true;
|
||||||
|
await getRateLimitData();
|
||||||
|
|
||||||
|
const traffic = formatStorage(record.traffic);
|
||||||
|
const duration = formatTime(record.duration);
|
||||||
|
|
||||||
|
formState.value = {
|
||||||
|
packageName: record.packageName,
|
||||||
|
periodNum: record.periodNum,
|
||||||
|
periodType: record.periodType,
|
||||||
|
price: record.price,
|
||||||
|
trafficEnable: record.trafficEnable,
|
||||||
|
traffic: traffic.value,
|
||||||
|
trafficUnit: traffic.unit,
|
||||||
|
rateLimitEnable: record.rateLimitEnable,
|
||||||
|
rateLimitId: record.rateLimitId,
|
||||||
|
durationEnable: record.durationEnable,
|
||||||
|
duration: duration.value,
|
||||||
|
durationUnit: duration.unit,
|
||||||
|
clientNumEnable: record.clientNumEnable,
|
||||||
|
clientNum: record.clientNum,
|
||||||
|
packageEnable: record.packageEnable
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = (record: Api.Auth.Package) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('page.package.confirmdelete'),
|
||||||
|
content: t('page.package.deletecontent'),
|
||||||
|
okText: t('page.package.confirm'),
|
||||||
|
cancelText: t('page.package.close'),
|
||||||
|
okType: 'danger',
|
||||||
|
async onOk() {
|
||||||
|
try {
|
||||||
|
await deletePackage(record.id);
|
||||||
|
message.success(t('page.package.deletesuc'));
|
||||||
|
getData();
|
||||||
|
} catch (error) {
|
||||||
|
// message.error(t('page.package.deleteerr'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getRateLimitData();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.h-full {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
<template>
|
||||||
|
<SimpleScrollbar>
|
||||||
|
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||||
|
<ACard
|
||||||
|
:title="t('page.ratelimit.title')"
|
||||||
|
:bordered="false"
|
||||||
|
:body-style="{ flex: 1, overflow: 'hidden' }"
|
||||||
|
class="flex-col-stretch sm:flex-1-hidden card-wrapper"
|
||||||
|
>
|
||||||
|
<template #extra>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<TableHeaderOperation
|
||||||
|
v-model:columns="columnChecks"
|
||||||
|
:loading="loading"
|
||||||
|
:show-delete="false"
|
||||||
|
:show-add="false"
|
||||||
|
@refresh="getData"
|
||||||
|
@add="handleAdd"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<ATable
|
||||||
|
ref="wrapperEl"
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="data"
|
||||||
|
:loading="loading"
|
||||||
|
row-key="rateLimitName"
|
||||||
|
size="small"
|
||||||
|
:pagination="mobilePagination"
|
||||||
|
:scroll="scrollConfig"
|
||||||
|
class="h-full"
|
||||||
|
/>
|
||||||
|
</ACard>
|
||||||
|
|
||||||
|
<!-- 新增限速配置弹窗 -->
|
||||||
|
<AModal
|
||||||
|
v-model:visible="showModal"
|
||||||
|
:title="isEdit ? t('page.ratelimit.change') : t('page.ratelimit.add')"
|
||||||
|
@ok="handleOk"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<AForm
|
||||||
|
ref="formRef"
|
||||||
|
:model="formState"
|
||||||
|
:rules="rules"
|
||||||
|
:label-col="{ span: 9 }"
|
||||||
|
:wrapper-col="{ span: 13 }"
|
||||||
|
>
|
||||||
|
<AFormItem :label="t('page.ratelimit.name')" name="rateLimitName">
|
||||||
|
<AInput v-model:value="formState.rateLimitName" :placeholder="t('page.ratelimit.plename')" />
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :label="t('page.ratelimit.upratelimit')" name="upLimitEnable">
|
||||||
|
<ACheckbox v-model:checked="formState.upLimitEnable">{{ t('page.ratelimit.useuplimit') }}</ACheckbox>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
v-if="formState.upLimitEnable"
|
||||||
|
:label="t('page.ratelimit.uplimit')"
|
||||||
|
name="upLimit"
|
||||||
|
>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<AFormItem name="upLimit" class="mb-0 flex-1">
|
||||||
|
<AInputNumber
|
||||||
|
v-model:value="formState.upLimit"
|
||||||
|
:placeholder="t('page.ratelimit.pleuplimit')"
|
||||||
|
:min="1"
|
||||||
|
:max="1024"
|
||||||
|
:precision="0"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem name="upLimitUnit" class="mb-0">
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formState.upLimitUnit"
|
||||||
|
:options="bandwidthUnits.map(unit => ({ label: unit, value: unit }))"
|
||||||
|
style="width: 100px"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem :label="t('page.ratelimit.downratelimit')" name="downLimitEnable">
|
||||||
|
<ACheckbox v-model:checked="formState.downLimitEnable">{{ t('page.ratelimit.usedownlimit') }}</ACheckbox>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
v-if="formState.downLimitEnable"
|
||||||
|
:label="t('page.ratelimit.downlimit')"
|
||||||
|
name="downLimit"
|
||||||
|
>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<AFormItem name="downLimit" class="mb-0 flex-1">
|
||||||
|
<AInputNumber
|
||||||
|
v-model:value="formState.downLimit"
|
||||||
|
:placeholder="t('page.ratelimit.pledownlimit')"
|
||||||
|
:min="1"
|
||||||
|
:max="1024"
|
||||||
|
:precision="0"
|
||||||
|
style="width: 100%"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem name="downLimitUnit" class="mb-0">
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formState.downLimitUnit"
|
||||||
|
:options="bandwidthUnits.map(unit => ({ label: unit, value: unit }))"
|
||||||
|
style="width: 100px"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
</div>
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
</AModal>
|
||||||
|
</div>
|
||||||
|
</SimpleScrollbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="tsx">
|
||||||
|
import { useTable } from '@/hooks/common/table';
|
||||||
|
import { SimpleScrollbar } from '~/packages/materials/src';
|
||||||
|
import { computed, shallowRef, ref } from 'vue';
|
||||||
|
import { useElementSize } from '@vueuse/core';
|
||||||
|
import { fetchRateLimitList, addRateLimit, editRateLimit, removeRateLimit } from '@/service/api/auth';
|
||||||
|
import { message, Modal, Button } from 'ant-design-vue';
|
||||||
|
import type { Rule } from 'ant-design-vue/es/form';
|
||||||
|
import { PlusOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { bandwidthUnits, convertBandwidth, formatBandwidth, type BandwidthUnit } from '@/utils/units';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
interface RateLimitForm extends Omit<Api.Auth.RateLimitAdd, 'upLimit' | 'downLimit'> {
|
||||||
|
upLimit: number;
|
||||||
|
downLimit: number;
|
||||||
|
upLimitUnit: BandwidthUnit;
|
||||||
|
downLimitUnit: BandwidthUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wrapperEl = shallowRef<HTMLElement | null>(null);
|
||||||
|
const { height: wrapperElHeight } = useElementSize(wrapperEl);
|
||||||
|
|
||||||
|
const scrollConfig = computed(() => {
|
||||||
|
return {
|
||||||
|
y: wrapperElHeight.value - 72,
|
||||||
|
x: 1000
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const showModal = ref(false);
|
||||||
|
const formRef = ref();
|
||||||
|
const formState = ref<RateLimitForm>({
|
||||||
|
rateLimitName: '',
|
||||||
|
upLimitEnable: false,
|
||||||
|
downLimitEnable: false,
|
||||||
|
upLimit: 0,
|
||||||
|
downLimit: 0,
|
||||||
|
upLimitUnit: 'Mbps',
|
||||||
|
downLimitUnit: 'Mbps'
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules: Record<string, Rule[]> = {
|
||||||
|
rateLimitName: [{ required: true, message: t('page.ratelimit.plename'), trigger: 'blur' }],
|
||||||
|
upLimit: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('page.ratelimit.pleuplimit'),
|
||||||
|
trigger: 'blur',
|
||||||
|
validator: (_rule: Rule, value: number) => {
|
||||||
|
if (!formState.value.upLimitEnable) return Promise.resolve();
|
||||||
|
if (!value || value <= 0) return Promise.reject(t('page.ratelimit.reject'));
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
downLimit: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('page.ratelimit.pledownlimit'),
|
||||||
|
trigger: 'blur',
|
||||||
|
validator: (_rule: Rule, value: number) => {
|
||||||
|
if (!formState.value.downLimitEnable) return Promise.resolve();
|
||||||
|
if (!value || value <= 0) return Promise.reject(t('page.ratelimit.reject'));
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const isEdit = ref(false);
|
||||||
|
const editId = ref<number>();
|
||||||
|
|
||||||
|
const handleAdd = () => {
|
||||||
|
isEdit.value = false;
|
||||||
|
editId.value = undefined;
|
||||||
|
formState.value = {
|
||||||
|
rateLimitName: '',
|
||||||
|
upLimitEnable: false,
|
||||||
|
downLimitEnable: false,
|
||||||
|
upLimit: 0,
|
||||||
|
downLimit: 0,
|
||||||
|
upLimitUnit: 'Mbps',
|
||||||
|
downLimitUnit: 'Mbps'
|
||||||
|
};
|
||||||
|
showModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEdit = (record: Api.Auth.RateLimit) => {
|
||||||
|
isEdit.value = true;
|
||||||
|
editId.value = record.id;
|
||||||
|
|
||||||
|
formState.value = {
|
||||||
|
rateLimitName: record.rateLimitName,
|
||||||
|
upLimitEnable: record.upLimitEnable,
|
||||||
|
downLimitEnable: record.downLimitEnable,
|
||||||
|
upLimit: convertBandwidth(record.upLimit, 'Kbps', 'Mbps'),
|
||||||
|
downLimit: convertBandwidth(record.downLimit, 'Kbps', 'Mbps'),
|
||||||
|
upLimitUnit: 'Mbps',
|
||||||
|
downLimitUnit: 'Mbps'
|
||||||
|
};
|
||||||
|
|
||||||
|
showModal.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = (record: Api.Auth.RateLimit) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('page.ratelimit.confirmdelete'),
|
||||||
|
icon: () => <ExclamationCircleOutlined />,
|
||||||
|
content: `${t('page.ratelimit.deletecontant')} "${record.rateLimitName}"?`,
|
||||||
|
async onOk() {
|
||||||
|
try {
|
||||||
|
await removeRateLimit(record.id);
|
||||||
|
message.success(t('page.ratelimit.deletesuc'));
|
||||||
|
getData();
|
||||||
|
} catch (error) {
|
||||||
|
// console.error('error:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
showModal.value = false;
|
||||||
|
formState.value = {
|
||||||
|
rateLimitName: '',
|
||||||
|
upLimitEnable: false,
|
||||||
|
downLimitEnable: false,
|
||||||
|
upLimit: 0,
|
||||||
|
downLimit: 0,
|
||||||
|
upLimitUnit: 'Mbps',
|
||||||
|
downLimitUnit: 'Mbps'
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOk = async () => {
|
||||||
|
try {
|
||||||
|
await formRef.value?.validate();
|
||||||
|
const submitData = {
|
||||||
|
...formState.value,
|
||||||
|
upLimit: formState.value.upLimitEnable
|
||||||
|
? Math.round(convertBandwidth(formState.value.upLimit, formState.value.upLimitUnit, 'Kbps'))
|
||||||
|
: 0,
|
||||||
|
downLimit: formState.value.downLimitEnable
|
||||||
|
? Math.round(convertBandwidth(formState.value.downLimit, formState.value.downLimitUnit, 'Kbps'))
|
||||||
|
: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isEdit.value) {
|
||||||
|
if (!editId.value) {
|
||||||
|
message.error(t('page.ratelimit.idnull'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {error} = await editRateLimit({
|
||||||
|
id: editId.value,
|
||||||
|
rateLimitName: submitData.rateLimitName,
|
||||||
|
upLimitEnable: submitData.upLimitEnable,
|
||||||
|
downLimitEnable: submitData.downLimitEnable,
|
||||||
|
upLimit: submitData.upLimit,
|
||||||
|
downLimit: submitData.downLimit
|
||||||
|
});
|
||||||
|
if(!error) {
|
||||||
|
message.success(t('page.ratelimit.changesuc'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const{ error } = await addRateLimit(submitData);
|
||||||
|
if(!error) {
|
||||||
|
message.success(t('page.ratelimit.addsuc'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleCancel();
|
||||||
|
getData();
|
||||||
|
} catch (error) {
|
||||||
|
// message.error(isEdit.value ? 'change error' : 'add error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const {
|
||||||
|
columns,
|
||||||
|
columnChecks,
|
||||||
|
data,
|
||||||
|
loading,
|
||||||
|
getData,
|
||||||
|
mobilePagination
|
||||||
|
} = useTable({
|
||||||
|
apiFn: async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetchRateLimitList();
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
rows: response.data || [],
|
||||||
|
total: response.data?.length || 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
rows: [],
|
||||||
|
total: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
immediate: true,
|
||||||
|
rowKey: 'id',
|
||||||
|
columns: (): AntDesign.TableColumn<Api.Auth.RateLimit>[] => [
|
||||||
|
{
|
||||||
|
key: 'rateLimitName',
|
||||||
|
dataIndex: 'rateLimitName',
|
||||||
|
title: t('page.ratelimit.name'),
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'upLimit',
|
||||||
|
dataIndex: 'upLimit',
|
||||||
|
title: t('page.ratelimit.upratelimit'),
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ text, record }) => {
|
||||||
|
if (!record.upLimitEnable) return t('page.ratelimit.unlimit');
|
||||||
|
const { value, unit } = formatBandwidth(text);
|
||||||
|
return `${value} ${unit}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'downLimit',
|
||||||
|
dataIndex: 'downLimit',
|
||||||
|
title: t('page.ratelimit.downratelimit'),
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ text, record }) => {
|
||||||
|
if (!record.downLimitEnable) return t('page.ratelimit.unlimit');
|
||||||
|
const { value, unit } = formatBandwidth(text);
|
||||||
|
return `${value} ${unit}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.ratelimit.operate'),
|
||||||
|
key: 'operate',
|
||||||
|
align: 'center',
|
||||||
|
width: 200,
|
||||||
|
fixed: 'right',
|
||||||
|
customRender: ({ record }) => (
|
||||||
|
<div class="flex justify-center gap-2">
|
||||||
|
<Button type="link" onClick={() => handleEdit(record)}>
|
||||||
|
{ t('page.ratelimit.changed') }
|
||||||
|
</Button>
|
||||||
|
<Button type="link" danger onClick={() => handleDelete(record)}>
|
||||||
|
{t('page.ratelimit.delete')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -0,0 +1,393 @@
|
|||||||
|
<template>
|
||||||
|
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||||
|
<!-- 货币设置卡片 -->
|
||||||
|
<ACard
|
||||||
|
:title="t('page.rule.title')"
|
||||||
|
:bordered="false"
|
||||||
|
class="flex-col-stretch"
|
||||||
|
>
|
||||||
|
<div class="currency-selector">
|
||||||
|
<ASpace size="large">
|
||||||
|
<div class="selector-item">
|
||||||
|
<span class="selector-label">{{ t('page.rule.currencySelect') }}:</span>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="selectedCurrency"
|
||||||
|
style="width: 120px"
|
||||||
|
@change="handleCurrencyChange"
|
||||||
|
>
|
||||||
|
<ASelect.Option
|
||||||
|
v-for="currency in availableCurrencies"
|
||||||
|
:key="currency.code"
|
||||||
|
:value="currency.code"
|
||||||
|
>
|
||||||
|
{{ currency.code }}
|
||||||
|
</ASelect.Option>
|
||||||
|
</ASelect>
|
||||||
|
</div>
|
||||||
|
<div class="selector-item">
|
||||||
|
<span class="selector-label">{{ t('page.rule.currencySymbol') }}:</span>
|
||||||
|
<span class="currency-symbol">{{ currencyStore.symbol }}</span>
|
||||||
|
</div>
|
||||||
|
</ASpace>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 支付方式配置 -->
|
||||||
|
<div class="payment-selector">
|
||||||
|
<ASpace size="large">
|
||||||
|
<div class="selector-item">
|
||||||
|
<span class="selector-label">{{ t('page.rule.paymentMethods') }}:</span>
|
||||||
|
</div>
|
||||||
|
<div class="selector-item">
|
||||||
|
<ACheckbox.Group
|
||||||
|
v-model:value="selectedPaymentMethods"
|
||||||
|
:options="paymentOptions"
|
||||||
|
@change="handlePaymentMethodsChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</ASpace>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 计费规则表格 -->
|
||||||
|
<ATable
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="data"
|
||||||
|
:loading="loading"
|
||||||
|
row-key="id"
|
||||||
|
size="small"
|
||||||
|
:pagination="false"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<ASpace>
|
||||||
|
<AButton type="primary" ghost @click="handleEdit(record)">{{ t('page.rule.edit') }}</AButton>
|
||||||
|
</ASpace>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</ATable>
|
||||||
|
</ACard>
|
||||||
|
|
||||||
|
<!-- 编辑抽屉 -->
|
||||||
|
<ADrawer
|
||||||
|
v-model:visible="drawerVisible"
|
||||||
|
:title="drawerTitle"
|
||||||
|
placement="right"
|
||||||
|
width="500px"
|
||||||
|
@close="closeDrawer"
|
||||||
|
>
|
||||||
|
<AForm
|
||||||
|
v-if="currentRule"
|
||||||
|
ref="formRef"
|
||||||
|
:model="currentRule"
|
||||||
|
:rules="rules"
|
||||||
|
layout="vertical"
|
||||||
|
>
|
||||||
|
<AFormItem :label="t('page.rule.traffic')" name="traffic">
|
||||||
|
<AInputNumber
|
||||||
|
v-model:value="currentRule.traffic"
|
||||||
|
:min="1"
|
||||||
|
:precision="0"
|
||||||
|
style="width: 100%"
|
||||||
|
:placeholder="t('page.rule.pletraffic')"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="t('page.rule.price')" name="price">
|
||||||
|
<AInputNumber
|
||||||
|
v-model:value="currentRule.price"
|
||||||
|
:min="0"
|
||||||
|
:precision="2"
|
||||||
|
style="width: 100%"
|
||||||
|
:placeholder="t('page.rule.pleprice')"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="t('page.rule.unit')" name="unit">
|
||||||
|
<ASelect
|
||||||
|
v-model:value="currentRule.unit"
|
||||||
|
style="width: 100%"
|
||||||
|
:placeholder="t('page.rule.pleunit')"
|
||||||
|
>
|
||||||
|
<ASelect.Option
|
||||||
|
v-for="option in unitOptions"
|
||||||
|
:key="option.value"
|
||||||
|
:value="option.value"
|
||||||
|
>
|
||||||
|
{{ option.label }}
|
||||||
|
</ASelect.Option>
|
||||||
|
</ASelect>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem :label="t('page.rule.status')" name="enable">
|
||||||
|
<ASwitch v-model:checked="currentRule.enable" />
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<ASpace>
|
||||||
|
<AButton @click="closeDrawer">{{ t('page.rule.close') }}</AButton>
|
||||||
|
<AButton type="primary" :loading="submitLoading" @click="handleSubmit">{{ t('page.rule.confirm') }}</AButton>
|
||||||
|
</ASpace>
|
||||||
|
</template>
|
||||||
|
</ADrawer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { fetchBillRuleList, updateBillRule, updatePaymentConfig, getPaymentConfig } from '@/service/api/auth';
|
||||||
|
import {
|
||||||
|
Card as ACard,
|
||||||
|
Table as ATable,
|
||||||
|
Space as ASpace,
|
||||||
|
Switch as ASwitch,
|
||||||
|
Button as AButton,
|
||||||
|
Drawer as ADrawer,
|
||||||
|
Form as AForm,
|
||||||
|
FormItem as AFormItem,
|
||||||
|
InputNumber as AInputNumber,
|
||||||
|
message,
|
||||||
|
Select as ASelect,
|
||||||
|
Descriptions as ADescriptions,
|
||||||
|
DescriptionsItem as ADescriptionsItem,
|
||||||
|
Checkbox as ACheckbox
|
||||||
|
} from 'ant-design-vue';
|
||||||
|
import type { FormInstance } from 'ant-design-vue';
|
||||||
|
import type { ColumnsType } from 'ant-design-vue/es/table';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useCurrencyStore, availableCurrencies } from '@/views/billing/rule/modules/currency';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const currencyStore = useCurrencyStore();
|
||||||
|
const selectedCurrency = ref(currencyStore.code);
|
||||||
|
|
||||||
|
interface BillRule {
|
||||||
|
id: number;
|
||||||
|
traffic: number;
|
||||||
|
price: number;
|
||||||
|
unit: number;
|
||||||
|
enable: boolean;
|
||||||
|
createBy: string | null;
|
||||||
|
createTime: string;
|
||||||
|
updateBy: string | null;
|
||||||
|
updateTime: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BillRuleUpdate {
|
||||||
|
traffic: number;
|
||||||
|
price: number;
|
||||||
|
unit: number;
|
||||||
|
enable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const submitLoading = ref(false);
|
||||||
|
const data = ref<BillRule[]>([]);
|
||||||
|
const drawerVisible = ref(false);
|
||||||
|
const drawerTitle = ref(t('page.rule.modaltitle'));
|
||||||
|
const currentRule = ref<BillRuleUpdate | null>(null);
|
||||||
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
// 单位选项
|
||||||
|
const unitOptions = [
|
||||||
|
{ label: 'B', value: 0 },
|
||||||
|
{ label: 'KB', value: 1 },
|
||||||
|
{ label: 'MB', value: 2 },
|
||||||
|
{ label: 'GB', value: 3 },
|
||||||
|
{ label: 'TB', value: 4 }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 获取单位显示文本
|
||||||
|
const getUnitText = (unit: number) => {
|
||||||
|
return unitOptions.find(option => option.value === unit)?.label || '';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 支付方式配置
|
||||||
|
const paymentOptions = [
|
||||||
|
{ label: 'PayPal', value: 'paypal' },
|
||||||
|
{ label: 'Stripe', value: 'stripe' },
|
||||||
|
{ label: 'Alipay', value: 'alipay' },
|
||||||
|
{ label: 'WeChat Pay', value: 'wxpay' },
|
||||||
|
];
|
||||||
|
const selectedPaymentMethods = ref<string[]>(['paypal','stripe']);
|
||||||
|
|
||||||
|
// 处理货币变更
|
||||||
|
const handleCurrencyChange = async (value: string) => {
|
||||||
|
currencyStore.setCurrency(value);
|
||||||
|
// 同步更新支付配置
|
||||||
|
try {
|
||||||
|
await updatePaymentConfig({
|
||||||
|
currency: value,
|
||||||
|
currencySymbol: currencyStore.symbol,
|
||||||
|
paymentMethods: selectedPaymentMethods.value
|
||||||
|
});
|
||||||
|
message.success(t('page.rule.updatesuc'));
|
||||||
|
} catch (error) {
|
||||||
|
message.error(t('page.rule.updatefail'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理支付方式变更
|
||||||
|
const handlePaymentMethodsChange = async (values: string[]) => {
|
||||||
|
selectedPaymentMethods.value = values;
|
||||||
|
try {
|
||||||
|
await updatePaymentConfig({
|
||||||
|
currency: selectedCurrency.value,
|
||||||
|
currencySymbol: currencyStore.symbol,
|
||||||
|
paymentMethods: values
|
||||||
|
});
|
||||||
|
message.success(t('page.rule.updatesuc'));
|
||||||
|
} catch (error) {
|
||||||
|
message.error(t('page.rule.updatefail'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns: ColumnsType = [
|
||||||
|
{
|
||||||
|
title: t('page.rule.traffic'),
|
||||||
|
dataIndex: 'traffic',
|
||||||
|
key: 'traffic',
|
||||||
|
align: 'center',
|
||||||
|
width: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.rule.price'),
|
||||||
|
dataIndex: 'price',
|
||||||
|
key: 'price',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
customRender: ({ text }) => `${currencyStore.symbol}${text}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.rule.unit'),
|
||||||
|
dataIndex: 'unit',
|
||||||
|
key: 'unit',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
customRender: ({ text }) => getUnitText(text)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.rule.status'),
|
||||||
|
dataIndex: 'enable',
|
||||||
|
key: 'enable',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
customRender: ({ text: enable }) => (enable ? t('page.rule.use') : t('page.rule.unuse'))
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.rule.action'),
|
||||||
|
key: 'action',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
fixed: 'right'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
traffic: [{ required: true, message: t('page.rule.pletraffic') }],
|
||||||
|
price: [{ required: true, message: t('page.rule.pleprice') }],
|
||||||
|
unit: [{ required: true, message: t('page.rule.pleunit') }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取列表数据
|
||||||
|
const getData = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await fetchBillRuleList();
|
||||||
|
if (res.data && Array.isArray(res.data)) {
|
||||||
|
data.value = res.data;
|
||||||
|
} else {
|
||||||
|
data.value = [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
data.value = [];
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取支付配置
|
||||||
|
const getPayConfig = async () => {
|
||||||
|
try {
|
||||||
|
const res = await getPaymentConfig();
|
||||||
|
if (res.data) {
|
||||||
|
// 更新货币和支付方式
|
||||||
|
selectedCurrency.value = res.data.currency;
|
||||||
|
currencyStore.setCurrency(res.data.currency);
|
||||||
|
selectedPaymentMethods.value = res.data.paymentMethods;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
message.error(t('page.rule.getConfigFail'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开编辑抽屉
|
||||||
|
const handleEdit = (record: BillRule) => {
|
||||||
|
currentRule.value = { ...record };
|
||||||
|
drawerVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭抽屉
|
||||||
|
const closeDrawer = () => {
|
||||||
|
drawerVisible.value = false;
|
||||||
|
currentRule.value = null;
|
||||||
|
formRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!currentRule.value) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await formRef.value?.validate();
|
||||||
|
submitLoading.value = true;
|
||||||
|
|
||||||
|
await updateBillRule(currentRule.value);
|
||||||
|
message.success(t('page.rule.updatesuc'));
|
||||||
|
closeDrawer();
|
||||||
|
getData();
|
||||||
|
} catch (error) {
|
||||||
|
} finally {
|
||||||
|
submitLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getData();
|
||||||
|
getPayConfig(); // 获取支付配置
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.currency-selector {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector-label {
|
||||||
|
color: rgba(0, 0, 0, 0.85);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.currency-symbol {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
min-width: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment-selector {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-form-item) {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-descriptions-item) {
|
||||||
|
padding-bottom: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
interface CurrencyOption {
|
||||||
|
code: string
|
||||||
|
symbol: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CurrencyState {
|
||||||
|
currentCurrency: CurrencyOption
|
||||||
|
}
|
||||||
|
|
||||||
|
export const availableCurrencies: CurrencyOption[] = [
|
||||||
|
{ code: 'USD', symbol: '$', name: '美元' },
|
||||||
|
{ code: 'CNY', symbol: '¥', name: '人民币' },
|
||||||
|
{ code: 'EUR', symbol: '€', name: '欧元' },
|
||||||
|
{ code: 'GBP', symbol: '£', name: '英镑' },
|
||||||
|
{ code: 'AUD', symbol: '$', name: '澳元' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const useCurrencyStore = defineStore('currency', {
|
||||||
|
state: (): CurrencyState => ({
|
||||||
|
currentCurrency: availableCurrencies[0]
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
setCurrency(currencyCode: string) {
|
||||||
|
const currency = availableCurrencies.find(c => c.code === currencyCode)
|
||||||
|
if (currency) {
|
||||||
|
this.currentCurrency = currency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getters: {
|
||||||
|
symbol: (state: CurrencyState): string => state.currentCurrency.symbol,
|
||||||
|
code: (state: CurrencyState): string => state.currentCurrency.code,
|
||||||
|
name: (state: CurrencyState): string => state.currentCurrency.name
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -11,22 +11,22 @@ import CreativityBanner from './modules/creativity-banner.vue';
|
|||||||
<ASpace direction="vertical" :size="16">
|
<ASpace direction="vertical" :size="16">
|
||||||
<HeaderBanner />
|
<HeaderBanner />
|
||||||
<CardData />
|
<CardData />
|
||||||
<ARow :gutter="[16, 16]">
|
<!-- <ARow :gutter="[16, 16]">-->
|
||||||
<ACol :span="24" :lg="14">
|
<!-- <ACol :span="24" :lg="14">-->
|
||||||
<LineChart />
|
<!-- <LineChart />-->
|
||||||
</ACol>
|
<!-- </ACol>-->
|
||||||
<ACol :span="24" :lg="10">
|
<!-- <ACol :span="24" :lg="10">-->
|
||||||
<PieChart />
|
<!-- <PieChart />-->
|
||||||
</ACol>
|
<!-- </ACol>-->
|
||||||
</ARow>
|
<!-- </ARow>-->
|
||||||
<ARow :gutter="[16, 16]">
|
<!-- <ARow :gutter="[16, 16]">-->
|
||||||
<ACol :span="24" :lg="14">
|
<!-- <ACol :span="24" :lg="14">-->
|
||||||
<ProjectNews />
|
<!-- <ProjectNews />-->
|
||||||
</ACol>
|
<!-- </ACol>-->
|
||||||
<ACol :span="24" :lg="10">
|
<!-- <ACol :span="24" :lg="10">-->
|
||||||
<CreativityBanner />
|
<!-- <CreativityBanner />-->
|
||||||
</ACol>
|
<!-- </ACol>-->
|
||||||
</ARow>
|
<!-- </ARow>-->
|
||||||
</ASpace>
|
</ASpace>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -0,0 +1,662 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import type { TableColumnType } from 'ant-design-vue';
|
||||||
|
import {
|
||||||
|
EnvironmentOutlined,
|
||||||
|
SearchOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
InfoCircleOutlined
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
|
import { getDashboardSiteList, addSite, deleteSite, getSiteConfig, updateSite, getMeshConfig, updateMeshConfig, getRoamingConfig, updateRoamingConfig } from '@/service/api/auth';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { Form, Modal, Divider, Checkbox, Select, Input, Button } from 'ant-design-vue';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
import { regionOptions, timeZoneOptions } from '@/constants/site-options';
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'CardData'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单实例
|
||||||
|
const formRef = ref();
|
||||||
|
const useForm = Form.useForm;
|
||||||
|
|
||||||
|
// 弹窗控制
|
||||||
|
const showAddDialog = ref(false);
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const formData = ref({
|
||||||
|
name: '',
|
||||||
|
region: '',
|
||||||
|
timeZone: '',
|
||||||
|
scenario: '',
|
||||||
|
deviceAccountSetting: {
|
||||||
|
username: '',
|
||||||
|
password: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单验证规则
|
||||||
|
const { validate, validateInfos } = useForm(formData, {
|
||||||
|
name: [
|
||||||
|
{ required: true, message: t('page.carddata.nameRequired') },
|
||||||
|
{
|
||||||
|
pattern: /^[^ \+\-\@\=]$|^[^ \+\-\@\=].{0,62}[^ ]$/,
|
||||||
|
message: t('page.carddata.nameInvalid')
|
||||||
|
}
|
||||||
|
],
|
||||||
|
region: [{ required: true, message: t('page.carddata.regionRequired') }],
|
||||||
|
timeZone: [{ required: true, message: t('page.carddata.timeZoneRequired') }],
|
||||||
|
scenario: [{ required: true, message: t('page.carddata.scenarioRequired') }],
|
||||||
|
'deviceAccountSetting.username': [
|
||||||
|
{ required: true, message: t('page.carddata.usernameRequired') },
|
||||||
|
{
|
||||||
|
pattern: /^[\x21-\x7E]{1,64}$/,
|
||||||
|
message: t('page.carddata.usernameInvalid')
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'deviceAccountSetting.password': [
|
||||||
|
{ required: true, message: t('page.carddata.passwordRequired') },
|
||||||
|
{
|
||||||
|
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!#\$%&'\(\)\*\+,\-\.\/\:;\<\=\>\@\[\\\]\^_`\{\|\}\~])(?!.*[\x00-\x20\x22\x3f\x0f7]).{8,64}$/,
|
||||||
|
message: t('page.carddata.passwordInvalid')
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 使用场景选项
|
||||||
|
const scenarioOptions = [
|
||||||
|
{ label: t('page.carddata.office'), value: 'office' },
|
||||||
|
{ label: t('page.carddata.hotel'), value: 'hotel' },
|
||||||
|
{ label: t('page.carddata.education'), value: 'education' },
|
||||||
|
{ label: t('page.carddata.retail'), value: 'retail' },
|
||||||
|
{ label: t('page.carddata.other'), value: 'other' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 处理添加站点
|
||||||
|
const handleAddSite = async () => {
|
||||||
|
try {
|
||||||
|
await validate();
|
||||||
|
const response = await addSite(formData.value);
|
||||||
|
if (response) {
|
||||||
|
message.success(t('page.carddata.addSuccess'));
|
||||||
|
showAddDialog.value = false;
|
||||||
|
fetchSiteList(); // 刷新列表
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Add site failed:', error);
|
||||||
|
message.error(t('page.carddata.addFailed'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开添加对话框
|
||||||
|
const openAddDialog = () => {
|
||||||
|
formData.value = {
|
||||||
|
name: '',
|
||||||
|
region: '',
|
||||||
|
timeZone: '',
|
||||||
|
scenario: '',
|
||||||
|
deviceAccountSetting: {
|
||||||
|
username: '',
|
||||||
|
password: ''
|
||||||
|
}
|
||||||
|
};
|
||||||
|
showAddDialog.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 搜索和分页状态
|
||||||
|
const searchValue = ref('');
|
||||||
|
const currentPage = ref(1);
|
||||||
|
const pageSize = ref(10);
|
||||||
|
const loading = ref(false);
|
||||||
|
const total = ref(0);
|
||||||
|
|
||||||
|
const siteData = ref<Api.DashboardSite[]>([]);
|
||||||
|
|
||||||
|
const fetchSiteList = async () => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const { data } = await getDashboardSiteList({
|
||||||
|
pageNum: currentPage.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
|
searchKey: searchValue.value
|
||||||
|
});
|
||||||
|
console.log('API Response:', data);
|
||||||
|
if (data) {
|
||||||
|
siteData.value = data.rows || [];
|
||||||
|
total.value = data.total || 0;
|
||||||
|
console.log('Processed Site Data:', siteData.value);
|
||||||
|
console.log('Total:', total.value);
|
||||||
|
} else {
|
||||||
|
siteData.value = [];
|
||||||
|
total.value = 0;
|
||||||
|
}
|
||||||
|
}catch (error){
|
||||||
|
console.error('Failed to fetch site list:', error);
|
||||||
|
siteData.value = [];
|
||||||
|
total.value = 0;
|
||||||
|
}finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 修改监听方式
|
||||||
|
|
||||||
|
watch([currentPage, pageSize, searchValue], () => {
|
||||||
|
fetchSiteList();
|
||||||
|
}, { immediate: true });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 表格列定义
|
||||||
|
const columns: TableColumnType<Api.DashboardSite>[] = [
|
||||||
|
{
|
||||||
|
title: t('page.carddata.sitename'),
|
||||||
|
key: 'name',
|
||||||
|
dataIndex: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.carddata.country'),
|
||||||
|
key: 'region',
|
||||||
|
dataIndex: 'region'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.carddata.alert'),
|
||||||
|
key: 'alerts',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// title: t('page.carddata.gateway'),
|
||||||
|
// key: 'gateway',
|
||||||
|
// width: 100
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: t('page.carddata.switches'),
|
||||||
|
// key: 'switches',
|
||||||
|
// width: 100
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// title: 'OLTS',
|
||||||
|
// key: 'olts',
|
||||||
|
// width: 100
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
title: 'EAPS',
|
||||||
|
key: 'eaps',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.carddata.clients'),
|
||||||
|
key: 'clients',
|
||||||
|
width: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'ACTION',
|
||||||
|
key: 'action',
|
||||||
|
width: 100,
|
||||||
|
fixed: 'right'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// 按钮操作处理函数
|
||||||
|
|
||||||
|
//
|
||||||
|
// const handleCopy = (record: Api.DashboardSite) => {
|
||||||
|
// console.log('Copy:', record);
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
const handleDelete = (record: Api.DashboardSite) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('page.carddata.deleteConfirmTitle'),
|
||||||
|
content: t('page.carddata.deleteConfirmContent', { name: record.name }),
|
||||||
|
okText: t('page.carddata.confirm'),
|
||||||
|
cancelText: t('page.carddata.cancel'),
|
||||||
|
okType: 'danger',
|
||||||
|
async onOk() {
|
||||||
|
try {
|
||||||
|
await deleteSite(record.siteId);
|
||||||
|
message.success(t('page.carddata.deleteSuccess'));
|
||||||
|
fetchSiteList(); // 刷新列表
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//
|
||||||
|
// const handleHome = (record: Api.DashboardSite) => {
|
||||||
|
// console.log('Home:', record);
|
||||||
|
// };
|
||||||
|
|
||||||
|
// 分页处理函数
|
||||||
|
const handlePageChange = (page: number, pageSize: number) => {
|
||||||
|
currentPage.value = page;
|
||||||
|
if (pageSize !== undefined) {
|
||||||
|
handlePageSizeChange(pageSize);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePageSizeChange = (size: number) => {
|
||||||
|
pageSize.value = size;
|
||||||
|
currentPage.value = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 编辑弹窗控制
|
||||||
|
const showEditDialog = ref(false);
|
||||||
|
|
||||||
|
// 编辑表单数据
|
||||||
|
const editFormData = ref({
|
||||||
|
name: '',
|
||||||
|
region: '',
|
||||||
|
timeZone: '',
|
||||||
|
scenario: '',
|
||||||
|
meshEnable: false,
|
||||||
|
autoFailoverEnable: false,
|
||||||
|
defGatewayEnable: true,
|
||||||
|
gateway: '',
|
||||||
|
fullSector: false,
|
||||||
|
fastRoamingEnable: false,
|
||||||
|
nonStickRoamingEnable: false,
|
||||||
|
aiRoamingEnable: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当前编辑的站点ID
|
||||||
|
const currentEditSiteId = ref('');
|
||||||
|
|
||||||
|
// 编辑表单验证规则
|
||||||
|
const { validate: validateEdit, validateInfos: validateEditInfos } = useForm(editFormData, {
|
||||||
|
name: [
|
||||||
|
{ required: true, message: t('page.carddata.nameRequired') },
|
||||||
|
{
|
||||||
|
pattern: /^[^ \+\-\@\=]$|^[^ \+\-\@\=].{0,62}[^ ]$/,
|
||||||
|
message: t('page.carddata.nameInvalid')
|
||||||
|
}
|
||||||
|
],
|
||||||
|
region: [{ required: true, message: t('page.carddata.regionRequired') }],
|
||||||
|
timeZone: [{ required: true, message: t('page.carddata.timeZoneRequired') }],
|
||||||
|
scenario: [{ required: true, message: t('page.carddata.scenarioRequired') }]
|
||||||
|
});
|
||||||
|
|
||||||
|
// IP分段输入
|
||||||
|
const gatewayIpParts = ref(['', '', '', '']);
|
||||||
|
|
||||||
|
// 拆分IP到4段
|
||||||
|
function splitGatewayIp(ip: string) {
|
||||||
|
if (!ip) return ['', '', '', ''];
|
||||||
|
const parts = ip.split('.');
|
||||||
|
return [parts[0] || '', parts[1] || '', parts[2] || '', parts[3] || ''];
|
||||||
|
}
|
||||||
|
// 拼接4段为IP
|
||||||
|
function joinGatewayIp(parts: string[]) {
|
||||||
|
return parts.map(p => p.trim()).join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹窗打开时同步分段
|
||||||
|
watch(() => editFormData.value.gateway, (val: any) => {
|
||||||
|
gatewayIpParts.value = splitGatewayIp(val);
|
||||||
|
}, { immediate: true });
|
||||||
|
// 分段输入时同步到gateway
|
||||||
|
watch(gatewayIpParts, (val: any) => {
|
||||||
|
editFormData.value.gateway = joinGatewayIp(val);
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
|
// 处理编辑按钮点击
|
||||||
|
const handleEdit = async (record: Api.DashboardSite) => {
|
||||||
|
try {
|
||||||
|
currentEditSiteId.value = record.siteId;
|
||||||
|
const [siteRes, meshRes, roamingRes] = await Promise.all([
|
||||||
|
getSiteConfig(record.siteId),
|
||||||
|
getMeshConfig(record.siteId),
|
||||||
|
getRoamingConfig(record.siteId)
|
||||||
|
]);
|
||||||
|
if (siteRes.data) {
|
||||||
|
editFormData.value = {
|
||||||
|
name: siteRes.data.name,
|
||||||
|
region: siteRes.data.region,
|
||||||
|
timeZone: siteRes.data.timeZone,
|
||||||
|
scenario: siteRes.data.scenario,
|
||||||
|
meshEnable: meshRes.data?.mesh?.meshEnable ?? false,
|
||||||
|
autoFailoverEnable: meshRes.data?.mesh?.autoFailoverEnable ?? false,
|
||||||
|
defGatewayEnable: meshRes.data?.mesh?.defGatewayEnable ?? true,
|
||||||
|
gateway: meshRes.data?.mesh?.gateway ?? '',
|
||||||
|
fullSector: meshRes.data?.mesh?.fullSector ?? false,
|
||||||
|
fastRoamingEnable: roamingRes.data?.roaming?.fastRoamingEnable ?? false,
|
||||||
|
nonStickRoamingEnable: roamingRes.data?.roaming?.nonStickRoamingEnable ?? false,
|
||||||
|
aiRoamingEnable: roamingRes.data?.roaming?.aiRoamingEnable ?? false
|
||||||
|
};
|
||||||
|
gatewayIpParts.value = splitGatewayIp(editFormData.value.gateway);
|
||||||
|
showEditDialog.value = true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Get site config failed:', error);
|
||||||
|
message.error(t('page.carddata.getConfigFailed'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理更新站点
|
||||||
|
const handleUpdateSite = async () => {
|
||||||
|
try {
|
||||||
|
await validateEdit();
|
||||||
|
// 先保存基础配置
|
||||||
|
await updateSite(currentEditSiteId.value, {
|
||||||
|
name: editFormData.value.name,
|
||||||
|
region: editFormData.value.region,
|
||||||
|
timeZone: editFormData.value.timeZone,
|
||||||
|
scenario: editFormData.value.scenario
|
||||||
|
});
|
||||||
|
// mesh 配置为嵌套结构,meshEnable为true时才携带defGatewayEnable、gateway、fullSector
|
||||||
|
const meshData: any = { mesh: { meshEnable: editFormData.value.meshEnable } };
|
||||||
|
if (editFormData.value.meshEnable) {
|
||||||
|
meshData.mesh.autoFailoverEnable = editFormData.value.autoFailoverEnable;
|
||||||
|
meshData.mesh.defGatewayEnable = editFormData.value.defGatewayEnable;
|
||||||
|
meshData.mesh.fullSector = editFormData.value.fullSector;
|
||||||
|
if (editFormData.value.defGatewayEnable === false) {
|
||||||
|
meshData.mesh.gateway = editFormData.value.gateway;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// roaming 配置为嵌套结构
|
||||||
|
const roamingData: any = { roaming: { fastRoamingEnable: editFormData.value.fastRoamingEnable } };
|
||||||
|
if (editFormData.value.fastRoamingEnable) {
|
||||||
|
roamingData.roaming.nonStickRoamingEnable = editFormData.value.nonStickRoamingEnable;
|
||||||
|
roamingData.roaming.aiRoamingEnable = editFormData.value.aiRoamingEnable;
|
||||||
|
}else {
|
||||||
|
roamingData.roaming.nonStickRoamingEnable=false;
|
||||||
|
roamingData.roaming.aiRoamingEnable = false;
|
||||||
|
}
|
||||||
|
await Promise.all([
|
||||||
|
updateMeshConfig(currentEditSiteId.value, meshData),
|
||||||
|
updateRoamingConfig(currentEditSiteId.value, roamingData)
|
||||||
|
]);
|
||||||
|
message.success(t('page.carddata.updateSuccess'));
|
||||||
|
showEditDialog.value = false;
|
||||||
|
fetchSiteList(); // 刷新列表
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Update site failed:', error);
|
||||||
|
message.error(t('page.carddata.updateFailed'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ACard :bordered="false" size="small" class="card-wrapper">
|
||||||
|
<div class="flex justify-between items-center mb-16px">
|
||||||
|
<div class="flex items-center gap-8px">
|
||||||
|
<span class="text-16px font-medium">{{ t('page.carddata.sitelist') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-16px">
|
||||||
|
<AInput
|
||||||
|
v-model:value="searchValue"
|
||||||
|
:placeholder="t('page.carddata.search')"
|
||||||
|
class="w-240px"
|
||||||
|
allow-clear
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<search-outlined />
|
||||||
|
</template>
|
||||||
|
</AInput>
|
||||||
|
<AButton type="primary" @click="openAddDialog">
|
||||||
|
<template #icon>
|
||||||
|
<plus-outlined />
|
||||||
|
</template>
|
||||||
|
{{ t('page.carddata.addsite') }}
|
||||||
|
</AButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ATable
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="siteData"
|
||||||
|
:pagination="{
|
||||||
|
current: currentPage,
|
||||||
|
pageSize: pageSize,
|
||||||
|
total: total,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showQuickJumper: true,
|
||||||
|
showTotal: (total: number) => `${t('page.carddata.total')} ${total} `,
|
||||||
|
onChange: handlePageChange,
|
||||||
|
onShowSizeChange: handlePageSizeChange
|
||||||
|
}"
|
||||||
|
row-key="siteId"
|
||||||
|
:scroll="{ x: 1200 }"
|
||||||
|
:loading="loading"
|
||||||
|
>
|
||||||
|
<!-- 添加一个调试信息 -->
|
||||||
|
<template #headerCell="{ column }">
|
||||||
|
<span>{{ column.title }}</span>
|
||||||
|
</template>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<!-- 添加调试信息 -->
|
||||||
|
{{ console.log('Rendering cell:', column.key, record) }}
|
||||||
|
<template v-if="column.key === 'name'">
|
||||||
|
<div class="flex items-center gap-8px">
|
||||||
|
<environment-outlined class="text-16px" />
|
||||||
|
<span>{{ record.name }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'region'">
|
||||||
|
<span>{{ record.region }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'alerts'">
|
||||||
|
<span>0</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'gateway'">
|
||||||
|
<span>{{ record.connectedGatewayNum }}/{{ record.disconnectedGatewayNum }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'switches'">
|
||||||
|
<span>{{ record.connectedSwitchNum }}/{{ record.disconnectedSwitchNum }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'olts'">
|
||||||
|
<span>0/0</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'eaps'">
|
||||||
|
<span>{{ record.connectedApNum }}/{{ record.disconnectedApNum }}/{{ record.isolatedApNum }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'clients'">
|
||||||
|
<span>{{ record.wiredClientNum }}/{{ record.wirelessClientNum }}/{{ record.guestNum }}</span>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="column.key === 'action'">
|
||||||
|
<div class="flex items-center gap-8px">
|
||||||
|
<edit-outlined class="cursor-pointer text-primary" @click="handleEdit(record)" />
|
||||||
|
<!-- <copy-outlined class="cursor-pointer text-primary" @click="handleCopy(record)" />-->
|
||||||
|
<delete-outlined class="cursor-pointer text-red-500" @click="handleDelete(record)" />
|
||||||
|
<!-- <home-outlined class="cursor-pointer text-primary" @click="handleHome(record)" />-->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</ATable>
|
||||||
|
|
||||||
|
<!-- 添加站点对话框 -->
|
||||||
|
<AModal
|
||||||
|
v-model:visible="showAddDialog"
|
||||||
|
:title="t('page.carddata.addsite')"
|
||||||
|
@ok="handleAddSite"
|
||||||
|
@cancel="showAddDialog = false"
|
||||||
|
:maskClosable="false"
|
||||||
|
>
|
||||||
|
<AForm
|
||||||
|
ref="formRef"
|
||||||
|
:model="formData"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:wrapper-col="{ span: 18 }"
|
||||||
|
>
|
||||||
|
<AFormItem
|
||||||
|
name="name"
|
||||||
|
:label="t('page.carddata.sitename')"
|
||||||
|
v-bind="validateInfos.name"
|
||||||
|
>
|
||||||
|
<AInput v-model:value="formData.name" />
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="region"
|
||||||
|
:label="t('page.carddata.region')"
|
||||||
|
v-bind="validateInfos.region"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formData.region"
|
||||||
|
:options="regionOptions"
|
||||||
|
show-search
|
||||||
|
:filter-option="(input, option) =>
|
||||||
|
option?.label?.toLowerCase().includes(input.toLowerCase())"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="timeZone"
|
||||||
|
:label="t('page.carddata.timezone')"
|
||||||
|
v-bind="validateInfos.timeZone"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formData.timeZone"
|
||||||
|
:options="timeZoneOptions"
|
||||||
|
show-search
|
||||||
|
:filter-option="(input, option) =>
|
||||||
|
option?.label?.toLowerCase().includes(input.toLowerCase())"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="scenario"
|
||||||
|
:label="t('page.carddata.scenario')"
|
||||||
|
v-bind="validateInfos.scenario"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="formData.scenario"
|
||||||
|
:options="scenarioOptions"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="deviceAccountSetting.username"
|
||||||
|
:label="t('page.carddata.username')"
|
||||||
|
v-bind="validateInfos['deviceAccountSetting.username']"
|
||||||
|
>
|
||||||
|
<AInput v-model:value="formData.deviceAccountSetting.username" />
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="deviceAccountSetting.password"
|
||||||
|
:label="t('page.carddata.password')"
|
||||||
|
v-bind="validateInfos['deviceAccountSetting.password']"
|
||||||
|
>
|
||||||
|
<AInputPassword v-model:value="formData.deviceAccountSetting.password" />
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
</AModal>
|
||||||
|
|
||||||
|
<!-- 编辑站点对话框 -->
|
||||||
|
<AModal
|
||||||
|
v-model:visible="showEditDialog"
|
||||||
|
:title="t('page.carddata.editsite')"
|
||||||
|
@ok="handleUpdateSite"
|
||||||
|
@cancel="showEditDialog = false"
|
||||||
|
:maskClosable="false"
|
||||||
|
:width="700"
|
||||||
|
>
|
||||||
|
<AForm
|
||||||
|
:model="editFormData"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:wrapper-col="{ span: 24 }"
|
||||||
|
>
|
||||||
|
<AFormItem
|
||||||
|
name="name"
|
||||||
|
:label="t('page.carddata.sitename')"
|
||||||
|
v-bind="validateEditInfos.name"
|
||||||
|
>
|
||||||
|
<AInput v-model:value="editFormData.name" />
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="region"
|
||||||
|
:label="t('page.carddata.region')"
|
||||||
|
v-bind="validateEditInfos.region"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="editFormData.region"
|
||||||
|
:options="regionOptions"
|
||||||
|
show-search
|
||||||
|
:filter-option="(input, option) =>
|
||||||
|
option?.label?.toLowerCase().includes(input.toLowerCase())"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="timeZone"
|
||||||
|
:label="t('page.carddata.timezone')"
|
||||||
|
v-bind="validateEditInfos.timeZone"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="editFormData.timeZone"
|
||||||
|
:options="timeZoneOptions"
|
||||||
|
show-search
|
||||||
|
:filter-option="(input, option) =>
|
||||||
|
option?.label?.toLowerCase().includes(input.toLowerCase())"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<AFormItem
|
||||||
|
name="scenario"
|
||||||
|
:label="t('page.carddata.scenario')"
|
||||||
|
v-bind="validateEditInfos.scenario"
|
||||||
|
>
|
||||||
|
<ASelect
|
||||||
|
v-model:value="editFormData.scenario"
|
||||||
|
:options="scenarioOptions"
|
||||||
|
/>
|
||||||
|
</AFormItem>
|
||||||
|
|
||||||
|
<a-divider />
|
||||||
|
<div style="margin-bottom: 8px; font-weight: bold;">{{ t('page.carddata.wireless') }}</div>
|
||||||
|
<AFormItem>
|
||||||
|
<a-checkbox v-model:checked="editFormData.meshEnable">Mesh</a-checkbox>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem v-if="editFormData.meshEnable" style="margin-left: 24px;">
|
||||||
|
{{t('page.carddata.conDetection')}}
|
||||||
|
<ASelect v-model:value="editFormData.defGatewayEnable" style="width: 200px;">
|
||||||
|
<ASelectOption :value="true">{{ t('page.carddata.autoRec') }}</ASelectOption>
|
||||||
|
<ASelectOption :value="false">{{ t('page.carddata.custom') }}</ASelectOption>
|
||||||
|
</ASelect>
|
||||||
|
<template v-if="editFormData.defGatewayEnable === false">
|
||||||
|
<div style="display: inline-flex; align-items: center; margin-left: 12px;">
|
||||||
|
<AInput v-for="(part, idx) in gatewayIpParts" :key="idx" v-model:value="gatewayIpParts[idx]" maxlength="3" style="width: 48px; text-align: center; margin-right: 4px;" />
|
||||||
|
<span v-if="idx < 3" v-for="idx in 3" :key="'dot'+idx">.</span>
|
||||||
|
</div>
|
||||||
|
<a-tooltip placement="topLeft" :title="t('page.carddata.meshtext')">
|
||||||
|
<a-button type="ghost" color="blue"><InfoCircleOutlined /></a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem v-if="editFormData.meshEnable" style="margin-left: 24px;">
|
||||||
|
<a-checkbox v-model:checked="editFormData.autoFailoverEnable">{{ t('page.carddata.autoFailover') }}</a-checkbox>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem v-if="editFormData.meshEnable" style="margin-left: 24px;">
|
||||||
|
<a-checkbox v-model:checked="editFormData.fullSector">Full-Sector DFS</a-checkbox>
|
||||||
|
</AFormItem>
|
||||||
|
<AFormItem>
|
||||||
|
<a-checkbox v-model:checked="editFormData.fastRoamingEnable">{{ t('page.carddata.fastRoaming') }}</a-checkbox>
|
||||||
|
</AFormItem>
|
||||||
|
<!-- <AFormItem v-if="editFormData.fastRoamingEnable" style="margin-left: 24px;">-->
|
||||||
|
<!-- <a-checkbox v-model:checked="editFormData.nonStickRoamingEnable">Non-Stick Roaming</a-checkbox>-->
|
||||||
|
<!-- </AFormItem>-->
|
||||||
|
<AFormItem v-if="editFormData.fastRoamingEnable" style="margin-left: 24px;">
|
||||||
|
<a-checkbox v-model:checked="editFormData.aiRoamingEnable">{{ t('page.carddata.aiRoaming') }}</a-checkbox>
|
||||||
|
</AFormItem>
|
||||||
|
</AForm>
|
||||||
|
</AModal>
|
||||||
|
</ACard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.card-wrapper {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cursor-pointer {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-240px {
|
||||||
|
width: 240px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File renamed without changes.
@@ -0,0 +1,341 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {
|
||||||
|
EnvironmentOutlined,
|
||||||
|
SafetyOutlined,
|
||||||
|
HddOutlined,
|
||||||
|
GroupOutlined,
|
||||||
|
UserAddOutlined,
|
||||||
|
UserSwitchOutlined
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
|
import { computed, ref, onMounted } from 'vue';
|
||||||
|
import { getDashboardOverview } from '@/service/api/auth';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const router = useRouter();
|
||||||
|
//AP跳转
|
||||||
|
const handleApClick = () => {
|
||||||
|
router.push('/device/apdevice');
|
||||||
|
};
|
||||||
|
//用户跳转
|
||||||
|
const handleUserClick = () =>{
|
||||||
|
router.push('/user-center/user')
|
||||||
|
};
|
||||||
|
//终端跳转
|
||||||
|
const handleterminalClick = () => {
|
||||||
|
router.push('/device/terminal');
|
||||||
|
};
|
||||||
|
//告警跳转
|
||||||
|
const handAlertsClick = () => {
|
||||||
|
router.push('/device/alerts');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'HeaderBanner'
|
||||||
|
});
|
||||||
|
|
||||||
|
const overviewData = ref<Api.DashboardOverview>({
|
||||||
|
cloud: { connected: false },
|
||||||
|
siteNum: 0,
|
||||||
|
totalGatewayNum: 0,
|
||||||
|
connectedGatewayNum: 0,
|
||||||
|
disconnectedGatewayNum: 0,
|
||||||
|
totalSwitchNum: 0,
|
||||||
|
connectedSwitchNum: 0,
|
||||||
|
disconnectedSwitchNum: 0,
|
||||||
|
totalApNum: 0,
|
||||||
|
connectedApNum: 0,
|
||||||
|
disconnectedApNum: 0,
|
||||||
|
isolatedApNum: 0,
|
||||||
|
totalClientNum: 0,
|
||||||
|
wiredClientNum: 0,
|
||||||
|
wirelessClientNum: 0,
|
||||||
|
guestNum: 0,
|
||||||
|
registerUserNum: 0,
|
||||||
|
onlineUserNum: 0
|
||||||
|
});
|
||||||
|
|
||||||
|
const fetchOverviewData = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await getDashboardOverview();
|
||||||
|
if (data) {
|
||||||
|
overviewData.value = {
|
||||||
|
cloud: { connected: data.cloud?.connected ?? false },
|
||||||
|
siteNum: data.siteNum ?? 0,
|
||||||
|
totalGatewayNum: data.totalGatewayNum ?? 0,
|
||||||
|
connectedGatewayNum: data.connectedGatewayNum ?? 0,
|
||||||
|
disconnectedGatewayNum: data.disconnectedGatewayNum ?? 0,
|
||||||
|
totalSwitchNum: data.totalSwitchNum ?? 0,
|
||||||
|
connectedSwitchNum: data.connectedSwitchNum ?? 0,
|
||||||
|
disconnectedSwitchNum: data.disconnectedSwitchNum ?? 0,
|
||||||
|
totalApNum: data.totalApNum ?? 0,
|
||||||
|
connectedApNum: data.connectedApNum ?? 0,
|
||||||
|
disconnectedApNum: data.disconnectedApNum ?? 0,
|
||||||
|
isolatedApNum: data.isolatedApNum ?? 0,
|
||||||
|
totalClientNum: data.totalClientNum ?? 0,
|
||||||
|
wiredClientNum: data.wiredClientNum ?? 0,
|
||||||
|
wirelessClientNum: data.wirelessClientNum ?? 0,
|
||||||
|
guestNum: data.guestNum ?? 0,
|
||||||
|
registerUserNum: data.registerUserNum ?? 0,
|
||||||
|
onlineUserNum: data.onlineUserNum ?? 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchOverviewData();
|
||||||
|
});
|
||||||
|
|
||||||
|
const deviceStatus = computed(() => {
|
||||||
|
const status = {
|
||||||
|
ap: {
|
||||||
|
connected: Number(overviewData.value.connectedApNum) || 0,
|
||||||
|
disconnected: Number(overviewData.value.disconnectedApNum) || 0,
|
||||||
|
isolated: Number(overviewData.value.isolatedApNum) || 0
|
||||||
|
},
|
||||||
|
client: {
|
||||||
|
wiredUsers: Number(overviewData.value.wiredClientNum) || 0,
|
||||||
|
wirelessUsers: Number(overviewData.value.wirelessClientNum) || 0,
|
||||||
|
wirelessGuests: Number(overviewData.value.guestNum) || 0
|
||||||
|
},
|
||||||
|
users: {
|
||||||
|
registered: Number(overviewData.value.registerUserNum) || 0,
|
||||||
|
online: Number(overviewData.value.onlineUserNum) || 0
|
||||||
|
},
|
||||||
|
alerts: 0
|
||||||
|
};
|
||||||
|
return status;
|
||||||
|
});
|
||||||
|
|
||||||
|
const siteInfo = computed(() => ({
|
||||||
|
total: Number(overviewData.value.siteNum) || 0
|
||||||
|
}));
|
||||||
|
|
||||||
|
const otherDevices = computed(() => ({
|
||||||
|
gateways: {
|
||||||
|
total: Number(overviewData.value.totalGatewayNum) || 0,
|
||||||
|
connected: Number(overviewData.value.connectedGatewayNum) || 0,
|
||||||
|
disconnected: Number(overviewData.value.disconnectedGatewayNum) || 0
|
||||||
|
},
|
||||||
|
switches: {
|
||||||
|
total: Number(overviewData.value.totalSwitchNum) || 0,
|
||||||
|
connected: Number(overviewData.value.connectedSwitchNum) || 0,
|
||||||
|
disconnected: Number(overviewData.value.disconnectedSwitchNum) || 0
|
||||||
|
},
|
||||||
|
olts: {
|
||||||
|
total: 0,
|
||||||
|
connected: 0,
|
||||||
|
disconnected: 0
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ACard :bordered="false" class="card-wrapper">
|
||||||
|
<div class="text-16px font-bold mb-4px">{{ t('page.headerbanner.controller') }}</div>
|
||||||
|
<ARow :gutter="[16, 16]">
|
||||||
|
<ACol :span="24">
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-8px">
|
||||||
|
<!-- Connected Status -->
|
||||||
|
<div class="flex flex-col p-6px">
|
||||||
|
<div class="flex items-center gap-6px mb-6px">
|
||||||
|
<div class="size-48px flex-center bg-blue-50 rounded-lg">
|
||||||
|
<icon-mdi-cloud class="text-primary text-24px" />
|
||||||
|
</div>
|
||||||
|
<div class="text-16px font-medium">{{ t('page.headerbanner.connected') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-100 my-4px"></div>
|
||||||
|
<div class="text-12px text-gray-500">
|
||||||
|
{{ t('page.headerbanner.cloud') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Sites -->
|
||||||
|
<div class="flex flex-col p-6px">
|
||||||
|
<div class="flex items-center gap-6px mb-6px">
|
||||||
|
<div class="size-48px flex-center bg-gray-100 rounded-lg relative">
|
||||||
|
<environment-outlined class="text-24px text-primary" />
|
||||||
|
<span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">{{ siteInfo.total }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-16px font-medium">{{ t('page.headerbanner.sites') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-100 my-4px"></div>
|
||||||
|
<div class="flex flex-col text-12px text-gray-500">
|
||||||
|
<span>{{ t('page.headerbanner.totalsite') }}: {{ siteInfo.total }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <!– Gateways –>-->
|
||||||
|
<!-- <div class="flex flex-col p-6px">-->
|
||||||
|
<!-- <div class="flex items-center gap-6px mb-6px">-->
|
||||||
|
<!-- <div class="size-48px flex-center bg-gray-100 rounded-lg relative">-->
|
||||||
|
<!-- <safety-outlined class="text-24px text-primary" />-->
|
||||||
|
<!-- <span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">{{ otherDevices.gateways.connected + otherDevices.gateways.disconnected }}</span>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="text-16px font-medium">{{ t('page.headerbanner.gateway') }}</div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="border-t border-gray-100 my-4px"></div>-->
|
||||||
|
<!-- <div class="flex flex-col text-12px text-gray-500">-->
|
||||||
|
<!-- <span>{{ t('page.headerbanner.connect') }}: {{ otherDevices.gateways.connected }}</span>-->
|
||||||
|
<!-- <span>{{ t('page.headerbanner.disconnect') }}: {{ otherDevices.gateways.disconnected }}</span>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
|
<!-- <!– Switches –>-->
|
||||||
|
<!-- <div class="flex flex-col p-6px">-->
|
||||||
|
<!-- <div class="flex items-center gap-6px mb-6px">-->
|
||||||
|
<!-- <div class="size-48px flex-center bg-gray-100 rounded-lg relative">-->
|
||||||
|
<!-- <hdd-outlined class="text-24px text-primary" />-->
|
||||||
|
<!-- <span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">{{ otherDevices.switches.connected + otherDevices.switches.disconnected }}</span>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="text-16px font-medium">{{ t('page.headerbanner.switches') }}</div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="border-t border-gray-100 my-4px"></div>-->
|
||||||
|
<!-- <div class="flex flex-col text-12px text-gray-500">-->
|
||||||
|
<!-- <span>{{ t('page.headerbanner.connect') }}: {{ otherDevices.switches.connected }}</span>-->
|
||||||
|
<!-- <span>{{ t('page.headerbanner.disconnect') }}: {{ otherDevices.switches.disconnected }}</span>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
|
<!-- <!– OLTs –>-->
|
||||||
|
<!-- <div class="flex flex-col p-6px">-->
|
||||||
|
<!-- <div class="flex items-center gap-6px mb-6px">-->
|
||||||
|
<!-- <div class="size-48px flex-center bg-gray-100 rounded-lg relative">-->
|
||||||
|
<!-- <group-outlined class="text-24px text-primary" />-->
|
||||||
|
<!-- <span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">{{ otherDevices.olts.total }}</span>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="text-16px font-medium">OLTs</div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="border-t border-gray-100 my-4px"></div>-->
|
||||||
|
<!-- <div class="flex flex-col text-12px text-gray-500">-->
|
||||||
|
<!-- <span>{{ t('page.headerbanner.connect') }}: {{ otherDevices.olts.connected }}</span>-->
|
||||||
|
<!-- <span>{{ t('page.headerbanner.disconnect') }}: {{ otherDevices.olts.disconnected }}</span>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
|
||||||
|
<!-- Register Users -->
|
||||||
|
<div class="flex flex-col p-6px">
|
||||||
|
<div class="flex items-center gap-6px mb-6px">
|
||||||
|
<div class="size-48px flex-center bg-blue-50 rounded-lg relative hover:bg-green-100">
|
||||||
|
<user-add-outlined class="text-primary text-24px cursor-pointer" @click="handleUserClick"/>
|
||||||
|
</div>
|
||||||
|
<div class="text-16px font-medium">{{ t('page.headerbanner.register') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-100 my-4px"></div>
|
||||||
|
<div class="flex flex-col text-12px text-gray-500">
|
||||||
|
<span>{{ t('page.headerbanner.registuser') }}: {{ deviceStatus.users.registered }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Online Users -->
|
||||||
|
<div class="flex flex-col p-6px">
|
||||||
|
<div class="flex items-center gap-6px mb-6px">
|
||||||
|
<div class="size-48px flex-center bg-green-50 rounded-lg">
|
||||||
|
<user-switch-outlined class="text-primary text-24px" />
|
||||||
|
</div>
|
||||||
|
<div class="text-16px font-medium">{{ t('page.headerbanner.online') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-100 my-4px"></div>
|
||||||
|
<div class="flex flex-col text-12px text-gray-500">
|
||||||
|
<span>{{ t('page.headerbanner.onlineuser') }}: {{ deviceStatus.users.online }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- AP Status -->
|
||||||
|
<div class="flex flex-col p-6px" >
|
||||||
|
<div class="flex items-center gap-6px mb-6px">
|
||||||
|
<div class="size-48px flex-center bg-green-50 rounded-lg relative hover:bg-green-100">
|
||||||
|
<icon-mdi-access-point class="text-primary text-24px cursor-pointer" @click="handleApClick" />
|
||||||
|
<span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">
|
||||||
|
{{ overviewData.totalApNum }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-16px font-medium">AP</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-100 my-4px"></div>
|
||||||
|
<div class="flex flex-col text-12px text-gray-500">
|
||||||
|
<span>{{ t('page.headerbanner.connect') }}: {{ deviceStatus.ap.connected }}</span>
|
||||||
|
<span>{{ t('page.headerbanner.disconnect') }}: {{ deviceStatus.ap.disconnected }}</span>
|
||||||
|
<span>{{ t('page.headerbanner.isolated') }}: {{ deviceStatus.ap.isolated }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Client Status -->
|
||||||
|
<div class="flex flex-col p-6px">
|
||||||
|
<div class="flex items-center gap-6px mb-6px">
|
||||||
|
<div class="size-48px flex-center bg-purple-50 rounded-lg relative hover:bg-green-100">
|
||||||
|
<icon-mdi-laptop class="text-primary text-24px cursor-pointer" @click="handleterminalClick"/>
|
||||||
|
<span class="text-20px font-semibold absolute -right-2 -top-2 bg-primary text-white rounded-full w-6 h-6 flex-center">
|
||||||
|
{{ overviewData.totalClientNum }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="text-16px font-medium">{{ t('page.headerbanner.client') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-100 my-4px"></div>
|
||||||
|
<div class="flex flex-col text-12px text-gray-500">
|
||||||
|
<span>{{ t('page.headerbanner.wired') }}: {{ deviceStatus.client.wiredUsers }}</span>
|
||||||
|
<span>{{ t('page.headerbanner.wireless') }}: {{ deviceStatus.client.wirelessUsers }}</span>
|
||||||
|
<span>{{ t('page.headerbanner.guest') }}: {{ deviceStatus.client.wirelessGuests }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Alerts -->
|
||||||
|
<div class="flex flex-col p-6px">
|
||||||
|
<div class="flex items-center gap-6px mb-6px">
|
||||||
|
<div class="size-48px flex-center bg-yellow-50 rounded-lg relative hover:bg-green-100">
|
||||||
|
<icon-mdi-alert class="text-warning text-24px cursor-pointer" @click="handAlertsClick"/>
|
||||||
|
</div>
|
||||||
|
<div class="text-16px font-medium">{{ t('page.headerbanner.alerts') }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-100 my-4px"></div>
|
||||||
|
<div class="flex flex-col text-12px text-gray-500">
|
||||||
|
<span>{{ t('page.headerbanner.alert') }}: {{ deviceStatus.alerts || 0 }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ACol>
|
||||||
|
</ARow>
|
||||||
|
</ACard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.card-wrapper {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-center {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.size-48px {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-col > span {
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-gray-50 {
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.p-6px {
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt-8px {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-6px {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,682 @@
|
|||||||
|
<template>
|
||||||
|
<SimpleScrollbar>
|
||||||
|
<a-card
|
||||||
|
:bordered="false"
|
||||||
|
style="box-shadow: 0 2px 8px #f0f1f2; border-radius: 8px; padding: 0 24px; margin: 24px;"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<h2 style="font-weight: bold; font-size: 22px; margin-bottom: 8px;">{{ t('page.access.title') }}</h2>
|
||||||
|
<!-- 站点选择框 -->
|
||||||
|
<div style="display: flex; align-items: center; margin-bottom: 24px;">
|
||||||
|
<a-select
|
||||||
|
v-model:value="selectedSiteId"
|
||||||
|
:loading="siteLoading"
|
||||||
|
:placeholder="t('page.access.plesite')"
|
||||||
|
style="width: 200px; margin-right: 16px;"
|
||||||
|
@change="handleSiteChange"
|
||||||
|
>
|
||||||
|
<a-select-option v-for="site in siteList" :key="site.siteId" :value="site.siteId">
|
||||||
|
{{ site.name }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pre-Authentication Access -->
|
||||||
|
<div style="margin-bottom: 16px; display: flex; align-items: center; gap: 12px;">
|
||||||
|
<span>{{ t('page.access.authaccess') }}</span>
|
||||||
|
<a-switch v-model:checked="preAuthEnabled" />
|
||||||
|
<span>{{ t('page.access.enable') }}</span>
|
||||||
|
<a-tooltip title="Pre-Authentication Access 说明">
|
||||||
|
<i class="anticon anticon-info-circle" style="color: #13c2c2; margin-left: 4px;"></i>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<div v-if="preAuthEnabled">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;">
|
||||||
|
<span>{{ t('page.access.authaccesslist') }}</span>
|
||||||
|
<a-button type="link" style="color: #13c2c2; font-weight: bold;" @click="onAddPreAuth"><i class="anticon anticon-plus-circle" />
|
||||||
|
{{ t('page.access.add') }}</a-button>
|
||||||
|
</div>
|
||||||
|
<a-table
|
||||||
|
:columns="preAuthColumns"
|
||||||
|
:dataSource="preAuthList"
|
||||||
|
:pagination="false"
|
||||||
|
bordered
|
||||||
|
size="middle"
|
||||||
|
rowKey="key"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<a-tooltip :title="t('page.access.delete')">
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
style="color: #ff4d4f"
|
||||||
|
@click="() => handleDeletePreAuth(record)"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<DeleteOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Authentication-Free Client -->
|
||||||
|
<div style="margin: 32px 0 16px 0; display: flex; align-items: center; gap: 12px;">
|
||||||
|
<span>{{ t('page.access.authclient') }}</span>
|
||||||
|
<a-switch v-model:checked="freeClientEnabled" />
|
||||||
|
<span>{{ t('page.access.enable') }}</span>
|
||||||
|
<a-tooltip title="Authentication-Free Client 说明">
|
||||||
|
<i class="anticon anticon-info-circle" style="color: #13c2c2; margin-left: 4px;"></i>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
<div v-if="freeClientEnabled">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;">
|
||||||
|
<span>{{ t('page.access.authclientlist') }}</span>
|
||||||
|
<a-button type="link" style="color: #13c2c2; font-weight: bold;" @click="onAddFreeClient"><i class="anticon anticon-plus-circle" />
|
||||||
|
{{ t('page.access.add') }}</a-button>
|
||||||
|
</div>
|
||||||
|
<a-table
|
||||||
|
:columns="freeClientColumns"
|
||||||
|
:dataSource="freeClientList"
|
||||||
|
:pagination="false"
|
||||||
|
bordered
|
||||||
|
size="middle"
|
||||||
|
rowKey="key"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'action'">
|
||||||
|
<a-tooltip :title="t('page.access.delete')">
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
style="color: #ff4d4f"
|
||||||
|
@click="() => handleDeleteFreeClient(record)"
|
||||||
|
>
|
||||||
|
<template #icon>
|
||||||
|
<DeleteOutlined />
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<div style="margin-top: 32px; display: flex; gap: 16px;">
|
||||||
|
<a-button type="primary" @click="handleApply">{{ t('page.access.apply') }}</a-button>
|
||||||
|
<a-button @click="handleCancel">{{ t('page.access.cancel') }}</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
<!-- 新增:添加预认证白名单弹窗 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="addPreAuthVisible"
|
||||||
|
:title="t('page.access.addauth')"
|
||||||
|
@ok="handleAddPreAuthOk"
|
||||||
|
@cancel="() => addPreAuthVisible = false"
|
||||||
|
destroyOnClose
|
||||||
|
>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-form-item label="TYPE">
|
||||||
|
<a-select v-model:value="addPreAuthType" style="width: 100%;">
|
||||||
|
<a-select-option :value="1">IP</a-select-option>
|
||||||
|
<a-select-option :value="2">URL</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="addPreAuthType === 1" label="IP">
|
||||||
|
<div style="display: flex; align-items: center; gap: 4px;">
|
||||||
|
<a-input
|
||||||
|
v-model:value="addPreAuthIpParts[0]"
|
||||||
|
style="width: 56px;"
|
||||||
|
:maxlength="3"
|
||||||
|
@input="validateIpPart(0)"
|
||||||
|
placeholder="0-255"
|
||||||
|
/>
|
||||||
|
<span>.</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="addPreAuthIpParts[1]"
|
||||||
|
style="width: 56px;"
|
||||||
|
:maxlength="3"
|
||||||
|
@input="validateIpPart(1)"
|
||||||
|
placeholder="0-255"
|
||||||
|
/>
|
||||||
|
<span>.</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="addPreAuthIpParts[2]"
|
||||||
|
style="width: 56px;"
|
||||||
|
:maxlength="3"
|
||||||
|
@input="validateIpPart(2)"
|
||||||
|
placeholder="0-255"
|
||||||
|
/>
|
||||||
|
<span>.</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="addPreAuthIpParts[3]"
|
||||||
|
style="width: 56px;"
|
||||||
|
:maxlength="3"
|
||||||
|
@input="validateIpPart(3)"
|
||||||
|
placeholder="0-255"
|
||||||
|
/>
|
||||||
|
<span>/</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="addPreAuthIpParts[4]"
|
||||||
|
style="width: 56px;"
|
||||||
|
:maxlength="2"
|
||||||
|
@input="validateMaskPart"
|
||||||
|
placeholder="0-32"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="ipValidationError" style="color: #ff4d4f; font-size: 12px; margin-top: 4px;">
|
||||||
|
{{ ipValidationError }}
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="addPreAuthType === 2" label="URL">
|
||||||
|
<a-input-group compact>
|
||||||
|
<span style="display: inline-block; width: 90px; text-align: center; background: #f5f5f5; border: 1px solid #d9d9d9; border-right: none; border-radius: 6px 0 0 6px; line-height: 32px;">http(s)://</span>
|
||||||
|
<a-input v-model:value="addPreAuthValue" style="width: calc(100% - 90px); border-radius: 0 6px 6px 0;" placeholder="请输入URL" />
|
||||||
|
</a-input-group>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
<!-- 新增:添加免认证白名单弹窗 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="addFreeClientVisible"
|
||||||
|
:title="t('page.access.addclient')"
|
||||||
|
@ok="handleAddFreeClientOk"
|
||||||
|
@cancel="() => addFreeClientVisible = false"
|
||||||
|
destroyOnClose
|
||||||
|
>
|
||||||
|
<a-form layout="vertical">
|
||||||
|
<a-form-item label="TYPE">
|
||||||
|
<a-select v-model:value="addFreeClientType" style="width: 100%;">
|
||||||
|
<a-select-option :value="3">IP</a-select-option>
|
||||||
|
<a-select-option :value="4">MAC</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="addFreeClientType === 3" label="IP">
|
||||||
|
<div style="display: flex; align-items: center; gap: 4px;">
|
||||||
|
<a-input
|
||||||
|
v-model:value="addFreeClientIpParts[0]"
|
||||||
|
style="width: 56px;"
|
||||||
|
:maxlength="3"
|
||||||
|
@input="validateFreeClientIpPart(0)"
|
||||||
|
placeholder="0-255"
|
||||||
|
/>
|
||||||
|
<span>.</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="addFreeClientIpParts[1]"
|
||||||
|
style="width: 56px;"
|
||||||
|
:maxlength="3"
|
||||||
|
@input="validateFreeClientIpPart(1)"
|
||||||
|
placeholder="0-255"
|
||||||
|
/>
|
||||||
|
<span>.</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="addFreeClientIpParts[2]"
|
||||||
|
style="width: 56px;"
|
||||||
|
:maxlength="3"
|
||||||
|
@input="validateFreeClientIpPart(2)"
|
||||||
|
placeholder="0-255"
|
||||||
|
/>
|
||||||
|
<span>.</span>
|
||||||
|
<a-input
|
||||||
|
v-model:value="addFreeClientIpParts[3]"
|
||||||
|
style="width: 56px;"
|
||||||
|
:maxlength="3"
|
||||||
|
@input="validateFreeClientIpPart(3)"
|
||||||
|
placeholder="0-255"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-if="freeClientIpValidationError" style="color: #ff4d4f; font-size: 12px; margin-top: 4px;">
|
||||||
|
{{ freeClientIpValidationError }}
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="addFreeClientType === 4" label="MAC">
|
||||||
|
<div style="display: flex; align-items: center; gap: 4px;">
|
||||||
|
<a-input v-model:value="addFreeClientMacParts[0]" style="width: 40px;" :maxlength="2" />
|
||||||
|
<span>-</span>
|
||||||
|
<a-input v-model:value="addFreeClientMacParts[1]" style="width: 40px;" :maxlength="2" />
|
||||||
|
<span>-</span>
|
||||||
|
<a-input v-model:value="addFreeClientMacParts[2]" style="width: 40px;" :maxlength="2" />
|
||||||
|
<span>-</span>
|
||||||
|
<a-input v-model:value="addFreeClientMacParts[3]" style="width: 40px;" :maxlength="2" />
|
||||||
|
<span>-</span>
|
||||||
|
<a-input v-model:value="addFreeClientMacParts[4]" style="width: 40px;" :maxlength="2" />
|
||||||
|
<span>-</span>
|
||||||
|
<a-input v-model:value="addFreeClientMacParts[5]" style="width: 40px;" :maxlength="2" />
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</SimpleScrollbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, watch, h } from 'vue'
|
||||||
|
import { fetchSiteList, fetchAccessControl, updateAccessControl } from '@/service/api/auth'
|
||||||
|
import { DeleteOutlined } from '@ant-design/icons-vue'
|
||||||
|
import { message, Modal } from 'ant-design-vue'
|
||||||
|
import { SimpleScrollbar } from '~/packages/materials/src';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const preAuthEnabled = ref(true)
|
||||||
|
const freeClientEnabled = ref(true)
|
||||||
|
const preAuthList = ref([]) // 预认证白名单列表
|
||||||
|
const freeClientList = ref([]) // 免认证白名单列表
|
||||||
|
|
||||||
|
const siteList = ref<{ siteId: string, name: string }[]>([])
|
||||||
|
const selectedSiteId = ref('')
|
||||||
|
const siteLoading = ref(false)
|
||||||
|
|
||||||
|
// 新增:添加预认证白名单弹窗相关变量
|
||||||
|
const addPreAuthVisible = ref(false)
|
||||||
|
const addPreAuthType = ref(1) // 1: IP, 2: URL
|
||||||
|
const addPreAuthValue = ref('')
|
||||||
|
const addPreAuthIpParts = ref(['', '', '', '', '']) // [ip1, ip2, ip3, ip4, mask]
|
||||||
|
const ipValidationError = ref('')
|
||||||
|
|
||||||
|
// 新增:添加免认证白名单弹窗相关变量
|
||||||
|
const addFreeClientVisible = ref(false)
|
||||||
|
const addFreeClientType = ref(3) // 3: IP, 4: MAC
|
||||||
|
const addFreeClientIpParts = ref(['', '', '', ''])
|
||||||
|
const addFreeClientMacParts = ref(['', '', '', '', '', ''])
|
||||||
|
const freeClientIpValidationError = ref('')
|
||||||
|
|
||||||
|
// 定义表格列配置
|
||||||
|
const preAuthColumns = [
|
||||||
|
{
|
||||||
|
title: t('page.access.type'),
|
||||||
|
dataIndex: 'type',
|
||||||
|
key: 'type',
|
||||||
|
customRender: ({ record }: { record: any }) => {
|
||||||
|
if (record.type === 1) return 'IP'
|
||||||
|
if (record.type === 2) return 'URL'
|
||||||
|
return record.type
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.access.info'),
|
||||||
|
dataIndex: 'url',
|
||||||
|
key: 'url',
|
||||||
|
customRender: ({ record }: { record: any }) => {
|
||||||
|
if (record.type === 1) {
|
||||||
|
const ipDisplay = record.subnetMask ? `${record.ip}/${record.subnetMask}` : record.ip
|
||||||
|
return ipDisplay
|
||||||
|
}
|
||||||
|
if (record.type === 2) return record.url
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.access.action'),
|
||||||
|
key: 'action',
|
||||||
|
width: 120,
|
||||||
|
fixed: 'right',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ record }: { record: any }) => {
|
||||||
|
return h(
|
||||||
|
'a-button',
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
size: 'small',
|
||||||
|
style: { color: '#ff4d4f' },
|
||||||
|
onClick: () => handleDeletePreAuth(record)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: () => h(DeleteOutlined)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const freeClientColumns = [
|
||||||
|
{
|
||||||
|
title: t('page.access.type'),
|
||||||
|
dataIndex: 'type',
|
||||||
|
key: 'type',
|
||||||
|
customRender: ({ record }: { record: any }) => {
|
||||||
|
if (record.type === 3) return 'IP'
|
||||||
|
if (record.type === 4) return 'MAC'
|
||||||
|
return record.type
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.access.info'),
|
||||||
|
dataIndex: 'clientIp',
|
||||||
|
key: 'clientIp',
|
||||||
|
customRender: ({ record }: { record: any }) => {
|
||||||
|
if (record.type === 3) return record.clientIp
|
||||||
|
if (record.type === 4) return record.clientMac
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('page.access.action'),
|
||||||
|
key: 'action',
|
||||||
|
width: 120,
|
||||||
|
fixed: 'right',
|
||||||
|
align: 'center',
|
||||||
|
customRender: ({ record }: { record: any }) => {
|
||||||
|
return h(
|
||||||
|
'a-button',
|
||||||
|
{
|
||||||
|
type: 'link',
|
||||||
|
size: 'small',
|
||||||
|
style: { color: '#ff4d4f' },
|
||||||
|
onClick: () => handleDeleteFreeClient(record)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: () => h(DeleteOutlined)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const getSiteList = async () => {
|
||||||
|
siteLoading.value = true
|
||||||
|
const { data, error } = await fetchSiteList({ pageNum: 1, pageSize: 100 })
|
||||||
|
console.log('siteList接口返回', data, error)
|
||||||
|
if (!error) {
|
||||||
|
siteList.value = data.rows || []
|
||||||
|
console.log('siteList.value', siteList.value)
|
||||||
|
if (siteList.value.length > 0) {
|
||||||
|
selectedSiteId.value = siteList.value[0].siteId
|
||||||
|
console.log('getSiteList设置selectedSiteId', selectedSiteId.value)
|
||||||
|
await getAccessControl()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
siteLoading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAccessControl = async () => {
|
||||||
|
console.log('getAccessControl调用,selectedSiteId', selectedSiteId.value)
|
||||||
|
if (!selectedSiteId.value) return
|
||||||
|
const { data, error } = await fetchAccessControl(selectedSiteId.value)
|
||||||
|
console.log('accessControl接口返回', data, error)
|
||||||
|
if (!error && data) {
|
||||||
|
preAuthEnabled.value = !!data.preAuthAccessEnable
|
||||||
|
freeClientEnabled.value = !!data.freeAuthClientEnable
|
||||||
|
preAuthList.value = (data.preAuthAccessPolicies || []).map((item: any) => ({
|
||||||
|
key: String(item.idInt),
|
||||||
|
type: item.type,
|
||||||
|
ip: item.ip,
|
||||||
|
subnetMask: item.subnetMask,
|
||||||
|
url: item.url,
|
||||||
|
...item
|
||||||
|
}))
|
||||||
|
freeClientList.value = (data.freeAuthClientPolicies || []).map((item: any) => ({
|
||||||
|
key: String(item.idInt),
|
||||||
|
type: item.type,
|
||||||
|
clientIp: item.clientIp,
|
||||||
|
clientMac: item.clientMac,
|
||||||
|
...item
|
||||||
|
}))
|
||||||
|
console.log('preAuthList', preAuthList.value)
|
||||||
|
console.log('freeClientList', freeClientList.value)
|
||||||
|
} else {
|
||||||
|
console.log('getAccessControl未进入赋值分支', { error, data })
|
||||||
|
}
|
||||||
|
console.log('getAccessControl结束', preAuthList.value, freeClientList.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSiteChange = async (value: string) => {
|
||||||
|
selectedSiteId.value = value
|
||||||
|
// 不需要手动调用 getAccessControl,watch 会自动触发
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAddPreAuth = () => {
|
||||||
|
addPreAuthType.value = 1
|
||||||
|
addPreAuthValue.value = ''
|
||||||
|
addPreAuthIpParts.value = ['', '', '', '', '']
|
||||||
|
ipValidationError.value = ''
|
||||||
|
addPreAuthVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddPreAuthOk = () => {
|
||||||
|
if (addPreAuthType.value === 1) {
|
||||||
|
// 拼接IP
|
||||||
|
const ip = addPreAuthIpParts.value.slice(0, 4).join('.')
|
||||||
|
const mask = addPreAuthIpParts.value[4]
|
||||||
|
|
||||||
|
// IP地址格式校验
|
||||||
|
const ipRegex = /\b((?!\d\d\d)\d+|1\d\d|2[0-4]\d|25[0-5])\.((?!\d\d\d)\d+|1\d\d|2[0-4]\d|25[0-5])\.((?!\d\d\d)\d+|1\d\d|2[0-4]\d|25[0-5])\.((?!\d\d\d)\d+|1\d\d|2[0-4]\d|25[0-5])\b/
|
||||||
|
|
||||||
|
if (!ipRegex.test(ip)) {
|
||||||
|
message.error(t('page.access.iperror'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 子网掩码校验(如果输入了掩码)
|
||||||
|
if (mask) {
|
||||||
|
const maskNum = parseInt(mask)
|
||||||
|
if (isNaN(maskNum) || maskNum < 0 || maskNum > 32) {
|
||||||
|
message.error(t('page.access.subnetMask'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preAuthList.value.push({
|
||||||
|
key: Date.now() + Math.random(), // 简单唯一key
|
||||||
|
type: 1,
|
||||||
|
ip: ip,
|
||||||
|
subnetMask: mask || undefined,
|
||||||
|
url: null
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 只保存输入框内容,不带http(s)://
|
||||||
|
preAuthList.value.push({
|
||||||
|
key: Date.now() + Math.random(),
|
||||||
|
type: 2,
|
||||||
|
ip: null,
|
||||||
|
subnetMask: undefined,
|
||||||
|
url: addPreAuthValue.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
addPreAuthVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAddFreeClient = () => {
|
||||||
|
addFreeClientType.value = 3
|
||||||
|
addFreeClientIpParts.value = ['', '', '', '']
|
||||||
|
addFreeClientMacParts.value = ['', '', '', '', '', '']
|
||||||
|
freeClientIpValidationError.value = ''
|
||||||
|
addFreeClientVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddFreeClientOk = () => {
|
||||||
|
if (addFreeClientType.value === 3) {
|
||||||
|
// 拼接IP
|
||||||
|
const ip = addFreeClientIpParts.value.join('.')
|
||||||
|
|
||||||
|
// IP地址格式校验
|
||||||
|
const ipRegex = /\b((?!\d\d\d)\d+|1\d\d|2[0-4]\d|25[0-5])\.((?!\d\d\d)\d+|1\d\d|2[0-4]\d|25[0-5])\.((?!\d\d\d)\d+|1\d\d|2[0-4]\d|25[0-5])\.((?!\d\d\d)\d+|1\d\d|2[0-4]\d|25[0-5])\b/
|
||||||
|
|
||||||
|
if (!ipRegex.test(ip)) {
|
||||||
|
message.error(t('page.access.iperror'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
freeClientList.value.push({
|
||||||
|
key: Date.now() + Math.random(),
|
||||||
|
type: 3,
|
||||||
|
clientIp: ip,
|
||||||
|
clientMac: null
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 拼接MAC
|
||||||
|
const mac = addFreeClientMacParts.value.map(x => x.padStart(2, '0')).join('-')
|
||||||
|
freeClientList.value.push({
|
||||||
|
key: Date.now() + Math.random(),
|
||||||
|
type: 4,
|
||||||
|
clientIp: null,
|
||||||
|
clientMac: mac
|
||||||
|
})
|
||||||
|
}
|
||||||
|
addFreeClientVisible.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeletePreAuth = (record: any) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('page.access.deletetitle'),
|
||||||
|
content: t('page.access.deletebody'),
|
||||||
|
okText: t('page.access.ok'),
|
||||||
|
cancelText: t('page.access.cancel'),
|
||||||
|
onOk: () => {
|
||||||
|
preAuthList.value = preAuthList.value.filter(item => item.key !== record.key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDeleteFreeClient = (record: any) => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('page.access.deletetitle'),
|
||||||
|
content: t('page.access.deletebody'),
|
||||||
|
okText: t('page.access.ok'),
|
||||||
|
cancelText: t('page.access.cancel'),
|
||||||
|
onOk: () => {
|
||||||
|
freeClientList.value = freeClientList.value.filter(item => item.key !== record.key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听 selectedSiteId,变化时自动拉取白名单数据
|
||||||
|
watch(selectedSiteId, (val) => {
|
||||||
|
console.log('watch触发,selectedSiteId变为', val)
|
||||||
|
if (val) getAccessControl()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 在 script setup 中添加提交函数
|
||||||
|
const handleApply = async () => {
|
||||||
|
if (!selectedSiteId.value) {
|
||||||
|
// message.warning('请先选择站点')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 组装提交数据
|
||||||
|
const submitData = {
|
||||||
|
preAuthAccessEnable: preAuthEnabled.value,
|
||||||
|
freeAuthClientEnable: freeClientEnabled.value,
|
||||||
|
preAuthAccessPolicies: preAuthList.value.map(item => ({
|
||||||
|
type: item.type,
|
||||||
|
ip: item.type === 1 ? item.ip : undefined,
|
||||||
|
subnetMask: item.type === 1 ? item.subnetMask : undefined,
|
||||||
|
url: item.type === 2 ? item.url : undefined
|
||||||
|
})),
|
||||||
|
freeAuthClientPolicies: freeClientList.value.map(item => ({
|
||||||
|
type: item.type,
|
||||||
|
clientIp: item.type === 3 ? item.clientIp : undefined,
|
||||||
|
clientMac: item.type === 4 ? item.clientMac : undefined
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用更新接口
|
||||||
|
const { error } = await updateAccessControl(selectedSiteId.value, submitData)
|
||||||
|
if (!error) {
|
||||||
|
// message.error('提交失败')
|
||||||
|
message.success(t('page.access.applysuccess'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// message.success('提交成功')
|
||||||
|
// 重新获取最新数据
|
||||||
|
await getAccessControl()
|
||||||
|
} catch (e) {
|
||||||
|
console.error('提交出错:', e)
|
||||||
|
// message.error('提交失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在 script setup 中添加 Cancel 处理函数
|
||||||
|
const handleCancel = async () => {
|
||||||
|
if (!selectedSiteId.value) {
|
||||||
|
// message.warning('请先选择站点')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await getAccessControl()
|
||||||
|
// message.success('已刷新数据')
|
||||||
|
} catch (e) {
|
||||||
|
console.error('刷新数据出错:', e)
|
||||||
|
// message.error('刷新数据失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateIpPart = (index: number) => {
|
||||||
|
const value = addPreAuthIpParts.value[index]
|
||||||
|
if (value && !/^\d+$/.test(value)) {
|
||||||
|
ipValidationError.value = t('page.access.plenumber')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
const num = parseInt(value)
|
||||||
|
if (num < 0 || num > 255) {
|
||||||
|
ipValidationError.value = `IP${index + 1}must between 0-255`
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除错误信息
|
||||||
|
ipValidationError.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateMaskPart = () => {
|
||||||
|
const value = addPreAuthIpParts.value[4]
|
||||||
|
if (value && !/^\d+$/.test(value)) {
|
||||||
|
ipValidationError.value = t('page.access.plenumber')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
const num = parseInt(value)
|
||||||
|
if (num < 0 || num > 32) {
|
||||||
|
ipValidationError.value = t('page.access.subnetMask')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除错误信息
|
||||||
|
ipValidationError.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateFreeClientIpPart = (index: number) => {
|
||||||
|
const value = addFreeClientIpParts.value[index]
|
||||||
|
if (value && !/^\d+$/.test(value)) {
|
||||||
|
freeClientIpValidationError.value = t('page.access.plenumber')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
const num = parseInt(value)
|
||||||
|
if (num < 0 || num > 255) {
|
||||||
|
freeClientIpValidationError.value = `IP${index + 1}must in 0-255`
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除错误信息
|
||||||
|
freeClientIpValidationError.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
console.log('onMounted执行')
|
||||||
|
await getSiteList()
|
||||||
|
console.log('onMounted后selectedSiteId', selectedSiteId.value)
|
||||||
|
if (selectedSiteId.value) {
|
||||||
|
await getAccessControl()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.anticon-info-circle {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loaded 100 of 144 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user