Showing
58 changed files
with
2405 additions
and
905 deletions
Too many changes to show.
To preserve performance only 58 of 99 files are displayed.
... | ... | @@ -6,12 +6,18 @@ VITE_PUBLIC_PATH = / |
6 | 6 | |
7 | 7 | # Cross-domain proxy, you can configure multiple |
8 | 8 | # Please note that no line breaks |
9 | -# VITE_PROXY = [["/api","http://192.168.10.118:8080/api"],["/upload","http://192.168.10.116:3300/upload"]] | |
10 | -VITE_PROXY = [["/api","http://101.133.234.90:8080/api"],["/upload","http://192.168.10.116:3300/upload"]] | |
11 | -# VITE_PROXY=[["/api","https://vvbin.cn/test"]] | |
9 | + | |
10 | +# 本地 | |
11 | +# VITE_PROXY = [["/api","http://localhost:8080/api"]] | |
12 | + | |
13 | +# 线上 | |
14 | +VITE_PROXY = [["/api","http://101.133.234.90:8080/api"]] | |
15 | + | |
16 | +# 实时数据的ws地址 | |
17 | +VITE_WEB_SOCKET = ws://101.133.234.90:8080/api/ws/plugins/telemetry?token= | |
12 | 18 | |
13 | 19 | # Delete console |
14 | -VITE_DROP_CONSOLE = false | |
20 | +VITE_DROP_CONSOLE = true | |
15 | 21 | |
16 | 22 | # Basic interface address SPA |
17 | 23 | VITE_GLOB_API_URL=/api | ... | ... |
... | ... | @@ -10,26 +10,29 @@ VITE_DROP_CONSOLE = true |
10 | 10 | # Whether to enable gzip or brotli compression |
11 | 11 | # Optional: gzip | brotli | none |
12 | 12 | # If you need multiple forms, you can use `,` to separate |
13 | -VITE_BUILD_COMPRESS = 'none' | |
13 | +VITE_BUILD_COMPRESS = 'gzip' | |
14 | 14 | |
15 | 15 | # Whether to delete origin files when using compress, default false |
16 | 16 | VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false |
17 | 17 | |
18 | 18 | # Basic interface address SPA |
19 | -VITE_GLOB_API_URL=/api | |
19 | +VITE_GLOB_API_URL=http://localhost:8080/api | |
20 | 20 | |
21 | 21 | # File upload address, optional |
22 | 22 | # It can be forwarded by nginx or write the actual address directly |
23 | -VITE_GLOB_UPLOAD_URL=/upload | |
23 | +VITE_GLOB_UPLOAD_URL=http://localhost:8080/upload | |
24 | 24 | |
25 | 25 | # Interface prefix |
26 | -VITE_GLOB_API_URL_PREFIX=/v1 | |
26 | +VITE_GLOB_API_URL_PREFIX=/yt | |
27 | 27 | |
28 | 28 | # Whether to enable image compression |
29 | -VITE_USE_IMAGEMIN= true | |
29 | +VITE_USE_IMAGEMIN= false | |
30 | 30 | |
31 | 31 | # use pwa |
32 | 32 | VITE_USE_PWA = false |
33 | 33 | |
34 | 34 | # Is it compatible with older browsers |
35 | -VITE_LEGACY = false | |
35 | +VITE_LEGACY = true | |
36 | + | |
37 | +# 实时数据的ws地址 | |
38 | +VITE_WEB_SOCKET = ws://101.133.234.90:8080/api/ws/plugins/telemetry?token= | ... | ... |
configModel.ts
deleted
100644 → 0
1 | -import { BasicPageParams, BasicFetchResult } from '/@/api/model/baseModel'; | |
2 | -/** | |
3 | - * @description: Request list interface parameters | |
4 | - */ | |
5 | -export type MessageConfigParams = BasicPageParams & MessageParams; | |
6 | - | |
7 | -export type MessageParams = { | |
8 | - status?: number; | |
9 | - messageType?: string; | |
10 | -}; | |
11 | - | |
12 | -export interface MessageConfig { | |
13 | - id: string; | |
14 | - configName: string; | |
15 | - messageType: string; | |
16 | - platformType: string; | |
17 | - config: ConfigParams; | |
18 | - createTime: string; | |
19 | - updateTime: string; | |
20 | - status: number; | |
21 | -} | |
22 | -export interface ConfigParams { | |
23 | - host: string; | |
24 | - port: number; | |
25 | - username: string; | |
26 | - password: string; | |
27 | - accessKeyId: string; | |
28 | - accessKeySecret: string; | |
29 | -} | |
30 | - | |
31 | -/** | |
32 | - * @description: Request list return value | |
33 | - */ | |
34 | -export type MessageConfigResultModel = BasicFetchResult<MessageConfig>; | |
35 | - | |
36 | -export type MessageConfigResult = MessageConfig; |
... | ... | @@ -30,3 +30,14 @@ export const getDeviceDataKeys = (id: string) => { |
30 | 30 | } |
31 | 31 | ); |
32 | 32 | }; |
33 | +// 获取设备状态,在线 or 离线时间 | |
34 | +export const getDeviceActiveTime = (entityId: string) => { | |
35 | + return defHttp.get( | |
36 | + { | |
37 | + url: `/plugins/telemetry/DEVICE/${entityId}/values/attributes?keys=active`, | |
38 | + }, | |
39 | + { | |
40 | + joinPrefix: false, | |
41 | + } | |
42 | + ); | |
43 | +}; | ... | ... |
src/api/dashboard/index.ts
0 → 100644
1 | +import { BasicPageParams } from './../model/baseModel'; | |
2 | +import { defHttp } from '/@/utils/http/axios'; | |
3 | +enum HomeEnum { | |
4 | + home = '/homepage/left/top', | |
5 | + TenantExpireTimeList = '/homepage/right', | |
6 | + EntitiesQueryFind = '/entitiesQuery/find', | |
7 | +} | |
8 | + | |
9 | +export const getHomeData = () => { | |
10 | + return defHttp.get({ | |
11 | + url: HomeEnum.home, | |
12 | + }); | |
13 | +}; | |
14 | + | |
15 | +// 获取即将过期租户列表 | |
16 | +export const getTenantExpireTimeList = (params: BasicPageParams) => { | |
17 | + return defHttp.get({ | |
18 | + url: HomeEnum.TenantExpireTimeList, | |
19 | + params, | |
20 | + }); | |
21 | +}; | |
22 | + | |
23 | +// 获取entities实体ID | |
24 | +export const getEntitiesId = () => { | |
25 | + return defHttp.post( | |
26 | + { | |
27 | + url: HomeEnum.EntitiesQueryFind, | |
28 | + data: { | |
29 | + entityFilter: { | |
30 | + type: 'apiUsageState', | |
31 | + resolveMultiple: false, | |
32 | + }, | |
33 | + pageLink: { | |
34 | + pageSize: 1, | |
35 | + page: 0, | |
36 | + sortOrder: { | |
37 | + key: { | |
38 | + type: 'ENTITY_FIELD', | |
39 | + key: 'createdTime', | |
40 | + }, | |
41 | + direction: 'DESC', | |
42 | + }, | |
43 | + }, | |
44 | + entityFields: [ | |
45 | + { | |
46 | + type: 'ENTITY_FIELD', | |
47 | + key: 'name', | |
48 | + }, | |
49 | + { | |
50 | + type: 'ENTITY_FIELD', | |
51 | + key: 'label', | |
52 | + }, | |
53 | + { | |
54 | + type: 'ENTITY_FIELD', | |
55 | + key: 'additionalInfo', | |
56 | + }, | |
57 | + ], | |
58 | + }, | |
59 | + }, | |
60 | + { | |
61 | + joinPrefix: false, | |
62 | + } | |
63 | + ); | |
64 | +}; | ... | ... |
src/api/demo/error.ts
deleted
100644 → 0
src/api/demo/model/test.ts
deleted
100644 → 0
src/api/demo/tree.ts
deleted
100644 → 0
1 | -import { defHttp } from '/@/utils/http/axios'; | |
2 | - | |
3 | -enum Api { | |
4 | - TREE_OPTIONS_LIST = '/tree/getDemoOptions', | |
5 | -} | |
6 | - | |
7 | -/** | |
8 | - * @description: Get sample options value | |
9 | - */ | |
10 | -export const treeOptionsListApi = (params?: Recordable) => | |
11 | - defHttp.get<Recordable[]>({ url: Api.TREE_OPTIONS_LIST, params }); |
1 | -import { UploadApiResult } from './model/uploadModel'; | |
1 | +import { FileUploadResponse } from './model/uploadModel'; | |
2 | 2 | import { IPutPersonal } from './model/index'; |
3 | 3 | import { defHttp } from '/@/utils/http/axios'; |
4 | -import { UploadFileParams } from '/#/axios'; | |
5 | 4 | |
6 | 5 | enum API { |
7 | - BaseUploadUrl = '/api/yt/oss/upload', | |
6 | + BaseUploadUrl = '/oss/upload', | |
8 | 7 | PutPersonalUrl = '/user/center', |
9 | 8 | GetPersonalUrl = '/user/', |
10 | 9 | } |
11 | -/** | |
12 | - * @description: Upload interface | |
13 | - */ | |
14 | -export const uploadApi = ( | |
15 | - params: UploadFileParams, | |
16 | - onUploadProgress: (progressEvent: ProgressEvent) => void | |
17 | -) => { | |
18 | - return defHttp.uploadFile<UploadApiResult>( | |
19 | - { | |
20 | - url: API.BaseUploadUrl, | |
21 | - onUploadProgress, | |
22 | - }, | |
23 | - params | |
24 | - ); | |
10 | +export const uploadApi = (file) => { | |
11 | + return defHttp.post<FileUploadResponse>({ url: API.BaseUploadUrl, params: file }); | |
25 | 12 | }; |
26 | 13 | |
27 | 14 | export const personalGet = (id: string) => { | ... | ... |
... | ... | @@ -17,7 +17,7 @@ enum Api { |
17 | 17 | export const getMenuList = () => { |
18 | 18 | const userStore = useUserStore(); |
19 | 19 | let url = Api.GetMenuList; |
20 | - if (userStore.getRoleList.find((v) => v == RoleEnum.ROLE_SYS_ADMIN)) { | |
20 | + if (userStore.getRoleList.find((v) => v == RoleEnum.SYS_ADMIN)) { | |
21 | 21 | url = Api.SysAdminMenuList; |
22 | 22 | } |
23 | 23 | return defHttp.get<getMenuListResultModel>({ url }); | ... | ... |
src/assets/images/kf.png
0 → 100644
1.1 KB
src/assets/images/zh.png
0 → 100644
1.45 KB
... | ... | @@ -4,13 +4,14 @@ |
4 | 4 | --> |
5 | 5 | |
6 | 6 | <template> |
7 | - <div class="anticon" :class="getAppLogoClass" @click="goHome"> | |
8 | - <img :src="getLogo" /> | |
7 | + <div class="application" :class="getAppLogoClass"> | |
8 | + <img v-if="getLogo" :src="getLogo" /> | |
9 | + <img v-else src="/src/assets/images/logo.png" /> | |
9 | 10 | <span |
10 | 11 | class="ml-2 md:opacity-100" |
11 | 12 | :class="getTitleClass" |
12 | 13 | v-show="showTitle" |
13 | - style="white-space: nowrap" | |
14 | + style="white-space: nowrap; font-size: small" | |
14 | 15 | > |
15 | 16 | {{ getTitle }} |
16 | 17 | </span> |
... | ... | @@ -19,10 +20,8 @@ |
19 | 20 | <script lang="ts" setup> |
20 | 21 | import { computed, unref } from 'vue'; |
21 | 22 | import { useGlobSetting } from '/@/hooks/setting'; |
22 | - import { useGo } from '/@/hooks/web/usePage'; | |
23 | 23 | import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; |
24 | 24 | import { useDesign } from '/@/hooks/web/useDesign'; |
25 | - import { PageEnum } from '/@/enums/pageEnum'; | |
26 | 25 | import { useUserStore } from '/@/store/modules/user'; |
27 | 26 | const props = defineProps({ |
28 | 27 | /** |
... | ... | @@ -43,7 +42,6 @@ |
43 | 42 | const { getCollapsedShowTitle } = useMenuSetting(); |
44 | 43 | const userStore = useUserStore(); |
45 | 44 | const { title } = useGlobSetting(); |
46 | - const go = useGo(); | |
47 | 45 | |
48 | 46 | const getAppLogoClass = computed(() => [ |
49 | 47 | prefixCls, |
... | ... | @@ -56,12 +54,8 @@ |
56 | 54 | 'xs:opacity-0': !props.alwaysShowTitle, |
57 | 55 | }, |
58 | 56 | ]); |
59 | - | |
60 | - function goHome() { | |
61 | - go(userStore.getUserInfo.homePath || PageEnum.BASE_HOME); | |
62 | - } | |
63 | 57 | const getLogo = computed(() => { |
64 | - return userStore.platInfo?.logo ?? '/src/assets/images/logo.png'; | |
58 | + return userStore.platInfo?.logo; | |
65 | 59 | }); |
66 | 60 | const getTitle = computed(() => { |
67 | 61 | // 设置icon |
... | ... | @@ -82,7 +76,6 @@ |
82 | 76 | padding-left: 7px; |
83 | 77 | cursor: pointer; |
84 | 78 | transition: all 0.2s ease; |
85 | - | |
86 | 79 | &.light { |
87 | 80 | border-bottom: 1px solid @border-color-base; |
88 | 81 | } | ... | ... |
1 | 1 | export enum RoleEnum { |
2 | - ROLE_SYS_ADMIN = 'SYS_ADMIN', | |
3 | - ROLE_TENANT_ADMIN = 'TENANT_ADMIN', | |
4 | - ROLE_NORMAL_USER = 'CUSTOMER_USER', | |
5 | - ROLE_PLATFORM_ADMIN = 'PLATFORM_ADMIN', | |
2 | + SYS_ADMIN = 'SYS_ADMIN', | |
3 | + PLATFORM_ADMIN = 'PLATFORM_ADMIN', | |
4 | + TENANT_ADMIN = 'TENANT_ADMIN', | |
5 | + CUSTOMER_USER = 'CUSTOMER_USER', | |
6 | +} | |
7 | + | |
8 | +export function isAdmin(role: string) { | |
9 | + if (role === RoleEnum.SYS_ADMIN || role === RoleEnum.PLATFORM_ADMIN) { | |
10 | + return true; | |
11 | + } else if (role === RoleEnum.TENANT_ADMIN || role === RoleEnum.CUSTOMER_USER) { | |
12 | + return false; | |
13 | + } | |
6 | 14 | } | ... | ... |
src/hooks/web/useBatchDelete.ts
0 → 100644
1 | +import { ref, computed } from 'vue'; | |
2 | +import { useMessage } from '/@/hooks/web/useMessage'; | |
3 | +/** | |
4 | + * | |
5 | + * @param deleteFn 要删除的API接口方法 | |
6 | + * @param handleSuccess 刷新表格的方法 | |
7 | + * @returns { | |
8 | + * hasBatchDelete: 是否可以删除 | |
9 | + * selectionOptions 表格复选框配置项 | |
10 | + * handleDeleteOrBatchDelete 删除方法,适用单一删除和批量删除。参数为null为批量删除 | |
11 | + * } | |
12 | + * | |
13 | + */ | |
14 | +export interface selectionOptions { | |
15 | + rowKey: string; | |
16 | + clickToRowSelect: boolean; | |
17 | + rowSelection: { | |
18 | + onChange: (selectedRowKeys: string[]) => void; | |
19 | + type: 'radio' | 'checkbox'; | |
20 | + }; | |
21 | +} | |
22 | +export const useBatchDelete = ( | |
23 | + deleteFn: (deleteIds: string[]) => Promise<void>, | |
24 | + handleSuccess: () => void | |
25 | +) => { | |
26 | + const { createMessage } = useMessage(); | |
27 | + const selectedRowIds = ref<string[]>([]); | |
28 | + const hasBatchDelete = computed(() => selectedRowIds.value.length <= 0); | |
29 | + // 复选框事件 | |
30 | + const onSelectRowChange = (selectedRowKeys: string[]) => { | |
31 | + selectedRowIds.value = selectedRowKeys; | |
32 | + }; | |
33 | + const handleDeleteOrBatchDelete = async (record: Recordable | null) => { | |
34 | + if (record) { | |
35 | + try { | |
36 | + await deleteFn([record.id]); | |
37 | + createMessage.success('删除联系人成功'); | |
38 | + handleSuccess(); | |
39 | + } catch (e) { | |
40 | + createMessage.error('删除失败'); | |
41 | + } | |
42 | + } else { | |
43 | + try { | |
44 | + await deleteFn(selectedRowIds.value); | |
45 | + createMessage.success('批量删除联系人成功'); | |
46 | + selectedRowIds.value = []; | |
47 | + handleSuccess(); | |
48 | + } catch (e) { | |
49 | + createMessage.info('删除失败'); | |
50 | + } | |
51 | + } | |
52 | + }; | |
53 | + const selectionOptions: selectionOptions = { | |
54 | + rowKey: 'id', | |
55 | + clickToRowSelect: false, | |
56 | + rowSelection: { | |
57 | + onChange: onSelectRowChange, | |
58 | + type: 'checkbox', | |
59 | + }, | |
60 | + }; | |
61 | + return { hasBatchDelete, selectionOptions, handleDeleteOrBatchDelete }; | |
62 | +}; | ... | ... |
1 | 1 | import { FormSchema } from '/@/components/Table'; |
2 | +import { phoneRule, emailRule } from '/@/utils/rules'; | |
2 | 3 | |
3 | 4 | export const formSchema: FormSchema[] = [ |
4 | 5 | { |
5 | - field: 'nickName', | |
6 | + field: 'realName', | |
6 | 7 | label: '用户昵称', |
7 | 8 | colProps: { span: 13 }, |
8 | 9 | required: true, |
... | ... | @@ -20,6 +21,7 @@ export const formSchema: FormSchema[] = [ |
20 | 21 | componentProps: { |
21 | 22 | placeholder: '请输入手机号码', |
22 | 23 | }, |
24 | + rules: phoneRule, | |
23 | 25 | }, |
24 | 26 | { |
25 | 27 | field: 'email', |
... | ... | @@ -30,5 +32,6 @@ export const formSchema: FormSchema[] = [ |
30 | 32 | componentProps: { |
31 | 33 | placeholder: '请输入邮箱', |
32 | 34 | }, |
35 | + rules: emailRule, | |
33 | 36 | }, |
34 | 37 | ]; | ... | ... |
1 | 1 | <template> |
2 | 2 | <BasicModal |
3 | 3 | :useWrapper="true" |
4 | - width="80vw" | |
4 | + width="82vw" | |
5 | 5 | :height="compHeight" |
6 | 6 | v-bind="$attrs" |
7 | 7 | @register="registerModal" |
... | ... | @@ -22,15 +22,34 @@ |
22 | 22 | ><p style="font-size: 17px; margin-top: 7px; margin-left: 10px">个人信息</p></div |
23 | 23 | > |
24 | 24 | <div class="change-avatar" style="text-align: center"> |
25 | - <div class="mb-2">头像</div> | |
26 | - <CropperAvatar | |
27 | - :uploadApi="uploadApi" | |
28 | - :value="avatar" | |
29 | - btnText="更换头像" | |
30 | - :btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }" | |
31 | - @change="updateAvatar" | |
32 | - width="150" | |
33 | - /> | |
25 | + <div class="mb-2" style="font-weight: 700">个人头像</div> | |
26 | + <Upload | |
27 | + style="width: 20vw" | |
28 | + name="avatar" | |
29 | + list-type="picture-card" | |
30 | + class="avatar-uploader" | |
31 | + :show-upload-list="false" | |
32 | + :customRequest="customUploadqrcodePic" | |
33 | + :before-upload="beforeUploadqrcodePic" | |
34 | + > | |
35 | + <img | |
36 | + style="text-align: center; border-radius: 50%; width: 10vw; height: 15vh" | |
37 | + v-if="peresonalPic" | |
38 | + :src="peresonalPic" | |
39 | + alt="avatar" | |
40 | + /> | |
41 | + <div v-else> | |
42 | + <div style="margin-top: 30px"> | |
43 | + <PlusOutlined style="font-size: 30px" /> | |
44 | + </div> | |
45 | + <div | |
46 | + class="ant-upload-text flex" | |
47 | + style="width: 280px; height: 130px; align-items: center" | |
48 | + > | |
49 | + 支持.PNG、.JPG、.SVG格式,建议尺寸为300px × 300px(及以上),大小不超过2M。</div | |
50 | + > | |
51 | + </div> | |
52 | + </Upload> | |
34 | 53 | </div> |
35 | 54 | <Description |
36 | 55 | class="mt-8" |
... | ... | @@ -66,13 +85,13 @@ |
66 | 85 | import { BasicForm, useForm } from '/@/components/Form/index'; |
67 | 86 | import { formSchema } from './config'; |
68 | 87 | import { Description, DescItem, useDescription } from '/@/components/Description/index'; |
69 | - import { CropperAvatar } from '/@/components/Cropper'; | |
70 | - import defaultImage from '/@/assets/images/logo.png'; | |
71 | 88 | import { uploadApi, personalPut } from '/@/api/personal/index'; |
72 | 89 | import { useMessage } from '/@/hooks/web/useMessage'; |
73 | 90 | import { USER_INFO_KEY } from '/@/enums/cacheEnum'; |
74 | 91 | import { getAuthCache } from '/@/utils/auth'; |
75 | - import { useUserStore } from '/@/store/modules/user'; | |
92 | + import { Upload } from 'ant-design-vue'; | |
93 | + import { PlusOutlined } from '@ant-design/icons-vue'; | |
94 | + import type { FileItem } from '/@/components/Upload/src/typing'; | |
76 | 95 | |
77 | 96 | const schema: DescItem[] = [ |
78 | 97 | { |
... | ... | @@ -102,68 +121,91 @@ |
102 | 121 | ]; |
103 | 122 | export default defineComponent({ |
104 | 123 | name: 'index', |
105 | - components: { BasicModal, BasicForm, Description, CropperAvatar }, | |
106 | - setup() { | |
107 | - const userStore = useUserStore(); | |
124 | + components: { BasicModal, BasicForm, Description, Upload, PlusOutlined }, | |
125 | + emits: ['refreshPersonl', 'register'], | |
126 | + setup(_, { emit }) { | |
108 | 127 | const userInfo = getAuthCache(USER_INFO_KEY); |
109 | 128 | const { createMessage } = useMessage(); |
110 | 129 | const getPersonalValue: any = ref({}); |
111 | 130 | const getPersonalDetailValue: any = ref({}); |
112 | - const avatarUrl: any = ref(''); | |
131 | + const updatePersonalData: any = ref({}); | |
113 | 132 | const getBackendV: any = ref({}); |
114 | 133 | const [registerDesc] = useDescription({ |
115 | 134 | title: '个人详情', |
116 | 135 | schema: schema, |
117 | 136 | }); |
118 | 137 | |
119 | - const [registerModal, { closeModal }] = useModalInner(); | |
120 | - const [registerForm, { validate, resetFields }] = useForm({ | |
138 | + const peresonalPic = ref(); | |
139 | + | |
140 | + const customUploadqrcodePic = async ({ file }) => { | |
141 | + if (beforeUploadqrcodePic(file)) { | |
142 | + const formData = new FormData(); | |
143 | + formData.append('file', file); | |
144 | + const response = await uploadApi(formData); | |
145 | + if (response.fileStaticUri) { | |
146 | + peresonalPic.value = response.fileStaticUri; | |
147 | + } | |
148 | + } | |
149 | + }; | |
150 | + | |
151 | + const beforeUploadqrcodePic = (file: FileItem) => { | |
152 | + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; | |
153 | + if (!isJpgOrPng) { | |
154 | + createMessage.error('只能上传图片文件!'); | |
155 | + } | |
156 | + const isLt2M = (file.size as number) / 1024 / 1024 < 2; | |
157 | + if (!isLt2M) { | |
158 | + createMessage.error('图片大小不能超过2MB!'); | |
159 | + } | |
160 | + return isJpgOrPng && isLt2M; | |
161 | + }; | |
162 | + | |
163 | + const [registerForm, { validate, resetFields, setFieldsValue }] = useForm({ | |
121 | 164 | showActionButtonGroup: false, |
122 | 165 | schemas: formSchema, |
123 | 166 | }); |
124 | - const avatar = computed(() => { | |
125 | - const { avatar } = userStore.getUserInfo; | |
126 | - return avatar || defaultImage; | |
167 | + | |
168 | + const [registerModal, { closeModal }] = useModalInner(async (data) => { | |
169 | + (peresonalPic.value = data.userInfo.avatar), | |
170 | + setFieldsValue({ | |
171 | + realName: data.userInfo.realName, | |
172 | + phoneNumber: data.userInfo.phoneNumber, | |
173 | + email: data.userInfo.email, | |
174 | + }); | |
175 | + if (data.userInfo) { | |
176 | + getPersonalDetailValue.value = data.userInfo; | |
177 | + } | |
178 | + if (Object.keys(updatePersonalData.value).length != 0) { | |
179 | + getPersonalDetailValue.value = updatePersonalData.value; | |
180 | + peresonalPic.value = updatePersonalData.value.avatar; | |
181 | + setFieldsValue({ | |
182 | + realName: updatePersonalData.value.realName, | |
183 | + phoneNumber: updatePersonalData.value.phoneNumber, | |
184 | + email: updatePersonalData.value.email, | |
185 | + }); | |
186 | + } | |
127 | 187 | }); |
128 | 188 | const handleSubmit = async () => { |
129 | - // console.log(userStore.getUserInfo); | |
130 | 189 | const getUserInfo = await userInfo; |
131 | - // console.log(getUserInfo); | |
132 | 190 | getPersonalValue.value = await validate(); |
133 | 191 | getPersonalValue.value.id = getUserInfo.userId; |
134 | 192 | getPersonalValue.value.username = getBackendV.value.username; |
135 | - getPersonalValue.value.avatar = avatarUrl.value; | |
136 | - await personalPut(getPersonalValue.value); | |
193 | + getPersonalValue.value.avatar = peresonalPic.value; | |
194 | + const data = await personalPut(getPersonalValue.value); | |
195 | + updatePersonalData.value = data; | |
137 | 196 | createMessage.success('修改成功'); |
138 | 197 | closeModal(); |
139 | 198 | resetFields(); |
199 | + emit('refreshPersonl', updatePersonalData.value); | |
140 | 200 | }; |
141 | - const updateAvatar = async (v) => { | |
142 | - avatarUrl.value = v.data.fileStaticUri; | |
143 | - // console.log(avatarUrl.value); | |
144 | - // await personalPut({ avatar: v }); | |
145 | - }; | |
146 | - const getPersonalDetail = async () => { | |
147 | - try { | |
148 | - const getUserInfo = await userInfo; | |
149 | - getPersonalDetailValue.value = getUserInfo; | |
150 | - } catch (e) { | |
151 | - return e; | |
152 | - } | |
153 | - }; | |
154 | - getPersonalDetail(); | |
155 | - | |
156 | - // onMounted(async () => { | |
157 | - // getPersonalDetail(); | |
158 | - // }); | |
159 | 201 | const compHeight = computed(() => { |
160 | 202 | return 1000; |
161 | 203 | }); |
162 | 204 | return { |
163 | - uploadApi, | |
205 | + peresonalPic, | |
206 | + beforeUploadqrcodePic, | |
207 | + customUploadqrcodePic, | |
164 | 208 | compHeight, |
165 | - updateAvatar, | |
166 | - avatar, | |
167 | 209 | handleSubmit, |
168 | 210 | getPersonalDetailValue, |
169 | 211 | registerDesc, |
... | ... | @@ -174,4 +216,22 @@ |
174 | 216 | }, |
175 | 217 | }); |
176 | 218 | </script> |
177 | -<style lang="less"></style> | |
219 | +<style scoped lang="less"> | |
220 | + .change-avatar { | |
221 | + /deep/ .ant-upload-select-picture-card { | |
222 | + display: inherit; | |
223 | + float: none; | |
224 | + width: 10vw; | |
225 | + height: 17vh; | |
226 | + margin-right: 8px; | |
227 | + margin-bottom: 8px; | |
228 | + text-align: center; | |
229 | + vertical-align: top; | |
230 | + background-color: #fafafa; | |
231 | + border: 1px dashed #d9d9d9; | |
232 | + border-radius: 50%; | |
233 | + cursor: pointer; | |
234 | + transition: border-color 0.3s ease; | |
235 | + } | |
236 | + } | |
237 | +</style> | ... | ... |
1 | 1 | <template> |
2 | 2 | <Dropdown placement="bottomLeft" :overlayClassName="`${prefixCls}-dropdown-overlay`"> |
3 | 3 | <span :class="[prefixCls, `${prefixCls}--${theme}`]" class="flex"> |
4 | - <img :class="`${prefixCls}__header`" :src="getUserInfo.avatar" /> | |
4 | + <img | |
5 | + :class="`${prefixCls}__header`" | |
6 | + :src="refreshPersonlData.avatar ? refreshPersonlData.avatar : getUserInfo.avatar" | |
7 | + /> | |
5 | 8 | <span :class="`${prefixCls}__info hidden md:block`"> |
6 | 9 | <span :class="`${prefixCls}__name `" class="truncate"> |
7 | - {{ getUserInfo.realName }} | |
10 | + {{ refreshPersonlData.realName ? refreshPersonlData.realName : getUserInfo.realName }} | |
8 | 11 | </span> |
9 | 12 | </span> |
10 | 13 | </span> |
... | ... | @@ -12,12 +15,10 @@ |
12 | 15 | <template #overlay> |
13 | 16 | <Menu @click="handleMenuClick"> |
14 | 17 | <MenuItem |
15 | - key="doc" | |
16 | - :text="t('layout.header.dropdownItemDoc')" | |
18 | + key="personal" | |
19 | + :text="t('layout.header.dropdownItemPersonal')" | |
17 | 20 | icon="ion:document-text-outline" |
18 | - v-if="getShowDoc" | |
19 | 21 | /> |
20 | - <MenuDivider v-if="getShowDoc" /> | |
21 | 22 | <MenuItem |
22 | 23 | v-if="getUseLockPage" |
23 | 24 | key="lock" |
... | ... | @@ -29,22 +30,21 @@ |
29 | 30 | :text="t('layout.header.dropdownItemLoginOut')" |
30 | 31 | icon="ion:power-outline" |
31 | 32 | /> |
32 | - <MenuItem | |
33 | - key="personal" | |
34 | - :text="t('layout.header.dropdownItemPersonal')" | |
35 | - icon="ion:build-outlined" | |
36 | - /> | |
37 | 33 | </Menu> |
38 | 34 | </template> |
39 | 35 | </Dropdown> |
40 | 36 | <LockAction @register="register" /> |
41 | - <PersonalChild @register="registerPersonal" /> | |
37 | + <PersonalChild | |
38 | + @refreshPersonl="refreshPersonlFunc" | |
39 | + ref="personalRef" | |
40 | + @register="registerPersonal" | |
41 | + /> | |
42 | 42 | </template> |
43 | 43 | <script lang="ts"> |
44 | 44 | // components |
45 | 45 | import { Dropdown, Menu } from 'ant-design-vue'; |
46 | 46 | |
47 | - import { defineComponent, computed } from 'vue'; | |
47 | + import { defineComponent, computed, getCurrentInstance, ref, reactive } from 'vue'; | |
48 | 48 | |
49 | 49 | import { DOC_URL } from '/@/settings/siteSetting'; |
50 | 50 | |
... | ... | @@ -53,13 +53,12 @@ |
53 | 53 | import { useI18n } from '/@/hooks/web/useI18n'; |
54 | 54 | import { useDesign } from '/@/hooks/web/useDesign'; |
55 | 55 | import { useModal } from '/@/components/Modal'; |
56 | - | |
57 | 56 | import headerImg from '/@/assets/images/header.jpg'; |
58 | 57 | import { propTypes } from '/@/utils/propTypes'; |
59 | 58 | import { openWindow } from '/@/utils'; |
60 | - | |
61 | 59 | import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
62 | - | |
60 | + import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | |
61 | + import { getAuthCache } from '/@/utils/auth'; | |
63 | 62 | type MenuEvent = 'logout' | 'doc' | 'lock' | 'personal'; |
64 | 63 | |
65 | 64 | export default defineComponent({ |
... | ... | @@ -68,7 +67,6 @@ |
68 | 67 | Dropdown, |
69 | 68 | Menu, |
70 | 69 | MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')), |
71 | - MenuDivider: Menu.Divider, | |
72 | 70 | LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')), |
73 | 71 | PersonalChild: createAsyncComponent(() => import('../personal/index.vue')), |
74 | 72 | }, |
... | ... | @@ -76,14 +74,21 @@ |
76 | 74 | theme: propTypes.oneOf(['dark', 'light']), |
77 | 75 | }, |
78 | 76 | setup() { |
77 | + const refreshPersonlData = reactive({ | |
78 | + avatar: '', | |
79 | + realName: '', | |
80 | + }); | |
81 | + const userInfo = getAuthCache(USER_INFO_KEY); | |
82 | + const { proxy } = getCurrentInstance(); | |
83 | + const personalRef = ref(null); | |
79 | 84 | const { prefixCls } = useDesign('header-user-dropdown'); |
80 | 85 | const { t } = useI18n(); |
81 | 86 | const { getShowDoc, getUseLockPage } = useHeaderSetting(); |
82 | 87 | const userStore = useUserStore(); |
83 | 88 | |
84 | 89 | const getUserInfo = computed(() => { |
85 | - const { realName = '', avatar, desc } = userStore.getUserInfo || {}; | |
86 | - return { realName, avatar: avatar || headerImg, desc }; | |
90 | + const { realName = '', avatar } = userStore.getUserInfo || {}; | |
91 | + return { realName, avatar: avatar || headerImg }; | |
87 | 92 | }); |
88 | 93 | |
89 | 94 | const [register, { openModal }] = useModal(); |
... | ... | @@ -122,11 +127,21 @@ |
122 | 127 | |
123 | 128 | const openPersonalFunc = () => { |
124 | 129 | setTimeout(() => { |
125 | - openModalPersonal(true); | |
130 | + openModalPersonal(true, { | |
131 | + userInfo, | |
132 | + }); | |
126 | 133 | }, 10); |
127 | 134 | }; |
128 | 135 | |
136 | + const refreshPersonlFunc = (v) => { | |
137 | + refreshPersonlData.avatar = v.avatar; | |
138 | + refreshPersonlData.realName = v.realName; | |
139 | + }; | |
140 | + | |
129 | 141 | return { |
142 | + refreshPersonlData, | |
143 | + refreshPersonlFunc, | |
144 | + personalRef, | |
130 | 145 | registerPersonal, |
131 | 146 | openPersonalFunc, |
132 | 147 | prefixCls, | ... | ... |
... | ... | @@ -21,43 +21,18 @@ |
21 | 21 | </transition> |
22 | 22 | </template> |
23 | 23 | </RouterView> |
24 | - <!-- <BasicModal | |
25 | - @register="register" | |
26 | - v-bind="$attrs" | |
27 | - :mask="true" | |
28 | - :showCancelBtn="false" | |
29 | - :showOkBtn="false" | |
30 | - :canFullscreen="false" | |
31 | - :closable="false" | |
32 | - :maskStyle="maskColor" | |
33 | - :height="600" | |
34 | - :width="1500" | |
35 | - :maskClosable="false" | |
36 | - title="请您修改初始密码" | |
37 | - :helpMessage="['请您修改初始密码']" | |
38 | - :keyboard="false" | |
39 | - > | |
40 | - <PasswordDialog /> | |
41 | - </BasicModal> --> | |
24 | + | |
42 | 25 | <FrameLayout v-if="getCanEmbedIFramePage" /> |
43 | 26 | </template> |
44 | 27 | |
45 | 28 | <script lang="ts"> |
46 | - import { computed, defineComponent, unref, onMounted } from 'vue'; | |
47 | - // import PasswordDialog from '/@/views/system/password/index.vue'; | |
48 | - | |
29 | + import { computed, defineComponent, unref } from 'vue'; | |
49 | 30 | import FrameLayout from '/@/layouts/iframe/index.vue'; |
50 | - | |
51 | 31 | import { useRootSetting } from '/@/hooks/setting/useRootSetting'; |
52 | - | |
53 | 32 | import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; |
54 | 33 | import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; |
55 | 34 | import { getTransitionName } from './transition'; |
56 | - | |
57 | 35 | import { useMultipleTabStore } from '/@/store/modules/multipleTab'; |
58 | - // import { BasicModal, useModal } from '/@/components/Modal'; | |
59 | - // import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | |
60 | - // import { getAuthCache } from '/@/utils/auth'; | |
61 | 36 | export default defineComponent({ |
62 | 37 | name: 'PageLayout', |
63 | 38 | components: { FrameLayout }, |
... | ... | @@ -78,17 +53,6 @@ |
78 | 53 | return tabStore.getCachedTabList; |
79 | 54 | }); |
80 | 55 | |
81 | - // const [register, { openModal }] = useModal(); | |
82 | - // const maskColor = ref({ backgroundColor: 'grey' }); | |
83 | - // const statusModel = ref(false); | |
84 | - onMounted(() => { | |
85 | - // const userInfo = getAuthCache(USER_INFO_KEY); | |
86 | - // if (userInfo.needSetPwd == true) { | |
87 | - // statusModel.value = true; | |
88 | - // openModal(statusModel.value); | |
89 | - // } | |
90 | - }); | |
91 | - | |
92 | 56 | return { |
93 | 57 | getTransitionName, |
94 | 58 | openCache, |
... | ... | @@ -96,8 +60,6 @@ |
96 | 60 | getBasicTransition, |
97 | 61 | getCaches, |
98 | 62 | getCanEmbedIFramePage, |
99 | - // register, | |
100 | - // maskColor, | |
101 | 63 | }; |
102 | 64 | }, |
103 | 65 | }); | ... | ... |
... | ... | @@ -12,7 +12,7 @@ export default { |
12 | 12 | networkExceptionMsg: |
13 | 13 | 'Please check if your network connection is normal! The network is abnormal', |
14 | 14 | |
15 | - errMsg401: 'no permission', | |
15 | + errMsg401: '', | |
16 | 16 | errMsg403: 'not authorized', |
17 | 17 | errMsg404: 'the resource was not found!', |
18 | 18 | errMsg405: 'Network request error, request method not allowed!', | ... | ... |
... | ... | @@ -10,8 +10,7 @@ export default { |
10 | 10 | apiRequestFailed: '请求出错,请稍候重试', |
11 | 11 | networkException: '网络异常', |
12 | 12 | networkExceptionMsg: '网络异常,请检查您的网络连接是否正常!', |
13 | - | |
14 | - errMsg401: '没有权限!', | |
13 | + errMsg401: '', | |
15 | 14 | errMsg403: '未授权', |
16 | 15 | errMsg404: '未找到该资源!', |
17 | 16 | errMsg405: '网络请求错误,请求方法未允许!', | ... | ... |
... | ... | @@ -14,13 +14,7 @@ import { setupStore } from '/@/store'; |
14 | 14 | import { setupGlobDirectives } from '/@/directives'; |
15 | 15 | import { setupI18n } from '/@/locales/setupI18n'; |
16 | 16 | import { registerGlobComp } from '/@/components/registerGlobComp'; |
17 | -// Do not introduce on-demand in local development? | |
18 | -// In the local development for introduce on-demand, the number of browser requests will increase by about 20%. | |
19 | -// Which may slow down the browser refresh. | |
20 | -// Therefore, all are introduced in local development, and only introduced on demand in the production environment | |
21 | -if (import.meta.env.DEV) { | |
22 | - import('ant-design-vue/dist/antd.less'); | |
23 | -} | |
17 | +import 'ant-design-vue/dist/antd.less'; | |
24 | 18 | |
25 | 19 | async function bootstrap() { |
26 | 20 | const app = createApp(App); | ... | ... |
... | ... | @@ -129,7 +129,6 @@ export const useUserStore = defineStore({ |
129 | 129 | try { |
130 | 130 | const { goHome = true, mode, ...loginParams } = params; |
131 | 131 | const data = await loginApi(loginParams, mode); |
132 | - console.log(data); | |
133 | 132 | return this.process(data, goHome); |
134 | 133 | } catch (error) { |
135 | 134 | return Promise.reject(error); | ... | ... |
... | ... | @@ -10,7 +10,6 @@ import { SessionTimeoutProcessingEnum } from '/@/enums/appEnum'; |
10 | 10 | const { createMessage, createErrorModal } = useMessage(); |
11 | 11 | const error = createMessage.error!; |
12 | 12 | const stp = projectSetting.sessionTimeoutProcessing; |
13 | - | |
14 | 13 | export function checkStatus( |
15 | 14 | status: number, |
16 | 15 | msg: string, |
... | ... | @@ -19,7 +18,6 @@ export function checkStatus( |
19 | 18 | const { t } = useI18n(); |
20 | 19 | const userStore = useUserStoreWithOut(); |
21 | 20 | let errMessage = ''; |
22 | - | |
23 | 21 | switch (status) { |
24 | 22 | case 400: |
25 | 23 | errMessage = `${msg}`; | ... | ... |
... | ... | @@ -10,58 +10,17 @@ import { useGlobSetting } from '/@/hooks/setting'; |
10 | 10 | import { useMessage } from '/@/hooks/web/useMessage'; |
11 | 11 | import { RequestEnum, ContentTypeEnum } from '/@/enums/httpEnum'; |
12 | 12 | import { isString } from '/@/utils/is'; |
13 | -import { getJwtToken, getAuthCache } from '/@/utils/auth'; | |
13 | +import { getJwtToken } from '/@/utils/auth'; | |
14 | 14 | import { setObjToUrlParams, deepMerge } from '/@/utils'; |
15 | 15 | import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog'; |
16 | 16 | import { useI18n } from '/@/hooks/web/useI18n'; |
17 | 17 | import { joinTimestamp, formatRequestDate } from './helper'; |
18 | 18 | import { PageEnum } from '/@/enums/pageEnum'; |
19 | -import { REFRESH_TOKEN_KEY } from '/@/enums/cacheEnum'; | |
20 | 19 | import { router } from '/@/router'; |
21 | 20 | |
22 | -// import { useUserStore } from '/@/store/modules/user'; | |
23 | -// const userStore = useUserStore(); | |
24 | -// console.log(userStore.userInfo); | |
25 | - | |
26 | -// YUNTENG IOT__DEVELOPMENT__2.7.1__COMMON__LOCAL__KEY__ | |
27 | - | |
28 | -function timestampToTime(timestamp) { | |
29 | - const date = new Date(timestamp); //时间戳为10位需*1000,时间戳为13位的话不需乘1000 | |
30 | - const Y = date.getFullYear() + '-'; | |
31 | - const M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1) + '-'; | |
32 | - const D = date.getDate() + ' '; | |
33 | - const h = date.getHours() + ':'; | |
34 | - const m = date.getMinutes() + ':'; | |
35 | - const s = date.getSeconds(); | |
36 | - return Y + M + D + h + m + s; | |
37 | -} | |
38 | - | |
39 | -function convertToDate() { | |
40 | - const date = new Date(); | |
41 | - const y = date.getFullYear(); | |
42 | - let m = date.getMonth() + 1; | |
43 | - let d = date.getDate(); | |
44 | - let h = date.getHours(); | |
45 | - let min = date.getMinutes(); | |
46 | - let s = date.getSeconds(); | |
47 | - m = m < 10 ? '0' + m : m; //月小于10,加0 | |
48 | - d = d < 10 ? '0' + d : d; //day小于10,加0 | |
49 | - h = h < 10 ? '0' + h : h; | |
50 | - min = min < 10 ? '0' + min : min; | |
51 | - s = s < 10 ? '0' + s : s; | |
52 | - return y + '-' + m + '-' + d + ' ' + h + ':' + min + ':' + s; | |
53 | -} | |
54 | - | |
55 | 21 | const globSetting = useGlobSetting(); |
56 | 22 | const urlPrefix = globSetting.urlPrefix; |
57 | 23 | const { createMessage, createErrorModal } = useMessage(); |
58 | -const getJwtTokenInfo = getAuthCache(REFRESH_TOKEN_KEY); | |
59 | -const getExiper = window.localStorage.getItem( | |
60 | - 'UNDEFINED__DEVELOPMENT__2.7.1__COMMON__LOCAL__KEY__' | |
61 | -); | |
62 | -const getExiperValue = JSON.parse(getExiper); | |
63 | -const expireTime = timestampToTime(getExiperValue.expire); | |
64 | -const nowTime = convertToDate(); | |
65 | 24 | |
66 | 25 | /** |
67 | 26 | * @description: 数据处理,方便区分多种处理方式 |
... | ... | @@ -162,32 +121,13 @@ const transform: AxiosTransform = { |
162 | 121 | const msg: string = response?.data?.msg ?? ''; |
163 | 122 | const err: string = error?.toString?.() ?? ''; |
164 | 123 | let errMessage = ''; |
165 | - | |
166 | 124 | try { |
167 | - if (response.data.code === '401' || response.data.msg === 'tenant has expired') { | |
168 | - if (expireTime < nowTime) { | |
169 | - // console.log('过期'); | |
170 | - createMessage.error('token已经过期,请退回登录'); | |
171 | - } else { | |
172 | - // console.log('未过期'); | |
173 | - } | |
174 | - if (getJwtTokenInfo) { | |
175 | - if (PageEnum.BASE_LOGIN) { | |
176 | - router.push(PageEnum.BASE_LOGIN); | |
177 | - } | |
178 | - } | |
179 | - // router.beforeEach((to, from, next) => { | |
180 | - // if (getJwtTokenInfo) { | |
181 | - // if (to.path !== '/login') { | |
182 | - // // doRefresh(); | |
183 | - // next({ path: '/' }); | |
184 | - // } | |
185 | - // } | |
186 | - // }); | |
187 | - } else { | |
188 | - // doRefresh(); | |
125 | + console.log(response.data); | |
126 | + if (response.data.status == '401' || response.data.message == '"Authentication failed"') { | |
127 | + window.localStorage.clear(); | |
128 | + window.sessionStorage.clear(); | |
129 | + router.push(PageEnum.BASE_HOME); | |
189 | 130 | } |
190 | - | |
191 | 131 | if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) { |
192 | 132 | errMessage = t('sys.api.apiTimeoutMessage'); |
193 | 133 | } | ... | ... |
... | ... | @@ -60,3 +60,171 @@ export const EmailRegexp = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a |
60 | 60 | |
61 | 61 | // 手机号正则 |
62 | 62 | export const PhoneRegexp = /^[1][3,4,5,6,7,8,9][0-9]{9}$/; |
63 | + | |
64 | +//站内通知 | |
65 | +export const NotificationTitleMaxLength: Rule[] = [ | |
66 | + { | |
67 | + required: true, | |
68 | + validator: (_, value: string) => { | |
69 | + if (String(value).length > 50) { | |
70 | + return Promise.reject('标题长度不超过200字'); | |
71 | + } | |
72 | + return Promise.resolve(); | |
73 | + }, | |
74 | + validateTrigger: 'blur', | |
75 | + }, | |
76 | +]; | |
77 | + | |
78 | +export const NotificationContentMaxLength: Rule[] = [ | |
79 | + { | |
80 | + required: true, | |
81 | + validator: (_, value: string) => { | |
82 | + if (String(value).length > 50) { | |
83 | + return Promise.reject('内容长度不超过50字'); | |
84 | + } | |
85 | + return Promise.resolve(); | |
86 | + }, | |
87 | + validateTrigger: 'blur', | |
88 | + }, | |
89 | +]; | |
90 | + | |
91 | +export const DeviceNameMaxLength: Rule[] = [ | |
92 | + { | |
93 | + required: true, | |
94 | + validator: (_, value: string) => { | |
95 | + if (String(value).length > 30) { | |
96 | + return Promise.reject('设备名称长度不超过30字'); | |
97 | + } | |
98 | + return Promise.resolve(); | |
99 | + }, | |
100 | + validateTrigger: 'blur', | |
101 | + }, | |
102 | +]; | |
103 | + | |
104 | +export const DeviceProfileIdMaxLength: Rule[] = [ | |
105 | + { | |
106 | + required: true, | |
107 | + validator: (_, value: string) => { | |
108 | + if (String(value).length > 36) { | |
109 | + return Promise.reject('设备配置长度不超过36字'); | |
110 | + } | |
111 | + return Promise.resolve(); | |
112 | + }, | |
113 | + validateTrigger: 'blur', | |
114 | + }, | |
115 | +]; | |
116 | + | |
117 | +export const DeviceOrgIdMaxLength: Rule[] = [ | |
118 | + { | |
119 | + required: true, | |
120 | + validator: (_, value: string) => { | |
121 | + if (String(value).length > 36) { | |
122 | + return Promise.reject('组织长度不超过36字'); | |
123 | + } | |
124 | + return Promise.resolve(); | |
125 | + }, | |
126 | + validateTrigger: 'blur', | |
127 | + }, | |
128 | +]; | |
129 | + | |
130 | +export const DeviceLabelMaxLength: Rule[] = [ | |
131 | + { | |
132 | + required: true, | |
133 | + validator: (_, value: string) => { | |
134 | + if (String(value).length > 255) { | |
135 | + return Promise.reject('设备标签不超过255字'); | |
136 | + } | |
137 | + return Promise.resolve(); | |
138 | + }, | |
139 | + validateTrigger: 'blur', | |
140 | + }, | |
141 | +]; | |
142 | +export const DeviceDescriptionlMaxLength: Rule[] = [ | |
143 | + { | |
144 | + required: true, | |
145 | + validator: (_, value: string) => { | |
146 | + if (String(value).length > 500) { | |
147 | + return Promise.reject('备注不超过500字'); | |
148 | + } | |
149 | + return Promise.resolve(); | |
150 | + }, | |
151 | + validateTrigger: 'blur', | |
152 | + }, | |
153 | +]; | |
154 | +export const DeviceIdMaxLength: Rule[] = [ | |
155 | + { | |
156 | + required: true, | |
157 | + validator: (_, value: string) => { | |
158 | + if (String(value).length > 36) { | |
159 | + return Promise.reject('id不超过36字'); | |
160 | + } | |
161 | + return Promise.resolve(); | |
162 | + }, | |
163 | + validateTrigger: 'blur', | |
164 | + }, | |
165 | +]; | |
166 | + | |
167 | +export const DeviceTenantIdMaxLength: Rule[] = [ | |
168 | + { | |
169 | + required: true, | |
170 | + validator: (_, value: string) => { | |
171 | + if (String(value).length > 36) { | |
172 | + return Promise.reject('租户Code不超过36字'); | |
173 | + } | |
174 | + return Promise.resolve(); | |
175 | + }, | |
176 | + validateTrigger: 'blur', | |
177 | + }, | |
178 | +]; | |
179 | + | |
180 | +export const DeviceTbDeviceIdMaxLength: Rule[] = [ | |
181 | + { | |
182 | + required: true, | |
183 | + validator: (_, value: string) => { | |
184 | + if (String(value).length > 36) { | |
185 | + return Promise.reject('tbDeviceId不超过36字'); | |
186 | + } | |
187 | + return Promise.resolve(); | |
188 | + }, | |
189 | + validateTrigger: 'blur', | |
190 | + }, | |
191 | +]; | |
192 | + | |
193 | +export const DeviceUserNameMaxLength: Rule[] = [ | |
194 | + { | |
195 | + required: true, | |
196 | + validator: (_, value: string) => { | |
197 | + if (String(value).length > 50) { | |
198 | + return Promise.reject('用户名长度不超过50字'); | |
199 | + } | |
200 | + return Promise.resolve(); | |
201 | + }, | |
202 | + validateTrigger: 'blur', | |
203 | + }, | |
204 | +]; | |
205 | + | |
206 | +export const DeviceQueryUserNameMaxLength: Rule[] = [ | |
207 | + { | |
208 | + required: true, | |
209 | + validator: (_, value: string) => { | |
210 | + if (String(value).length > 50) { | |
211 | + return Promise.reject('设备名称长度不超过50字'); | |
212 | + } | |
213 | + return Promise.resolve(); | |
214 | + }, | |
215 | + validateTrigger: 'blur', | |
216 | + }, | |
217 | +]; | |
218 | + | |
219 | +export const DeviceProfileQueryUserNameMaxLength: Rule[] = [ | |
220 | + { | |
221 | + required: true, | |
222 | + validator: (_, value: string) => { | |
223 | + if (String(value).length > 255) { | |
224 | + return Promise.reject('配置名称长度不超过255字'); | |
225 | + } | |
226 | + return Promise.resolve(); | |
227 | + }, | |
228 | + validateTrigger: 'blur', | |
229 | + }, | |
230 | +]; | ... | ... |
... | ... | @@ -33,6 +33,23 @@ export const alarmSearchSchemas: FormSchema[] = [ |
33 | 33 | label: '告警类型', |
34 | 34 | component: 'Input', |
35 | 35 | colProps: { span: 6 }, |
36 | + componentProps: { | |
37 | + maxLength: 255, | |
38 | + placeholder: '请输入告警类型', | |
39 | + }, | |
40 | + dynamicRules: () => { | |
41 | + return [ | |
42 | + { | |
43 | + required: false, | |
44 | + validator: (_, value) => { | |
45 | + if (String(value).length > 255) { | |
46 | + return Promise.reject('字数不超过255个字'); | |
47 | + } | |
48 | + return Promise.resolve(); | |
49 | + }, | |
50 | + }, | |
51 | + ]; | |
52 | + }, | |
36 | 53 | }, |
37 | 54 | { |
38 | 55 | field: 'endTime', | ... | ... |
... | ... | @@ -34,8 +34,16 @@ |
34 | 34 | :canFullscreen="false" |
35 | 35 | > |
36 | 36 | <BasicForm @register="registerForm" /> |
37 | - <div ref="chartRef" :style="{ height: '600px', width }"></div> | |
37 | + <Alert | |
38 | + v-if="!isNull" | |
39 | + message="当前时间节点暂无历史数据" | |
40 | + description="请尝试选择其他时间段查询历史数据" | |
41 | + type="warning" | |
42 | + show-icon | |
43 | + /> | |
44 | + <div v-show="isNull" ref="chartRef" :style="{ height: '600px', width }"></div> | |
38 | 45 | </BasicModal> |
46 | + <DeviceDetailDrawer @register="registerDetailDrawer" /> | |
39 | 47 | </div> |
40 | 48 | </template> |
41 | 49 | <script lang="ts"> |
... | ... | @@ -44,22 +52,30 @@ |
44 | 52 | import { formSchema, columns } from './config.data'; |
45 | 53 | import { BasicTable, useTable } from '/@/components/Table'; |
46 | 54 | import { devicePage } from '/@/api/alarm/contact/alarmContact'; |
47 | - import { Tag } from 'ant-design-vue'; | |
55 | + import { Tag, Alert } from 'ant-design-vue'; | |
48 | 56 | import { DeviceState } from '/@/api/device/model/deviceModel'; |
49 | 57 | import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; |
50 | 58 | import { useModal, BasicModal } from '/@/components/Modal'; |
51 | 59 | import { BasicForm, useForm } from '/@/components/Form'; |
52 | 60 | import { schemas } from './config.data'; |
53 | 61 | import { useECharts } from '/@/hooks/web/useECharts'; |
54 | - import { getDeviceHistoryInfo, getDeviceDataKeys } from '/@/api/alarm/position'; | |
62 | + import { | |
63 | + getDeviceHistoryInfo, | |
64 | + getDeviceDataKeys, | |
65 | + getDeviceActiveTime, | |
66 | + } from '/@/api/alarm/position'; | |
67 | + import { useDrawer } from '/@/components/Drawer'; | |
68 | + import DeviceDetailDrawer from '/@/views/device/manage/cpns/modal/DeviceDetailDrawer.vue'; | |
55 | 69 | import moment from 'moment'; |
56 | 70 | export default defineComponent({ |
57 | 71 | name: 'BaiduMap', |
58 | 72 | components: { |
59 | 73 | BasicTable, |
60 | 74 | Tag, |
75 | + Alert, | |
61 | 76 | BasicModal, |
62 | 77 | BasicForm, |
78 | + DeviceDetailDrawer, | |
63 | 79 | }, |
64 | 80 | props: { |
65 | 81 | width: { |
... | ... | @@ -74,7 +90,10 @@ |
74 | 90 | setup() { |
75 | 91 | const wrapRef = ref<HTMLDivElement | null>(null); |
76 | 92 | const { toPromise } = useScript({ src: BAI_DU_MAP_URL }); |
77 | - const entityId = ref(''); | |
93 | + const [registerDetailDrawer, { openDrawer }] = useDrawer(); | |
94 | + | |
95 | + let entityId = ''; | |
96 | + let globalRecord: any = {}; | |
78 | 97 | async function initMap() { |
79 | 98 | await toPromise(); |
80 | 99 | await nextTick(); |
... | ... | @@ -101,13 +120,14 @@ |
101 | 120 | }, |
102 | 121 | }); |
103 | 122 | // 点击表格某一行触发 |
104 | - const deviceRowClick = (record) => { | |
105 | - entityId.value = record.tbDeviceId; | |
123 | + const deviceRowClick = async (record) => { | |
124 | + entityId = record.tbDeviceId; | |
125 | + globalRecord = record; | |
106 | 126 | const BMap = (window as any).BMap; |
107 | 127 | const wrapEl = unref(wrapRef); |
108 | 128 | const map = new BMap.Map(wrapEl); |
109 | 129 | if (record.deviceInfo.address) { |
110 | - const { name, organizationDTO, updateTime, deviceState, deviceProfile } = record; | |
130 | + const { name, organizationDTO, deviceState, deviceProfile } = record; | |
111 | 131 | const { longitude, latitude, address } = record.deviceInfo; |
112 | 132 | const point = new BMap.Point(longitude, latitude); |
113 | 133 | let options = { |
... | ... | @@ -117,6 +137,10 @@ |
117 | 137 | map.centerAndZoom(point, 15); |
118 | 138 | map.enableScrollWheelZoom(true); |
119 | 139 | // 创建信息窗口对象 |
140 | + const res = await getDeviceActiveTime(entityId); | |
141 | + | |
142 | + let { value: activeStatus, lastUpdateTs } = res[0]; | |
143 | + lastUpdateTs = moment(lastUpdateTs).format('YYYY-MM-DD HH:mm:ss'); | |
120 | 144 | let infoWindow = new BMap.InfoWindow( |
121 | 145 | ` |
122 | 146 | <div style="display:flex;justify-content:space-between; margin:20px 0px;"> |
... | ... | @@ -132,10 +156,9 @@ |
132 | 156 | <div>所属组织:${organizationDTO.name}</div> |
133 | 157 | <div style="margin-top:6px;">接入协议:${deviceProfile.transportType}</div> |
134 | 158 | <div style="margin-top:6px;">设备位置:${address}</div> |
135 | - <div style="margin-top:6px;">下线时间:${updateTime}</div> | |
136 | - <div style="display:flex;justify-content:space-between; margin-top:10px"> | |
137 | - <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">设备信息</button> | |
138 | - <button style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">报警记录</button> | |
159 | + <div style="margin-top:6px;">${activeStatus ? '在' : '离'}线时间:${lastUpdateTs}</div> | |
160 | + <div style="display:flex;justify-content:end; margin-top:10px"> | |
161 | + <button onclick="openDeviceInfoDrawer()" style="margin-right:10px;color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">设备信息</button> | |
139 | 162 | <button onclick="openHistoryModal()" style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">历史数据</button> |
140 | 163 | </div> |
141 | 164 | `, |
... | ... | @@ -185,13 +208,20 @@ |
185 | 208 | endTs = Date.now(); |
186 | 209 | // 发送请求 |
187 | 210 | const res = await getDeviceHistoryInfo({ |
188 | - entityId: entityId.value, | |
211 | + entityId, | |
189 | 212 | keys: keys.join(), |
190 | 213 | startTs, |
191 | 214 | endTs, |
192 | 215 | interval, |
193 | 216 | agg, |
194 | 217 | }); |
218 | + // 判断对象是否为空 | |
219 | + if (Object.keys(res).length === 0) { | |
220 | + isNull.value = false; | |
221 | + return; | |
222 | + } else { | |
223 | + isNull.value = true; | |
224 | + } | |
195 | 225 | // 处理数据 |
196 | 226 | for (const key in res) { |
197 | 227 | for (const item1 of res[key]) { |
... | ... | @@ -250,24 +280,38 @@ |
250 | 280 | |
251 | 281 | const chartRef = ref<HTMLDivElement | null>(null); |
252 | 282 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
253 | - | |
283 | + const isNull = ref(true); | |
284 | + // 设备信息 | |
285 | + const openDeviceInfoDrawer = async () => { | |
286 | + const { id, tbDeviceId } = globalRecord; | |
287 | + openDrawer(true, { | |
288 | + id, | |
289 | + tbDeviceId, | |
290 | + }); | |
291 | + }; | |
254 | 292 | const openHistoryModal = async () => { |
255 | 293 | openModal(true); |
256 | - | |
257 | 294 | // 收集参数 |
258 | 295 | const dataArray: any[] = []; |
259 | 296 | const startTs = Date.now() - 86400000; //最近一天 |
260 | 297 | const endTs = Date.now(); |
261 | 298 | // 发送请求 |
262 | - keys = await getDeviceDataKeys(entityId.value); | |
299 | + keys = await getDeviceDataKeys(entityId); | |
263 | 300 | const res = await getDeviceHistoryInfo({ |
264 | - entityId: entityId.value, | |
301 | + entityId, | |
265 | 302 | keys: keys.join(), |
266 | 303 | startTs, |
267 | 304 | endTs, |
268 | 305 | interval: 7200000, //间隔两小时 |
269 | 306 | agg: 'AVG', |
270 | 307 | }); |
308 | + // 判断对象是否为空 | |
309 | + if (Object.keys(res).length === 0) { | |
310 | + isNull.value = false; | |
311 | + return; | |
312 | + } else { | |
313 | + isNull.value = true; | |
314 | + } | |
271 | 315 | // 处理数据 |
272 | 316 | for (const key in res) { |
273 | 317 | for (const item1 of res[key]) { |
... | ... | @@ -327,12 +371,14 @@ |
327 | 371 | agg: 'AVG', |
328 | 372 | }); |
329 | 373 | }; |
374 | + | |
330 | 375 | const cancelHistoryModal = () => { |
331 | 376 | resetFields(); |
332 | 377 | setOptions({}); |
333 | 378 | }; |
334 | 379 | onMounted(() => { |
335 | 380 | initMap(); |
381 | + (window as any).openDeviceInfoDrawer = openDeviceInfoDrawer; | |
336 | 382 | (window as any).openHistoryModal = openHistoryModal; |
337 | 383 | }); |
338 | 384 | return { |
... | ... | @@ -343,7 +389,9 @@ |
343 | 389 | registerModal, |
344 | 390 | registerForm, |
345 | 391 | chartRef, |
392 | + isNull, | |
346 | 393 | cancelHistoryModal, |
394 | + registerDetailDrawer, | |
347 | 395 | }; |
348 | 396 | }, |
349 | 397 | }); | ... | ... |
... | ... | @@ -56,6 +56,7 @@ export const searchFormSchema: FormSchema[] = [ |
56 | 56 | component: 'Input', |
57 | 57 | colProps: { span: 6 }, |
58 | 58 | componentProps: { |
59 | + maxLength: 36, | |
59 | 60 | placeholder: '请输入联系人姓名', |
60 | 61 | }, |
61 | 62 | }, |
... | ... | @@ -70,6 +71,7 @@ export const formSchema: FormSchema[] = [ |
70 | 71 | component: 'Input', |
71 | 72 | componentProps: { |
72 | 73 | placeholder: '请输入联系人姓名', |
74 | + maxLength: 255, | |
73 | 75 | }, |
74 | 76 | }, |
75 | 77 | { |
... | ... | @@ -108,6 +110,7 @@ export const formSchema: FormSchema[] = [ |
108 | 110 | component: 'Input', |
109 | 111 | componentProps: { |
110 | 112 | placeholder: '请输入微信号', |
113 | + maxLength: 255, | |
111 | 114 | }, |
112 | 115 | }, |
113 | 116 | { |
... | ... | @@ -115,7 +118,8 @@ export const formSchema: FormSchema[] = [ |
115 | 118 | label: '备注', |
116 | 119 | component: 'InputTextArea', |
117 | 120 | componentProps: { |
118 | - placeholder: '', | |
121 | + placeholder: '请输入备注', | |
122 | + maxLength: 255, | |
119 | 123 | }, |
120 | 124 | }, |
121 | 125 | { |
... | ... | @@ -123,5 +127,8 @@ export const formSchema: FormSchema[] = [ |
123 | 127 | label: '', |
124 | 128 | component: 'Input', |
125 | 129 | show: false, |
130 | + componentProps: { | |
131 | + maxLength: 36, | |
132 | + }, | |
126 | 133 | }, |
127 | 134 | ]; | ... | ... |
1 | +<template> | |
2 | + 123 | |
3 | + <div ref="chartRef" :style="{ height, width }"></div> | |
4 | +</template> | |
5 | +<script lang="ts" setup> | |
6 | + import { ref, Ref, withDefaults } from 'vue'; | |
7 | + import { useECharts } from '/@/hooks/web/useECharts'; | |
8 | + | |
9 | + interface Props { | |
10 | + width?: string; | |
11 | + height?: string; | |
12 | + } | |
13 | + withDefaults(defineProps<Props>(), { | |
14 | + width: '100%', | |
15 | + height: '280px', | |
16 | + }); | |
17 | + | |
18 | + const chartRef = ref<HTMLDivElement | null>(null); | |
19 | + const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); | |
20 | +</script> | ... | ... |
1 | 1 | <template> |
2 | - <div class="md:flex justify-between"> | |
3 | - <template v-for="(item, index) in growCardList" :key="item.title"> | |
4 | - <div | |
5 | - class="growCardItem md:w-1/3 w-full !md:mt-0 !mt-4 bg-white" | |
6 | - :class="index === 0 ? '!md:ml-0' : '!md:ml-4'" | |
2 | + <div class="md:flex"> | |
3 | + <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4"> | |
4 | + <div class="flex" style="height: 100px"> | |
5 | + <div class="mr-4" | |
6 | + ><img src="/src/assets/images/device-count.png" style="width: 5rem; height: 5rem" | |
7 | + /></div> | |
8 | + <div class="flex-auto"> | |
9 | + <div class="flex justify-between" style="align-items: center"> | |
10 | + <div style="font-size: 1.625rem; color: #333">{{ | |
11 | + growCardList?.deviceInfo?.sumCount | |
12 | + }}</div> | |
13 | + <img src="/src/assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | |
14 | + </div> | |
15 | + <div> 设备数(个) </div> | |
16 | + <div class="flex mt-2"> | |
17 | + <div class="flex mr-1" style="align-items: center; font-size: 0.75rem" | |
18 | + ><img src="/src/assets/images/online.png" class="mr-1" /> | |
19 | + <span>在线{{ growCardList?.deviceInfo?.onLine }}</span> | |
20 | + </div> | |
21 | + <div class="flex mr-1" style="align-items: center; font-size: 0.75rem"> | |
22 | + <img src="/src/assets/images/offline.png" class="mr-1" /> | |
23 | + <span> 离线{{ growCardList?.deviceInfo?.offLine }} </span> | |
24 | + </div> | |
25 | + <div class="flex mr-1" style="align-items: center; font-size: 0.75rem"> | |
26 | + <img src="/src/assets/images/inactive.png" class="mr-1" /> | |
27 | + <span> 未激活{{ growCardList?.deviceInfo?.inActive }} </span> | |
28 | + </div> | |
29 | + </div> | |
30 | + </div> | |
31 | + </div> | |
32 | + <div class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5"> | |
33 | + 今日新增 {{ growCardList?.deviceInfo?.todayAdd }}</div | |
34 | + > | |
35 | + </Card> | |
36 | + <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4"> | |
37 | + <div class="flex" style="height: 100px"> | |
38 | + <div class="mr-4"> | |
39 | + <img | |
40 | + v-if="!isAdmin(role)" | |
41 | + src="/src/assets/images/alarm-count.png" | |
42 | + style="width: 5rem; height: 5rem" | |
43 | + /> | |
44 | + <img v-else src="/src/assets/images/zh.png" style="width: 5rem; height: 5rem" /> | |
45 | + </div> | |
46 | + <div class="flex-auto"> | |
47 | + <div class="flex justify-between" style="align-items: center"> | |
48 | + <div v-if="!isAdmin(role)" style="font-size: 1.625rem; color: #333">{{ | |
49 | + growCardList?.alarmInfo?.sumCount | |
50 | + }}</div> | |
51 | + <div style="font-size: 1.625rem; color: #333">{{ | |
52 | + growCardList?.tenantInfo?.sumCount | |
53 | + }}</div> | |
54 | + <img src="/src/assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | |
55 | + </div> | |
56 | + <div> {{ !isAdmin(role) ? `${currentMonth}月告警数(条)` : '租户总量(个)' }}</div> | |
57 | + </div> | |
58 | + </div> | |
59 | + <div v-if="!isAdmin(role)" class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5"> | |
60 | + 今日新增 {{ growCardList?.alarmInfo?.todayAdd }}</div | |
61 | + > | |
62 | + <div v-else class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5"> | |
63 | + 今日新增 {{ growCardList?.tenantInfo?.todayAdd }}</div | |
7 | 64 | > |
8 | - <div | |
9 | - class=" | |
10 | - growCardItem-top | |
11 | - border border-solid border-t-0 border-r-0 border-l-0 border-b-1 | |
12 | - dark:border-#ccc | |
13 | - light:border-#F2F2F5 | |
14 | - " | |
15 | - > | |
16 | - <img :src="item.imgUrl" style="width: 5rem; height: 5rem" /> | |
17 | - <div class="growCardItem-right"> | |
18 | - <div class="flex justify-between ml-3"> | |
19 | - <div style="font-size: 1.625rem; color: #333">{{ item.value }}</div> | |
20 | - <img src="../../../../assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | |
65 | + </Card> | |
66 | + <Card size="small" class="md:w-1/3 w-full !md:mt-0 !mt-4"> | |
67 | + <div class="flex" style="height: 100px"> | |
68 | + <div class="mr-4" | |
69 | + ><img | |
70 | + v-if="!isAdmin(role)" | |
71 | + src="/src/assets/images/msg-count.png" | |
72 | + style="width: 5rem; height: 5rem" | |
73 | + /><img v-else src="/src/assets/images/kf.png" style="width: 5rem; height: 5rem" /> | |
74 | + </div> | |
75 | + <div v-if="!isAdmin(role)" style="display: flex; align-items: center"> | |
76 | + <div> | |
77 | + <div class="flex" style="align-items: center"> | |
78 | + {{ `${currentMonth}月数据点(条)` }} | |
79 | + <span style="font-size: 1.625rem; color: #333"> | |
80 | + {{ growCardList?.messageInfo?.dataPointsCount }}</span | |
81 | + > | |
21 | 82 | </div> |
22 | - <div class="ml-3">{{ item.title }}</div> | |
23 | - <div class="ml-1.5 mt-3 flex flex-nowrap" style="width: 15rem" v-if="item.offLine"> | |
24 | - <div class="count"> | |
25 | - <img | |
26 | - src="../../../../assets/images/online.png" | |
27 | - style="width: 0.6rem; height: 0.6rem" | |
28 | - class="mr-1" | |
29 | - /> | |
30 | - 在线 {{ item.onLine }} | |
31 | - </div> | |
32 | - <div class="count"> | |
33 | - <img | |
34 | - src="../../../../assets/images/offline.png" | |
35 | - style="width: 0.6rem; height: 0.6rem" | |
36 | - class="mr-1" | |
37 | - /> | |
38 | - 离线 {{ item.offLine }} | |
39 | - </div> | |
40 | - <div class="count"> | |
41 | - <img | |
42 | - src="../../../../assets/images/inactive.png" | |
43 | - style="width: 0.6rem; height: 0.6rem" | |
44 | - class="mr-1" | |
45 | - /> | |
46 | - 未激活 {{ item.inactive }} | |
47 | - </div> | |
83 | + <div class="flex" style="align-items: center"> | |
84 | + {{ `${currentMonth}月消息量(条)` }} | |
85 | + <span style="font-size: 1.625rem; color: #333"> | |
86 | + {{ growCardList?.messageInfo?.messageCount }}</span | |
87 | + > | |
48 | 88 | </div> |
49 | 89 | </div> |
50 | 90 | </div> |
51 | - <div class="growCardItem-bottom"> 今日新增 {{ item.newDay }}</div> | |
91 | + <div class="flex-auto" v-else> | |
92 | + <div class="flex justify-between" style="align-items: center"> | |
93 | + <div style="font-size: 1.625rem; color: #333">{{ | |
94 | + growCardList?.customerInfo?.sumCount | |
95 | + }}</div> | |
96 | + <img src="/src/assets/images/tip.png" style="width: 1.4rem; height: 1.4rem" /> | |
97 | + </div> | |
98 | + <div>客户总量(个)</div> | |
99 | + </div> | |
100 | + </div> | |
101 | + <div v-if="!isAdmin(role)" class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5"> | |
102 | + 今日新增 | |
103 | + <span class="ml-8">数据点 ({{ growCardList?.messageInfo?.todayDataPointsAdd }})</span> | |
104 | + <span class="ml-8">消息量 ({{ growCardList?.messageInfo?.todayMessageAdd }})</span> | |
52 | 105 | </div> |
53 | - </template> | |
106 | + <div v-else class="ml-2 pt-4" style="border-top: 2px solid #f0f2f5"> | |
107 | + 今日新增 {{ growCardList?.customerInfo?.todayAdd }}</div | |
108 | + > | |
109 | + </Card> | |
54 | 110 | </div> |
55 | 111 | </template> |
56 | 112 | <script lang="ts" setup> |
57 | - import { growCardList } from '../data'; | |
58 | -</script> | |
59 | - | |
60 | -<style scoped lang="less"> | |
61 | - .growCardItem { | |
62 | - height: 11.187rem; | |
63 | - color: #666; | |
64 | - .growCardItem-top { | |
65 | - display: flex; | |
66 | - margin: 1.25rem; | |
67 | - padding-bottom: 0.625rem; | |
68 | - .growCardItem-right { | |
69 | - width: 18.75rem; | |
70 | - .count { | |
71 | - display: flex; | |
72 | - font-size: 0.75rem; | |
73 | - align-items: center; | |
74 | - margin-left: 0.5rem; | |
75 | - } | |
76 | - } | |
77 | - } | |
78 | - .growCardItem-bottom { | |
79 | - margin-left: 1.25rem; | |
80 | - } | |
113 | + import { ref, onMounted, computed } from 'vue'; | |
114 | + import { Card } from 'ant-design-vue'; | |
115 | + import { getHomeData } from '/@/api/dashboard'; | |
116 | + import { isAdmin } from '/@/enums/roleEnum'; | |
117 | + defineProps<{ | |
118 | + role: string; | |
119 | + }>(); | |
120 | + defineExpose({ | |
121 | + isAdmin, | |
122 | + }); | |
123 | + interface CardList { | |
124 | + deviceInfo: { | |
125 | + sumCount: number; | |
126 | + onLine: number; | |
127 | + offLine: number; | |
128 | + inActive: number; | |
129 | + todayAdd: number; | |
130 | + }; | |
131 | + tenantInfo?: { sumCount: number; todayAdd: number }; | |
132 | + customerInfo?: { sumCount: number; todayAdd: number }; | |
133 | + alarmInfo?: { | |
134 | + sumCount: number; | |
135 | + todayAdd: number; | |
136 | + }; | |
137 | + messageInfo?: { | |
138 | + dataPointsCount: number; | |
139 | + messageCount: number; | |
140 | + todayDataPointsAdd: number; | |
141 | + todayMessageAdd: number; | |
142 | + }; | |
81 | 143 | } |
82 | -</style> | |
144 | + const growCardList = ref<CardList>(); | |
145 | + onMounted(async () => { | |
146 | + const res = await getHomeData(); | |
147 | + growCardList.value = res; | |
148 | + }); | |
149 | + // 获取当前月份0-11 +1 | |
150 | + const currentMonth = computed(() => { | |
151 | + return new Date().getMonth() + 1; | |
152 | + }); | |
153 | +</script> | ... | ... |
1 | 1 | <template> |
2 | - <Card title="帮助文档"> | |
3 | - <div> | |
4 | - <template v-for="item in helpDoc" :key="item.title"> | |
5 | - <AnchorLink v-bind="item" /> | |
6 | - </template> | |
7 | - </div> | |
8 | - <Card | |
9 | - :tab-list="tabListTitle" | |
10 | - v-bind="$attrs" | |
11 | - :active-tab-key="activeKey" | |
12 | - :bordered="false" | |
13 | - @tabChange="onTabChange" | |
14 | - :bodyStyle="{ padding: 0 }" | |
15 | - > | |
16 | - <div v-if="activeKey === 'tab1'"> | |
17 | - <List item-layout="horizontal" :dataSource="dataSource"> | |
18 | - <template #renderItem="{ item }"> | |
19 | - <ListItem> | |
20 | - <ListItemMeta> | |
21 | - <template #avatar> | |
22 | - <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" /> | |
23 | - </template> | |
24 | - <template #description> | |
25 | - <span | |
26 | - @click="go('/stationnotification/mynotification')" | |
27 | - class="cursor-pointer noticeTitle" | |
28 | - >{{ item.sysNotice.title }} | |
29 | - </span> | |
30 | - </template> | |
31 | - <template #title> | |
32 | - <span>{{ item.user.realName }}</span> | |
2 | + <div> | |
3 | + <Card title="帮助文档" v-if="!isAdmin(role)"> | |
4 | + <div> | |
5 | + <template v-for="item in helpDoc" :key="item.title"> | |
6 | + <AnchorLink v-bind="item" /> | |
7 | + </template> | |
8 | + </div> | |
9 | + <Card | |
10 | + v-if="!isAdmin(role)" | |
11 | + :tab-list="tabListTitle" | |
12 | + v-bind="$attrs" | |
13 | + :active-tab-key="activeKey" | |
14 | + :bordered="false" | |
15 | + @tabChange="onTabChange" | |
16 | + :bodyStyle="{ padding: 0 }" | |
17 | + > | |
18 | + <div v-if="activeKey === 'tab1'"> | |
19 | + <List item-layout="horizontal" :dataSource="dataSource"> | |
20 | + <template #renderItem="{ item }"> | |
21 | + <ListItem> | |
22 | + <ListItemMeta> | |
23 | + <template #avatar> | |
24 | + <Avatar | |
25 | + src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" | |
26 | + /> | |
27 | + </template> | |
28 | + <template #description> | |
29 | + <span | |
30 | + class="cursor-pointer noticeTitle" | |
31 | + @click="go('/stationnotification/mynotification')" | |
32 | + >{{ item.sysNotice.title }} | |
33 | + </span> | |
34 | + </template> | |
35 | + <template #title> | |
36 | + <span>{{ item.user.realName }}</span> | |
37 | + </template> | |
38 | + </ListItemMeta> | |
39 | + <template #extra> | |
40 | + <Time :value="item.sysNotice.senderDate" /> | |
33 | 41 | </template> |
34 | - </ListItemMeta> | |
35 | - <template #extra> | |
36 | - <Time :value="item.sysNotice.senderDate" /> | |
37 | - </template> | |
38 | - </ListItem> | |
39 | - </template> | |
40 | - </List> | |
41 | - <Card hoverable title="联系我们" :bordered="false"> | |
42 | - <template #cover> | |
43 | - <img :src="getQrCode" alt="" style="width: 150px; height: 150px; margin: 50px auto" /> | |
44 | - </template> | |
45 | - <CardMeta> | |
46 | - <template #description> | |
47 | - <p>联系人: {{ getContacts }}</p> | |
48 | - <p>联系电话: {{ getTel }}</p> | |
49 | - <p>联系地址: {{ getAddress }} </p> | |
42 | + </ListItem> | |
50 | 43 | </template> |
51 | - </CardMeta> | |
52 | - </Card> | |
53 | - </div> | |
44 | + </List> | |
45 | + <Card hoverable title="联系我们" :bordered="false"> | |
46 | + <template #cover> | |
47 | + <img :src="getQrCode" alt="" style="width: 150px; height: 150px; margin: 50px auto" /> | |
48 | + </template> | |
49 | + <CardMeta> | |
50 | + <template #description> | |
51 | + <p>联系人: {{ getContacts }}</p> | |
52 | + <p>联系电话: {{ getTel }}</p> | |
53 | + <p>联系地址: {{ getAddress }} </p> | |
54 | + </template> | |
55 | + </CardMeta> | |
56 | + </Card> | |
57 | + </div> | |
58 | + </Card> | |
59 | + </Card> | |
60 | + | |
61 | + <Card v-if="isAdmin(role)"> | |
62 | + <Descriptions title="租户消息量TOP10" :column="1"> | |
63 | + <template v-for="(item, index) in 10" :key="index"> | |
64 | + <DescriptionsItem> | |
65 | + <span | |
66 | + class="mr-2" | |
67 | + style=" | |
68 | + width: 1.25rem; | |
69 | + height: 1.25rem; | |
70 | + border: 1px solid; | |
71 | + color: #0b55f1; | |
72 | + border-radius: 50%; | |
73 | + display: flex; | |
74 | + align-items: center; | |
75 | + justify-content: center; | |
76 | + " | |
77 | + :style="{ | |
78 | + color: | |
79 | + index === 0 | |
80 | + ? '#f0a16e' | |
81 | + : index === 1 | |
82 | + ? '#868585' | |
83 | + : index === 2 | |
84 | + ? '#e78739' | |
85 | + : '#4e84f5', | |
86 | + backgroundColor: | |
87 | + index === 0 ? '#fed36a' : index === 1 ? '#CBCAC9' : index === 2 ? '#F1B889' : '', | |
88 | + borderColor: | |
89 | + index === 0 | |
90 | + ? '#fdee7d' | |
91 | + : index === 1 | |
92 | + ? '#e6e6e5' | |
93 | + : index === 2 | |
94 | + ? '#f8c296' | |
95 | + : '#0b55f1;', | |
96 | + }" | |
97 | + >{{ index + 1 }}</span | |
98 | + >兰州天兆猪业</DescriptionsItem | |
99 | + > | |
100 | + </template> | |
101 | + </Descriptions> | |
102 | + </Card> | |
103 | + <Card v-if="isAdmin(role)"> | |
104 | + <BasicTable @register="registerTable" /> | |
54 | 105 | </Card> |
55 | - </Card> | |
106 | + </div> | |
56 | 107 | </template> |
57 | 108 | |
58 | 109 | <script lang="ts"> |
59 | 110 | import { defineComponent, ref, computed, onMounted } from 'vue'; |
60 | - import { Card, AnchorLink, List, ListItem, ListItemMeta, Avatar, CardMeta } from 'ant-design-vue'; | |
111 | + import { Card, Anchor, List, Avatar, Descriptions } from 'ant-design-vue'; | |
61 | 112 | import { useUserStore } from '/@/store/modules/user'; |
62 | 113 | import { getEnterPriseDetail } from '/@/api/oem'; |
63 | 114 | import { notifyMyGetrPageApi } from '/@/api/stationnotification/stationnotifyApi'; |
64 | 115 | import { Time } from '/@/components/Time'; |
65 | 116 | import { useGo } from '/@/hooks/web/usePage'; |
117 | + import { BasicTable, useTable } from '/@/components/Table'; | |
118 | + import { columns } from './props'; | |
119 | + import { isAdmin } from '/@/enums/roleEnum'; | |
120 | + import { getTenantExpireTimeList } from '/@/api/dashboard'; | |
66 | 121 | export default defineComponent({ |
67 | 122 | components: { |
68 | 123 | Card, |
69 | - AnchorLink, | |
124 | + CardMeta: Card.Meta, | |
125 | + AnchorLink: Anchor.Link, | |
70 | 126 | List, |
71 | - ListItem, | |
72 | - ListItemMeta, | |
127 | + ListItem: List.Item, | |
128 | + ListItemMeta: List.Item.Meta, | |
129 | + Descriptions, | |
130 | + DescriptionsItem: Descriptions.Item, | |
73 | 131 | Avatar, |
74 | 132 | Time, |
75 | - CardMeta, | |
133 | + BasicTable, | |
76 | 134 | }, |
77 | - setup() { | |
78 | - onMounted(async () => { | |
79 | - const res = await getEnterPriseDetail(); | |
80 | - userStore.setEnterPriseInfo(res); | |
81 | - }); | |
135 | + props: { | |
136 | + role: { | |
137 | + type: String, | |
138 | + required: true, | |
139 | + }, | |
140 | + }, | |
141 | + setup(props) { | |
142 | + // 通知数据 | |
143 | + const dataSource = ref([]); | |
144 | + const go = useGo(); | |
145 | + | |
82 | 146 | const helpDoc = ref([ |
83 | 147 | { |
84 | 148 | title: '如何接入设备?', |
... | ... | @@ -109,6 +173,18 @@ |
109 | 173 | activeKey.value = key; |
110 | 174 | }; |
111 | 175 | |
176 | + const [registerTable, { redoHeight }] = useTable({ | |
177 | + api: getTenantExpireTimeList, | |
178 | + title: '本月即将过期租户', | |
179 | + showIndexColumn: false, | |
180 | + useSearchForm: false, | |
181 | + columns, | |
182 | + fetchSetting: { | |
183 | + listField: 'expireTenant.items', | |
184 | + totalField: 'expireTenant.total', | |
185 | + }, | |
186 | + }); | |
187 | + | |
112 | 188 | const userStore = useUserStore(); |
113 | 189 | const getContacts = computed(() => { |
114 | 190 | return userStore.enterPriseInfo?.contacts; |
... | ... | @@ -122,32 +198,35 @@ |
122 | 198 | const getQrCode = computed(() => { |
123 | 199 | return userStore.enterPriseInfo?.qrCode; |
124 | 200 | }); |
125 | - | |
126 | - // 通知数据 | |
127 | - const dataSource = ref([]); | |
128 | - const go = useGo(); | |
129 | 201 | onMounted(async () => { |
130 | - const res = await notifyMyGetrPageApi({ page: 1, pageSize: 5 }); | |
131 | - dataSource.value = res.items; | |
202 | + if (isAdmin(props.role)) return; | |
203 | + | |
204 | + const res = await getEnterPriseDetail(); | |
205 | + const notice = await notifyMyGetrPageApi({ page: 1, pageSize: 5 }); | |
206 | + userStore.setEnterPriseInfo(res); | |
207 | + dataSource.value = notice.items; | |
132 | 208 | }); |
133 | 209 | |
134 | 210 | return { |
135 | 211 | activeKey, |
136 | 212 | tabListTitle, |
137 | - onTabChange, | |
138 | 213 | helpDoc, |
139 | 214 | getQrCode, |
140 | 215 | getContacts, |
141 | 216 | getAddress, |
142 | 217 | getTel, |
143 | 218 | dataSource, |
219 | + onTabChange, | |
144 | 220 | go, |
221 | + registerTable, | |
222 | + isAdmin, | |
223 | + redoHeight, | |
145 | 224 | }; |
146 | 225 | }, |
147 | 226 | }); |
148 | 227 | </script> |
149 | 228 | |
150 | -<style lang="less" scoped> | |
229 | +<style scoped> | |
151 | 230 | .noticeTitle:hover { |
152 | 231 | border-bottom: 1px solid #ccc; |
153 | 232 | } | ... | ... |
... | ... | @@ -4,59 +4,347 @@ |
4 | 4 | v-bind="$attrs" |
5 | 5 | :active-tab-key="activeKey" |
6 | 6 | @tabChange="onTabChange" |
7 | + v-if="!isAdmin(role)" | |
7 | 8 | > |
8 | 9 | <template #tabBarExtraContent> |
9 | 10 | <div class="extra-date"> |
10 | - <template v-for="(item, index) in dateList" :key="item"> | |
11 | - <span @click="changeDate(index)" :class="{ active: index === activeIndex }">{{ | |
12 | - item | |
13 | - }}</span> | |
11 | + <template v-for="(item, index) in dateList" :key="item.value"> | |
12 | + <span | |
13 | + @click="quickQueryDate(index, item.value)" | |
14 | + :class="{ active: index === activeIndex }" | |
15 | + >{{ item.label }}</span | |
16 | + > | |
14 | 17 | </template> |
15 | - <DatePicker @change="onDateChange" /> | |
18 | + <DatePicker @change="onDateChange" v-model:value="dateValue" /> | |
16 | 19 | </div> |
17 | 20 | </template> |
18 | - <div v-if="activeKey === 'tab1'"> | |
19 | - <p class="center">告警数</p> | |
20 | - <VisitAnalysis /> | |
21 | + <div v-show="activeKey === '1'"> | |
22 | + <!-- 折线图 --> | |
23 | + <VisitAnalysis :alarmList="state.alarmList" /> | |
21 | 24 | </div> |
22 | - <div v-else> | |
23 | - <p class="center">消息数</p> | |
24 | - <VisitAnalysisBar /> | |
25 | + <div v-show="activeKey === '2'"> | |
26 | + <!-- 柱形图 --> | |
27 | + <VisitAnalysisBar :dataPointList="state.dataPointList" :messageList="state.messageList" /> | |
25 | 28 | </div> |
26 | 29 | </Card> |
30 | + <Card v-bind="$attrs" v-if="isAdmin(role)" title="租户趋势"> | |
31 | + <TenantTrend /> | |
32 | + </Card> | |
33 | + <Card v-bind="$attrs" v-if="isAdmin(role)" title="客户趋势"> | |
34 | + <CustomerTrend /> | |
35 | + </Card> | |
27 | 36 | </template> |
28 | 37 | <script lang="ts" setup> |
29 | - import { ref } from 'vue'; | |
38 | + import { ref, reactive } from 'vue'; | |
30 | 39 | import { Card, DatePicker } from 'ant-design-vue'; |
31 | 40 | import VisitAnalysis from './VisitAnalysis.vue'; |
32 | 41 | import VisitAnalysisBar from './VisitAnalysisBar.vue'; |
33 | - | |
34 | - const activeKey = ref('tab1'); | |
35 | - | |
42 | + import { isAdmin } from '/@/enums/roleEnum'; | |
43 | + import { useWebSocket } from '@vueuse/core'; | |
44 | + import { getAuthCache } from '/@/utils/auth'; | |
45 | + import CustomerTrend from './CustomerTrend.vue'; | |
46 | + import TenantTrend from './TenantTrend.vue'; | |
47 | + import { JWT_TOKEN_KEY } from '/@/enums/cacheEnum'; | |
48 | + import { formatToDateTime } from '/@/utils/dateUtil'; | |
49 | + import { getEntitiesId } from '/@/api/dashboard/index'; | |
50 | + defineExpose({ | |
51 | + isAdmin, | |
52 | + }); | |
53 | + const props = defineProps<{ | |
54 | + role: string; | |
55 | + }>(); | |
56 | + const activeKey = ref('1'); | |
57 | + let entityId = null; | |
58 | + // 图表tab切换选项卡 | |
36 | 59 | const tabListTitle = [ |
37 | 60 | { |
38 | - key: 'tab1', | |
61 | + key: '1', | |
39 | 62 | tab: '告警数统计', |
40 | 63 | }, |
41 | 64 | { |
42 | - key: 'tab2', | |
65 | + key: '2', | |
43 | 66 | tab: '消息量统计', |
44 | 67 | }, |
45 | 68 | ]; |
46 | - const dateList = ref(['1小时', '1天', '7天', '30天']); | |
47 | - const activeIndex = ref(0); | |
48 | - function onTabChange(key) { | |
69 | + // 快速选择日期 | |
70 | + const activeIndex = ref(3); | |
71 | + const dateValue = ref(); | |
72 | + const dateList = ref([ | |
73 | + { label: '1小时', value: 3600000 }, | |
74 | + { label: '1天', value: 86400000 }, | |
75 | + { label: '7天', value: 604800000 }, | |
76 | + { label: '30天', value: 2592000000 }, | |
77 | + ]); | |
78 | + // web Socket | |
79 | + const token: string = getAuthCache(JWT_TOKEN_KEY); | |
80 | + const state = reactive({ | |
81 | + server: `${import.meta.env.VITE_WEB_SOCKET}${token}`, | |
82 | + alarmList: new Array<[number, string]>(), | |
83 | + alarmItem: new Array<[number, string]>(), | |
84 | + dataPointList: new Array<[number, string]>(), | |
85 | + messageList: new Array<[number, string]>(), | |
86 | + dataPoint: new Array<[number, string]>(), | |
87 | + MsgCount: new Array<[number, string]>(), | |
88 | + }); | |
89 | + const { send, close } = useWebSocket(state.server, { | |
90 | + async onConnected() { | |
91 | + if (isAdmin(props.role)) return; | |
92 | + const res = await getEntitiesId(); | |
93 | + entityId = res.data[0].entityId; | |
94 | + const sendValue = JSON.stringify({ | |
95 | + entityDataCmds: [ | |
96 | + { | |
97 | + query: { | |
98 | + entityFilter: { | |
99 | + type: 'singleEntity', | |
100 | + singleEntity: entityId, | |
101 | + }, | |
102 | + pageLink: { | |
103 | + pageSize: 1024, | |
104 | + page: 0, | |
105 | + sortOrder: { | |
106 | + key: { | |
107 | + type: 'ENTITY_FIELD', | |
108 | + key: 'createdTime', | |
109 | + }, | |
110 | + direction: 'DESC', | |
111 | + }, | |
112 | + }, | |
113 | + entityFields: [ | |
114 | + { | |
115 | + type: 'ENTITY_FIELD', | |
116 | + key: 'name', | |
117 | + }, | |
118 | + { | |
119 | + type: 'ENTITY_FIELD', | |
120 | + key: 'label', | |
121 | + }, | |
122 | + { | |
123 | + type: 'ENTITY_FIELD', | |
124 | + key: 'additionalInfo', | |
125 | + }, | |
126 | + ], | |
127 | + latestValues: [ | |
128 | + { | |
129 | + type: 'TIME_SERIES', | |
130 | + key: 'createdAlarmsCountHourly', | |
131 | + }, | |
132 | + ], | |
133 | + }, | |
134 | + cmdId: activeKey.value, | |
135 | + }, | |
136 | + ], | |
137 | + }); | |
138 | + const sendValue1 = JSON.stringify({ | |
139 | + entityDataCmds: [ | |
140 | + { | |
141 | + cmdId: activeKey.value, | |
142 | + historyCmd: { | |
143 | + keys: ['createdAlarmsCountHourly'], | |
144 | + startTs: Date.now() - 2592000000, | |
145 | + endTs: Date.now(), | |
146 | + interval: 86400000, | |
147 | + agg: 'COUNT', | |
148 | + }, | |
149 | + }, | |
150 | + ], | |
151 | + }); | |
152 | + send(sendValue); | |
153 | + send(sendValue1); | |
154 | + console.log('建立连接了'); | |
155 | + }, | |
156 | + onMessage(_, e) { | |
157 | + const { data, update } = JSON.parse(e.data); | |
158 | + console.log('来新消息了', data, update); | |
159 | + if (activeKey.value === '1') { | |
160 | + if (data) { | |
161 | + const { createdAlarmsCountHourly } = data.data[0].latest.TIME_SERIES; | |
162 | + state.alarmItem = [createdAlarmsCountHourly.ts, createdAlarmsCountHourly.value]; | |
163 | + state.alarmList.push([createdAlarmsCountHourly.ts, createdAlarmsCountHourly.value]); | |
164 | + } | |
165 | + if (update) { | |
166 | + const { createdAlarmsCountHourly } = update[0].timeseries; | |
167 | + const newArray: any = []; | |
168 | + for (const item of createdAlarmsCountHourly) { | |
169 | + newArray.push([item.ts, item.value]); | |
170 | + } | |
171 | + state.alarmList = newArray; | |
172 | + } | |
173 | + } else { | |
174 | + if (data) { | |
175 | + const { transportDataPointsCountHourly, transportMsgCountHourly } = | |
176 | + data.data[0].latest.TIME_SERIES; | |
177 | + state.dataPoint = [ | |
178 | + transportDataPointsCountHourly.ts, | |
179 | + transportDataPointsCountHourly.value, | |
180 | + ]; | |
181 | + state.MsgCount = [ | |
182 | + transportDataPointsCountHourly.ts, | |
183 | + transportDataPointsCountHourly.value, | |
184 | + ]; | |
185 | + state.dataPointList.push([ | |
186 | + transportDataPointsCountHourly.ts, | |
187 | + transportDataPointsCountHourly.value, | |
188 | + ]); | |
189 | + state.messageList.push([transportMsgCountHourly.ts, transportMsgCountHourly.value]); | |
190 | + } | |
191 | + if (update) { | |
192 | + const { transportDataPointsCountHourly, transportMsgCountHourly } = update[0].timeseries; | |
193 | + const newArray: any[] = []; | |
194 | + const newArray1: any[] = []; | |
195 | + for (const item of transportDataPointsCountHourly) { | |
196 | + newArray.push([item.ts, item.value]); | |
197 | + } | |
198 | + for (const item of transportMsgCountHourly) { | |
199 | + newArray1.push([item.ts, item.value]); | |
200 | + } | |
201 | + state.dataPointList = newArray; | |
202 | + state.messageList = newArray1; | |
203 | + } | |
204 | + } | |
205 | + }, | |
206 | + onDisconnected() { | |
207 | + console.log('断开连接了'); | |
208 | + close(); | |
209 | + }, | |
210 | + }); | |
211 | + | |
212 | + // 切换tab页 | |
213 | + function onTabChange(key: string) { | |
49 | 214 | activeKey.value = key; |
215 | + activeIndex.value = 3; | |
216 | + dateValue.value = ''; | |
217 | + const sendValue = JSON.stringify({ | |
218 | + entityDataCmds: [ | |
219 | + { | |
220 | + cmdId: activeKey.value, | |
221 | + historyCmd: { | |
222 | + keys: | |
223 | + activeKey.value === '1' | |
224 | + ? ['createdAlarmsCountHourly'] | |
225 | + : ['transportMsgCountHourly', 'transportDataPointsCountHourly'], | |
226 | + startTs: Date.now() - 2592000000, | |
227 | + endTs: Date.now(), | |
228 | + interval: 86400000, | |
229 | + agg: 'COUNT', | |
230 | + }, | |
231 | + }, | |
232 | + ], | |
233 | + }); | |
234 | + if (key === '2') { | |
235 | + const sendMessageValue = JSON.stringify({ | |
236 | + entityDataCmds: [ | |
237 | + { | |
238 | + query: { | |
239 | + entityFilter: { | |
240 | + type: 'singleEntity', | |
241 | + singleEntity: entityId, | |
242 | + }, | |
243 | + pageLink: { | |
244 | + pageSize: 1024, | |
245 | + page: 0, | |
246 | + sortOrder: { | |
247 | + key: { | |
248 | + type: 'ENTITY_FIELD', | |
249 | + key: 'createdTime', | |
250 | + }, | |
251 | + direction: 'DESC', | |
252 | + }, | |
253 | + }, | |
254 | + entityFields: [ | |
255 | + { | |
256 | + type: 'ENTITY_FIELD', | |
257 | + key: 'name', | |
258 | + }, | |
259 | + { | |
260 | + type: 'ENTITY_FIELD', | |
261 | + key: 'label', | |
262 | + }, | |
263 | + { | |
264 | + type: 'ENTITY_FIELD', | |
265 | + key: 'additionalInfo', | |
266 | + }, | |
267 | + ], | |
268 | + latestValues: [ | |
269 | + { | |
270 | + type: 'TIME_SERIES', | |
271 | + key: 'transportMsgCountHourly', | |
272 | + }, | |
273 | + { | |
274 | + type: 'TIME_SERIES', | |
275 | + key: 'transportDataPointsCountHourly', | |
276 | + }, | |
277 | + ], | |
278 | + }, | |
279 | + cmdId: activeKey.value, | |
280 | + }, | |
281 | + ], | |
282 | + }); | |
283 | + send(sendMessageValue); | |
284 | + } | |
285 | + send(sendValue); | |
50 | 286 | } |
51 | - function onDateChange(date, dateString) { | |
52 | - console.log(date, dateString); | |
287 | + // 选择日期 | |
288 | + function onDateChange(_, dateString) { | |
289 | + activeIndex.value = -1; | |
290 | + const dateTime = Number(formatToDateTime(dateString, 'x')); | |
291 | + // 动态发送ws数据 | |
292 | + const sendValue = JSON.stringify({ | |
293 | + entityDataCmds: [ | |
294 | + { | |
295 | + cmdId: activeKey.value, | |
296 | + historyCmd: { | |
297 | + keys: | |
298 | + activeKey.value === '1' | |
299 | + ? ['createdAlarmsCountHourly'] | |
300 | + : ['transportMsgCountHourly', 'transportDataPointsCountHourly'], | |
301 | + startTs: dateTime, | |
302 | + endTs: dateTime + 86400000, | |
303 | + interval: 7200000, | |
304 | + limit: 12, | |
305 | + agg: 'COUNT', | |
306 | + }, | |
307 | + }, | |
308 | + ], | |
309 | + }); | |
310 | + send(sendValue); | |
53 | 311 | } |
54 | - function changeDate(index: number) { | |
312 | + // 快速选择时间 | |
313 | + function quickQueryDate(index: number, value: number) { | |
314 | + if (activeIndex.value === index) return; | |
55 | 315 | activeIndex.value = index; |
316 | + dateValue.value = ''; | |
317 | + let interval = 300000; | |
318 | + if (value === 86400000) { | |
319 | + interval = 7200000; | |
320 | + } else if (value === 604800000 || value === 2592000000) { | |
321 | + interval = 86400000; | |
322 | + } | |
323 | + // 动态发送ws数据 | |
324 | + const sendValue = JSON.stringify({ | |
325 | + entityDataCmds: [ | |
326 | + { | |
327 | + cmdId: activeKey.value, | |
328 | + historyCmd: { | |
329 | + keys: | |
330 | + activeKey.value === '1' | |
331 | + ? ['createdAlarmsCountHourly'] | |
332 | + : ['transportMsgCountHourly', 'transportDataPointsCountHourly'], | |
333 | + startTs: Date.now() - value, | |
334 | + endTs: Date.now(), | |
335 | + interval, | |
336 | + agg: 'COUNT', | |
337 | + }, | |
338 | + }, | |
339 | + ], | |
340 | + }); | |
341 | + send(sendValue); | |
342 | + | |
343 | + console.log(JSON.parse(sendValue), '----interval', state.alarmList); | |
56 | 344 | } |
57 | 345 | </script> |
58 | 346 | |
59 | -<style scoped lang="less"> | |
347 | +<style lang="less"> | |
60 | 348 | .center { |
61 | 349 | display: flex; |
62 | 350 | justify-content: center; | ... | ... |
1 | +<template> | |
2 | + 123 | |
3 | + <div ref="chartRef" :style="{ height, width }"></div> | |
4 | +</template> | |
5 | +<script lang="ts" setup> | |
6 | + import { ref, Ref, withDefaults } from 'vue'; | |
7 | + import { useECharts } from '/@/hooks/web/useECharts'; | |
8 | + | |
9 | + interface Props { | |
10 | + width?: string; | |
11 | + height?: string; | |
12 | + } | |
13 | + withDefaults(defineProps<Props>(), { | |
14 | + width: '100%', | |
15 | + height: '280px', | |
16 | + }); | |
17 | + | |
18 | + const chartRef = ref<HTMLDivElement | null>(null); | |
19 | + const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); | |
20 | +</script> | ... | ... |
1 | 1 | <template> |
2 | - <div ref="chartRef" :style="{ height, width }"></div> | |
2 | + <div> | |
3 | + <p class="center">告警数</p> | |
4 | + <div ref="chartRef" :style="{ height, width }" v-show="alarmList.length"></div> | |
5 | + <div v-show="!alarmList.length">暂无数据</div> | |
6 | + </div> | |
3 | 7 | </template> |
4 | 8 | <script lang="ts" setup> |
5 | - import { onMounted, ref, Ref } from 'vue'; | |
9 | + import { onMounted, ref, Ref, withDefaults, watch } from 'vue'; | |
6 | 10 | import { useECharts } from '/@/hooks/web/useECharts'; |
7 | - import { basicProps } from './props'; | |
8 | 11 | |
9 | - defineProps({ | |
10 | - ...basicProps, | |
12 | + interface Props { | |
13 | + width?: string; | |
14 | + height?: string; | |
15 | + alarmList: [number, string][]; | |
16 | + } | |
17 | + const props = withDefaults(defineProps<Props>(), { | |
18 | + width: '100%', | |
19 | + height: '280px', | |
20 | + alarmList: () => [], | |
11 | 21 | }); |
22 | + | |
12 | 23 | const chartRef = ref<HTMLDivElement | null>(null); |
13 | 24 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
14 | 25 | |
... | ... | @@ -16,79 +27,60 @@ |
16 | 27 | setOptions({ |
17 | 28 | tooltip: { |
18 | 29 | trigger: 'axis', |
19 | - axisPointer: { | |
20 | - lineStyle: { | |
21 | - width: 1, | |
22 | - color: '#019680', | |
23 | - }, | |
24 | - }, | |
25 | 30 | }, |
31 | + grid: { | |
32 | + left: '3%', | |
33 | + right: '4%', | |
34 | + bottom: '3%', | |
35 | + containLabel: true, | |
36 | + }, | |
37 | + | |
26 | 38 | xAxis: { |
27 | - type: 'category', | |
28 | - boundaryGap: false, | |
29 | - data: [ | |
30 | - '6:00', | |
31 | - '7:00', | |
32 | - '8:00', | |
33 | - '9:00', | |
34 | - '10:00', | |
35 | - '11:00', | |
36 | - '12:00', | |
37 | - '13:00', | |
38 | - '14:00', | |
39 | - '15:00', | |
40 | - '16:00', | |
41 | - '17:00', | |
42 | - '18:00', | |
43 | - '19:00', | |
44 | - '20:00', | |
45 | - '21:00', | |
46 | - '22:00', | |
47 | - '23:00', | |
48 | - ], | |
49 | - splitLine: { | |
50 | - show: true, | |
51 | - lineStyle: { | |
52 | - width: 1, | |
53 | - type: 'solid', | |
54 | - color: 'rgba(226,226,226,0.5)', | |
55 | - }, | |
56 | - }, | |
57 | - axisTick: { | |
58 | - show: false, | |
59 | - }, | |
39 | + type: 'time', | |
40 | + }, | |
41 | + yAxis: { | |
42 | + type: 'value', | |
60 | 43 | }, |
61 | - yAxis: [ | |
62 | - { | |
63 | - type: 'value', | |
64 | - max: 80000, | |
65 | - splitNumber: 4, | |
66 | - axisTick: { | |
67 | - show: false, | |
68 | - }, | |
69 | - splitArea: { | |
70 | - show: true, | |
71 | - areaStyle: { | |
72 | - color: ['rgba(255,255,255,0.2)', 'rgba(226,226,226,0.2)'], | |
73 | - }, | |
74 | - }, | |
75 | - }, | |
76 | - ], | |
77 | - grid: { left: '1%', right: '1%', top: '2 %', bottom: 0, containLabel: true }, | |
78 | 44 | series: [ |
79 | 45 | { |
80 | - smooth: true, | |
81 | - data: [ | |
82 | - 111, 222, 4000, 18000, 33333, 55555, 66666, 33333, 14000, 36000, 66666, 44444, 22222, | |
83 | - 11111, 4000, 2000, 500, 333, 222, 111, | |
84 | - ], | |
85 | - type: 'line', | |
86 | - areaStyle: {}, | |
87 | - itemStyle: { | |
88 | - color: '#5ab1ef', | |
89 | - }, | |
46 | + name: '告警数', | |
47 | + type: 'bar', | |
48 | + stack: 'Total', | |
49 | + data: props.alarmList, | |
90 | 50 | }, |
91 | 51 | ], |
92 | 52 | }); |
93 | 53 | }); |
54 | + watch( | |
55 | + () => props.alarmList, | |
56 | + (newValue) => { | |
57 | + console.log(newValue); | |
58 | + setOptions({ | |
59 | + tooltip: { | |
60 | + trigger: 'axis', | |
61 | + }, | |
62 | + grid: { | |
63 | + left: '3%', | |
64 | + right: '4%', | |
65 | + bottom: '3%', | |
66 | + containLabel: true, | |
67 | + }, | |
68 | + | |
69 | + xAxis: { | |
70 | + type: 'time', | |
71 | + }, | |
72 | + yAxis: { | |
73 | + type: 'value', | |
74 | + }, | |
75 | + series: [ | |
76 | + { | |
77 | + name: '告警数', | |
78 | + type: 'bar', | |
79 | + stack: 'Total', | |
80 | + data: newValue, | |
81 | + }, | |
82 | + ], | |
83 | + }); | |
84 | + } | |
85 | + ); | |
94 | 86 | </script> | ... | ... |
1 | 1 | <template> |
2 | - <div ref="chartRef" :style="{ height, width }"></div> | |
2 | + <div> | |
3 | + <p class="center">消息量</p> | |
4 | + <div ref="chartRef" :style="{ height, width }" v-show="dataPointList.length"></div> | |
5 | + <div v-show="!dataPointList.length">暂无数据</div> | |
6 | + </div> | |
3 | 7 | </template> |
4 | 8 | <script lang="ts" setup> |
5 | - import { onMounted, ref, Ref } from 'vue'; | |
9 | + import { ref, Ref, watch, withDefaults } from 'vue'; | |
6 | 10 | import { useECharts } from '/@/hooks/web/useECharts'; |
7 | - import { basicProps } from './props'; | |
8 | - | |
9 | - defineProps({ | |
10 | - ...basicProps, | |
11 | + type DataItem = [number, string]; | |
12 | + interface Props { | |
13 | + width?: string; | |
14 | + height?: string; | |
15 | + dataPointList: DataItem[]; | |
16 | + messageList: DataItem[]; | |
17 | + } | |
18 | + const props = withDefaults(defineProps<Props>(), { | |
19 | + width: '100%', | |
20 | + height: '280px', | |
21 | + dataPointList: () => [], | |
22 | + messageList: () => [], | |
11 | 23 | }); |
12 | - | |
13 | 24 | const chartRef = ref<HTMLDivElement | null>(null); |
14 | 25 | const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); |
15 | - onMounted(() => { | |
16 | - setOptions({ | |
17 | - tooltip: { | |
18 | - trigger: 'axis', | |
19 | - axisPointer: { | |
20 | - lineStyle: { | |
21 | - width: 1, | |
22 | - color: '#019680', | |
26 | + watch( | |
27 | + () => [props.dataPointList, props.messageList], | |
28 | + ([newValue, newValue1]) => { | |
29 | + // 计算总量 | |
30 | + let dataPointTotal = 0; | |
31 | + let messageTotal = 0; | |
32 | + for (const item of newValue) { | |
33 | + dataPointTotal += Number(item[1]); | |
34 | + } | |
35 | + for (const item of newValue1) { | |
36 | + messageTotal += Number(item[1]); | |
37 | + } | |
38 | + setOptions({ | |
39 | + tooltip: { | |
40 | + trigger: 'axis', | |
41 | + axisPointer: { | |
42 | + type: 'shadow', | |
23 | 43 | }, |
24 | 44 | }, |
25 | - }, | |
26 | - grid: { left: '1%', right: '1%', top: '2 %', bottom: 0, containLabel: true }, | |
27 | - xAxis: { | |
28 | - type: 'category', | |
29 | - data: [ | |
30 | - '1月', | |
31 | - '2月', | |
32 | - '3月', | |
33 | - '4月', | |
34 | - '5月', | |
35 | - '6月', | |
36 | - '7月', | |
37 | - '8月', | |
38 | - '9月', | |
39 | - '10月', | |
40 | - '11月', | |
41 | - '12月', | |
42 | - ], | |
43 | - }, | |
44 | - yAxis: { | |
45 | - type: 'value', | |
46 | - max: 8000, | |
47 | - splitNumber: 4, | |
48 | - }, | |
49 | - series: [ | |
50 | - { | |
51 | - data: [3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000, 3200, 4800], | |
52 | - type: 'bar', | |
53 | - barMaxWidth: 80, | |
45 | + xAxis: { | |
46 | + type: 'time', | |
54 | 47 | }, |
55 | - ], | |
56 | - }); | |
57 | - }); | |
48 | + legend: { | |
49 | + data: ['传输数据点', '传输消息量'], | |
50 | + left: '5%', | |
51 | + orient: 'vertical', | |
52 | + formatter: (name) => { | |
53 | + return name === '传输数据点' ? `${name} ${dataPointTotal}` : `${name} ${messageTotal}`; | |
54 | + }, | |
55 | + }, | |
56 | + | |
57 | + yAxis: {}, | |
58 | + grid: { | |
59 | + left: '3%', | |
60 | + right: '4%', | |
61 | + bottom: '3%', | |
62 | + containLabel: true, | |
63 | + }, | |
64 | + series: [ | |
65 | + { | |
66 | + name: '传输数据点', | |
67 | + type: 'bar', | |
68 | + stack: 'total', | |
69 | + data: newValue, | |
70 | + color: '#9fe080', | |
71 | + }, | |
72 | + { | |
73 | + name: '传输消息量', | |
74 | + type: 'bar', | |
75 | + stack: 'total', | |
76 | + data: newValue1, | |
77 | + color: '#5c7bd9', | |
78 | + }, | |
79 | + ], | |
80 | + }); | |
81 | + } | |
82 | + ); | |
58 | 83 | </script> | ... | ... |
1 | 1 | import { PropType } from 'vue'; |
2 | - | |
2 | +import type { BasicColumn } from '/@/components/Table'; | |
3 | 3 | export interface BasicProps { |
4 | 4 | width: string; |
5 | 5 | height: string; |
... | ... | @@ -14,3 +14,16 @@ export const basicProps = { |
14 | 14 | default: '280px', |
15 | 15 | }, |
16 | 16 | }; |
17 | + | |
18 | +export const columns: BasicColumn[] = [ | |
19 | + { | |
20 | + title: '租户名称', | |
21 | + dataIndex: 'name', | |
22 | + width: 120, | |
23 | + }, | |
24 | + { | |
25 | + title: '过期时间', | |
26 | + dataIndex: 'tenantExpireTime', | |
27 | + width: 120, | |
28 | + }, | |
29 | +]; | ... | ... |
src/views/dashboard/workbench/data.ts
deleted
100644 → 0
1 | -export interface GrowCardItem { | |
2 | - imgUrl: string; | |
3 | - title: string; | |
4 | - value: string; | |
5 | - onLine?: number; | |
6 | - offLine?: number; | |
7 | - inactive?: number; | |
8 | - newDay: string; | |
9 | -} | |
10 | - | |
11 | -export const growCardList: GrowCardItem[] = [ | |
12 | - { | |
13 | - imgUrl: '/src/assets/images/device-count.png', | |
14 | - title: '设备数(个)', | |
15 | - value: '10,000', | |
16 | - onLine: 2000, | |
17 | - offLine: 3000, | |
18 | - inactive: 4000, | |
19 | - newDay: '123,45', | |
20 | - }, | |
21 | - { | |
22 | - imgUrl: '/src/assets/images/alarm-count.png', | |
23 | - title: '11月告警数(条)', | |
24 | - value: '11,000', | |
25 | - newDay: '167,45', | |
26 | - }, | |
27 | - { | |
28 | - imgUrl: '/src/assets/images/msg-count.png', | |
29 | - title: '11月消息量(条)', | |
30 | - value: '12,000', | |
31 | - newDay: '198,45', | |
32 | - }, | |
33 | -]; |
1 | 1 | <template> |
2 | 2 | <div class="p-4 md:flex"> |
3 | 3 | <div class="md:w-7/10 w-full !mr-4 enter-y"> |
4 | - <GrowCard :loading="loading" class="enter-y" /> | |
5 | - <SiteAnalysis class="!my-4 enter-y" :loading="loading" /> | |
6 | - <div class="md:flex enter-y"> | |
4 | + <GrowCard :loading="loading" class="enter-y" :role="role" /> | |
5 | + <SiteAnalysis class="!my-4 enter-y" :loading="loading" :role="role" /> | |
6 | + <div class="md:flex enter-y" v-if="!isAdmin(role)"> | |
7 | 7 | <Card title="核心流程指南" style="width: 100%"> |
8 | - <img alt="核心流程指南" src="../../../assets/images/flow.png" /> | |
8 | + <img alt="核心流程指南" src="/src/assets/images/flow.png" /> | |
9 | 9 | </Card> |
10 | 10 | </div> |
11 | 11 | </div> |
12 | 12 | <div class="md:w-3/10 w-full enter-y"> |
13 | - <HelpDoc /> | |
13 | + <HelpDoc :role="role" /> | |
14 | 14 | </div> |
15 | 15 | </div> |
16 | 16 | </template> |
... | ... | @@ -20,8 +20,19 @@ |
20 | 20 | import SiteAnalysis from './components/SiteAnalysis.vue'; |
21 | 21 | import { Card } from 'ant-design-vue'; |
22 | 22 | import HelpDoc from './components/HelpDoc.vue'; |
23 | + import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | |
24 | + import { getAuthCache } from '/@/utils/auth'; | |
25 | + import { isAdmin } from '/@/enums/roleEnum'; | |
26 | + defineExpose({ | |
27 | + isAdmin, | |
28 | + }); | |
23 | 29 | |
30 | + const userInfo: any = getAuthCache(USER_INFO_KEY); | |
31 | + const role: string = userInfo.roles[0]; | |
24 | 32 | const loading = ref(true); |
33 | + | |
34 | + console.log(role); | |
35 | + | |
25 | 36 | setTimeout(() => { |
26 | 37 | loading.value = false; |
27 | 38 | }, 1500); | ... | ... |
... | ... | @@ -3,6 +3,7 @@ import { findDictItemByCode } from '/@/api/system/dict'; |
3 | 3 | import { deviceProfile } from '/@/api/device/deviceManager'; |
4 | 4 | import { getOrganizationList } from '/@/api/system/system'; |
5 | 5 | import { copyTransFun } from '/@/utils/fnUtils'; |
6 | + | |
6 | 7 | // 第一步的表单 |
7 | 8 | export const step1Schemas: FormSchema[] = [ |
8 | 9 | { |
... | ... | @@ -17,6 +18,7 @@ export const step1Schemas: FormSchema[] = [ |
17 | 18 | required: true, |
18 | 19 | component: 'Input', |
19 | 20 | componentProps: { |
21 | + placeholder: '设备名称', | |
20 | 22 | maxLength: 30, |
21 | 23 | }, |
22 | 24 | }, |
... | ... | @@ -26,6 +28,7 @@ export const step1Schemas: FormSchema[] = [ |
26 | 28 | required: true, |
27 | 29 | component: 'ApiSelect', |
28 | 30 | componentProps: { |
31 | + placeholder: '设备类型', | |
29 | 32 | api: findDictItemByCode, |
30 | 33 | params: { |
31 | 34 | dictCode: 'device_type', |
... | ... | @@ -64,6 +67,20 @@ export const step1Schemas: FormSchema[] = [ |
64 | 67 | component: 'Input', |
65 | 68 | componentProps: { |
66 | 69 | maxLength: 255, |
70 | + placeholder: '请输入设备标签', | |
71 | + }, | |
72 | + dynamicRules: () => { | |
73 | + return [ | |
74 | + { | |
75 | + required: false, | |
76 | + validator: (_, value) => { | |
77 | + if (String(value).length > 255) { | |
78 | + return Promise.reject('字数不超过255个字'); | |
79 | + } | |
80 | + return Promise.resolve(); | |
81 | + }, | |
82 | + }, | |
83 | + ]; | |
67 | 84 | }, |
68 | 85 | }, |
69 | 86 | { |
... | ... | @@ -76,24 +93,92 @@ export const step1Schemas: FormSchema[] = [ |
76 | 93 | field: 'description', |
77 | 94 | label: '备注', |
78 | 95 | component: 'InputTextArea', |
96 | + componentProps: { | |
97 | + maxLength: 500, | |
98 | + placeholder: '请输入备注', | |
99 | + }, | |
100 | + dynamicRules: () => { | |
101 | + return [ | |
102 | + { | |
103 | + required: false, | |
104 | + validator: (_, value) => { | |
105 | + if (String(value).length > 500) { | |
106 | + return Promise.reject('字数不超过500个字'); | |
107 | + } | |
108 | + return Promise.resolve(); | |
109 | + }, | |
110 | + }, | |
111 | + ]; | |
112 | + }, | |
79 | 113 | }, |
80 | 114 | { |
81 | 115 | field: 'id', |
82 | 116 | label: 'id', |
83 | 117 | component: 'Input', |
84 | 118 | show: false, |
119 | + componentProps: { | |
120 | + maxLength: 36, | |
121 | + placeholder: '请输入id', | |
122 | + }, | |
123 | + dynamicRules: () => { | |
124 | + return [ | |
125 | + { | |
126 | + required: false, | |
127 | + validator: (_, value) => { | |
128 | + if (String(value).length > 36) { | |
129 | + return Promise.reject('字数不超过36个字'); | |
130 | + } | |
131 | + return Promise.resolve(); | |
132 | + }, | |
133 | + }, | |
134 | + ]; | |
135 | + }, | |
85 | 136 | }, |
86 | 137 | { |
87 | 138 | field: 'tenantId', |
88 | 139 | label: '租户Code', |
89 | 140 | component: 'Input', |
90 | 141 | show: false, |
142 | + componentProps: { | |
143 | + maxLength: 36, | |
144 | + placeholder: '请输入租户Code', | |
145 | + }, | |
146 | + dynamicRules: () => { | |
147 | + return [ | |
148 | + { | |
149 | + required: false, | |
150 | + validator: (_, value) => { | |
151 | + if (String(value).length > 36) { | |
152 | + return Promise.reject('字数不超过36个字'); | |
153 | + } | |
154 | + return Promise.resolve(); | |
155 | + }, | |
156 | + }, | |
157 | + ]; | |
158 | + }, | |
91 | 159 | }, |
92 | 160 | { |
93 | 161 | field: 'tbDeviceId', |
94 | 162 | label: 'tbDeviceId', |
95 | 163 | component: 'Input', |
96 | 164 | show: false, |
165 | + componentProps: { | |
166 | + maxLength: 36, | |
167 | + placeholder: '请输入tbDeviceId', | |
168 | + }, | |
169 | + dynamicRules: () => { | |
170 | + return [ | |
171 | + { | |
172 | + required: false, | |
173 | + validator: (_, value) => { | |
174 | + if (String(value).length > 36) { | |
175 | + return Promise.reject('字数不超过36个字'); | |
176 | + } | |
177 | + return Promise.resolve(); | |
178 | + }, | |
179 | + }, | |
180 | + ]; | |
181 | + }, | |
97 | 182 | }, |
98 | 183 | ]; |
99 | 184 | |
... | ... | @@ -244,6 +329,10 @@ export const step2Schemas: FormSchema[] = [ |
244 | 329 | field: 'credentialsId', |
245 | 330 | required: true, |
246 | 331 | ifShow: false, |
332 | + componentProps: { | |
333 | + maxLength: 36, | |
334 | + placeholder: '请输入访问令牌', | |
335 | + }, | |
247 | 336 | }, |
248 | 337 | { |
249 | 338 | label: 'RSA公钥', |
... | ... | @@ -251,6 +340,10 @@ export const step2Schemas: FormSchema[] = [ |
251 | 340 | field: 'publicKey', |
252 | 341 | required: true, |
253 | 342 | ifShow: false, |
343 | + componentProps: { | |
344 | + maxLength: 36, | |
345 | + placeholder: '请输入RSA公钥', | |
346 | + }, | |
254 | 347 | }, |
255 | 348 | { |
256 | 349 | label: '客户端ID', |
... | ... | @@ -258,6 +351,10 @@ export const step2Schemas: FormSchema[] = [ |
258 | 351 | field: 'clientId', |
259 | 352 | required: true, |
260 | 353 | ifShow: false, |
354 | + componentProps: { | |
355 | + maxLength: 36, | |
356 | + placeholder: '请输入客户端ID', | |
357 | + }, | |
261 | 358 | }, |
262 | 359 | { |
263 | 360 | label: '用户名', |
... | ... | @@ -265,11 +362,32 @@ export const step2Schemas: FormSchema[] = [ |
265 | 362 | field: 'username', |
266 | 363 | required: true, |
267 | 364 | ifShow: false, |
365 | + componentProps: { | |
366 | + maxLength: 255, | |
367 | + placeholder: '请输入用户名', | |
368 | + }, | |
268 | 369 | }, |
269 | 370 | { |
270 | 371 | label: '密码', |
271 | 372 | component: 'InputPassword', |
272 | 373 | field: 'password', |
374 | + componentProps: { | |
375 | + maxLength: 36, | |
376 | + placeholder: '请输入密码', | |
377 | + }, | |
378 | + dynamicRules: () => { | |
379 | + return [ | |
380 | + { | |
381 | + required: false, | |
382 | + validator: (_, value) => { | |
383 | + if (String(value).length > 36) { | |
384 | + return Promise.reject('字数不超过36个字'); | |
385 | + } | |
386 | + return Promise.resolve(); | |
387 | + }, | |
388 | + }, | |
389 | + ]; | |
390 | + }, | |
273 | 391 | ifShow: false, |
274 | 392 | }, |
275 | 393 | ]; |
... | ... | @@ -409,6 +527,10 @@ export const TokenSchemas: FormSchema[] = [ |
409 | 527 | field: 'credentialsId', |
410 | 528 | required: true, |
411 | 529 | ifShow: false, |
530 | + componentProps: { | |
531 | + maxLength: 36, | |
532 | + placeholder: '请输入访问令牌', | |
533 | + }, | |
412 | 534 | }, |
413 | 535 | { |
414 | 536 | label: 'RSA公钥', |
... | ... | @@ -416,6 +538,10 @@ export const TokenSchemas: FormSchema[] = [ |
416 | 538 | field: 'publicKey', |
417 | 539 | required: true, |
418 | 540 | ifShow: false, |
541 | + componentProps: { | |
542 | + maxLength: 36, | |
543 | + placeholder: '请输入RSA公钥', | |
544 | + }, | |
419 | 545 | }, |
420 | 546 | { |
421 | 547 | label: '客户端ID', |
... | ... | @@ -423,6 +549,10 @@ export const TokenSchemas: FormSchema[] = [ |
423 | 549 | field: 'clientId', |
424 | 550 | required: true, |
425 | 551 | ifShow: false, |
552 | + componentProps: { | |
553 | + maxLength: 36, | |
554 | + placeholder: '请输入客户端ID', | |
555 | + }, | |
426 | 556 | }, |
427 | 557 | { |
428 | 558 | label: '用户名', |
... | ... | @@ -430,23 +560,78 @@ export const TokenSchemas: FormSchema[] = [ |
430 | 560 | field: 'username', |
431 | 561 | required: true, |
432 | 562 | ifShow: false, |
563 | + componentProps: { | |
564 | + maxLength: 255, | |
565 | + placeholder: '请输入用户名', | |
566 | + }, | |
433 | 567 | }, |
434 | 568 | { |
435 | 569 | label: '密码', |
436 | 570 | component: 'InputPassword', |
437 | 571 | field: 'password', |
438 | 572 | ifShow: false, |
573 | + componentProps: { | |
574 | + maxLength: 36, | |
575 | + placeholder: '请输入密码', | |
576 | + }, | |
577 | + dynamicRules: () => { | |
578 | + return [ | |
579 | + { | |
580 | + required: false, | |
581 | + validator: (_, value) => { | |
582 | + if (String(value).length > 36) { | |
583 | + return Promise.reject('字数不超过36个字'); | |
584 | + } | |
585 | + return Promise.resolve(); | |
586 | + }, | |
587 | + }, | |
588 | + ]; | |
589 | + }, | |
439 | 590 | }, |
440 | 591 | { |
441 | 592 | label: 'id', |
442 | 593 | component: 'Input', |
443 | 594 | field: 'id', |
444 | 595 | show: false, |
596 | + componentProps: { | |
597 | + maxLength: 36, | |
598 | + placeholder: '请输入id', | |
599 | + }, | |
600 | + dynamicRules: () => { | |
601 | + return [ | |
602 | + { | |
603 | + required: false, | |
604 | + validator: (_, value) => { | |
605 | + if (String(value).length > 36) { | |
606 | + return Promise.reject('字数不超过36个字'); | |
607 | + } | |
608 | + return Promise.resolve(); | |
609 | + }, | |
610 | + }, | |
611 | + ]; | |
612 | + }, | |
445 | 613 | }, |
446 | 614 | { |
447 | 615 | label: 'tbDeviceId', |
448 | 616 | component: 'Input', |
449 | 617 | field: 'tbDeviceId', |
450 | 618 | show: false, |
619 | + componentProps: { | |
620 | + maxLength: 36, | |
621 | + placeholder: '请输入tbDeviceId', | |
622 | + }, | |
623 | + dynamicRules: () => { | |
624 | + return [ | |
625 | + { | |
626 | + required: false, | |
627 | + validator: (_, value) => { | |
628 | + if (String(value).length > 36) { | |
629 | + return Promise.reject('字数不超过36个字'); | |
630 | + } | |
631 | + return Promise.resolve(); | |
632 | + }, | |
633 | + }, | |
634 | + ]; | |
635 | + }, | |
451 | 636 | }, |
452 | 637 | ]; | ... | ... |
1 | 1 | import { formatToDateTime } from '/@/utils/dateUtil'; |
2 | 2 | import { FormSchema } from '/@/components/Form'; |
3 | 3 | import { BasicColumn } from '/@/components/Table'; |
4 | + | |
4 | 5 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
5 | 6 | |
6 | 7 | export const columns: BasicColumn[] = [ |
... | ... | @@ -8,25 +9,20 @@ export const columns: BasicColumn[] = [ |
8 | 9 | title: '设备名称', |
9 | 10 | dataIndex: 'name', |
10 | 11 | width: 120, |
11 | - key: 'name', | |
12 | 12 | }, |
13 | 13 | { |
14 | 14 | title: '设备标签', |
15 | 15 | dataIndex: 'label', |
16 | 16 | width: 100, |
17 | - key: 'label', | |
18 | 17 | }, |
19 | 18 | { |
20 | 19 | title: '设备配置', |
21 | 20 | dataIndex: 'deviceProfile.name', |
22 | 21 | width: 160, |
23 | - key: 'deviceProfile.name', | |
24 | 22 | }, |
25 | - | |
26 | 23 | { |
27 | 24 | title: '设备类型', |
28 | 25 | dataIndex: 'deviceType', |
29 | - key: 'deviceType', | |
30 | 26 | customRender({ text }) { |
31 | 27 | return text === DeviceTypeEnum.GATEWAY |
32 | 28 | ? '网关设备' |
... | ... | @@ -39,7 +35,6 @@ export const columns: BasicColumn[] = [ |
39 | 35 | title: '描述', |
40 | 36 | dataIndex: 'description', |
41 | 37 | width: 180, |
42 | - key: 'description', | |
43 | 38 | }, |
44 | 39 | ]; |
45 | 40 | // 实时数据表格 |
... | ... | @@ -95,6 +90,9 @@ export const alarmSearchSchemas: FormSchema[] = [ |
95 | 90 | label: '告警类型', |
96 | 91 | component: 'Input', |
97 | 92 | colProps: { span: 6 }, |
93 | + componentProps: { | |
94 | + maxLength: 36, | |
95 | + }, | |
98 | 96 | }, |
99 | 97 | { |
100 | 98 | field: 'endTime', |
... | ... | @@ -208,6 +206,9 @@ export const alarmSchemasForm: FormSchema[] = [ |
208 | 206 | field: 'details', |
209 | 207 | label: '详情', |
210 | 208 | component: 'InputTextArea', |
209 | + componentProps: { | |
210 | + maxLength: 255, | |
211 | + }, | |
211 | 212 | }, |
212 | 213 | ]; |
213 | 214 | |
... | ... | @@ -218,12 +219,18 @@ export const childDeviceSchemas: FormSchema[] = [ |
218 | 219 | label: '设备配置', |
219 | 220 | component: 'Select', |
220 | 221 | colProps: { span: 12 }, |
222 | + componentProps: { | |
223 | + maxLength: 255, | |
224 | + }, | |
221 | 225 | }, |
222 | 226 | { |
223 | 227 | field: 'icon', |
224 | 228 | label: '设备名称', |
225 | 229 | component: 'Input', |
226 | 230 | colProps: { span: 12 }, |
231 | + componentProps: { | |
232 | + maxLength: 255, | |
233 | + }, | |
227 | 234 | }, |
228 | 235 | ]; |
229 | 236 | export const childDeviceColumns: BasicColumn[] = [ | ... | ... |
1 | +import { formatToDate } from '/@/utils/dateUtil'; | |
1 | 2 | import { BasicColumn } from '/@/components/Table'; |
2 | 3 | import { FormSchema } from '/@/components/Table'; |
3 | 4 | import { DeviceTypeEnum, DeviceState } from '/@/api/device/model/deviceModel'; |
5 | + | |
4 | 6 | // 表格列数据 |
5 | 7 | export const columns: BasicColumn[] = [ |
6 | 8 | { |
... | ... | @@ -19,6 +21,7 @@ export const columns: BasicColumn[] = [ |
19 | 21 | dataIndex: 'deviceProfile.name', |
20 | 22 | width: 160, |
21 | 23 | slots: { customRender: 'deviceProfile' }, |
24 | + ellipsis: true, | |
22 | 25 | }, |
23 | 26 | |
24 | 27 | { |
... | ... | @@ -36,10 +39,16 @@ export const columns: BasicColumn[] = [ |
36 | 39 | width: 120, |
37 | 40 | slots: { customRender: 'deviceState' }, |
38 | 41 | }, |
39 | - | |
40 | 42 | { |
41 | 43 | title: '最后连接时间', |
42 | - dataIndex: 'lastConnectTime', | |
44 | + dataIndex: 'lastOnlineTime', | |
45 | + format: (text) => formatToDate(text, 'YYYY-MM-DD HH:mm:ss'), | |
46 | + width: 180, | |
47 | + }, | |
48 | + { | |
49 | + title: '最后断开时间', | |
50 | + dataIndex: 'lastOfflineTime', | |
51 | + format: (text) => formatToDate(text, 'YYYY-MM-DD HH:mm:ss'), | |
43 | 52 | width: 180, |
44 | 53 | }, |
45 | 54 | ]; |
... | ... | @@ -76,6 +85,23 @@ export const searchFormSchema: FormSchema[] = [ |
76 | 85 | field: 'name', |
77 | 86 | label: '设备名称', |
78 | 87 | component: 'Input', |
79 | - colProps: { span: 6 }, | |
88 | + colProps: { span: 7 }, | |
89 | + componentProps: { | |
90 | + maxLength: 255, | |
91 | + placeholder: '请输入设备名称', | |
92 | + }, | |
93 | + dynamicRules: () => { | |
94 | + return [ | |
95 | + { | |
96 | + required: false, | |
97 | + validator: (_, value) => { | |
98 | + if (String(value).length > 255) { | |
99 | + return Promise.reject('字数不超过255个字'); | |
100 | + } | |
101 | + return Promise.resolve(); | |
102 | + }, | |
103 | + }, | |
104 | + ]; | |
105 | + }, | |
80 | 106 | }, |
81 | 107 | ]; | ... | ... |
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | :destroyOnClose="true" |
7 | 7 | @close="closeDrawer" |
8 | 8 | :title="deviceDetail.name" |
9 | - width="78%" | |
9 | + width="70%" | |
10 | 10 | > |
11 | 11 | <Tabs v-model:activeKey="activeKey" :size="size" type="card"> |
12 | 12 | <TabPane key="1" tab="详情" |
... | ... | @@ -26,7 +26,7 @@ |
26 | 26 | import { defineComponent, ref } from 'vue'; |
27 | 27 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; |
28 | 28 | |
29 | - import { Tabs, TabPane } from 'ant-design-vue'; | |
29 | + import { Tabs } from 'ant-design-vue'; | |
30 | 30 | import Detail from '../tabs/Detail.vue'; |
31 | 31 | import RealTimeData from '../tabs/RealTimeData.vue'; |
32 | 32 | import Alarm from '../tabs/Alarm.vue'; |
... | ... | @@ -37,13 +37,12 @@ |
37 | 37 | components: { |
38 | 38 | BasicDrawer, |
39 | 39 | Tabs, |
40 | - TabPane, | |
40 | + TabPane: Tabs.TabPane, | |
41 | 41 | Detail, |
42 | 42 | RealTimeData, |
43 | 43 | Alarm, |
44 | 44 | ChildDevice, |
45 | 45 | }, |
46 | - | |
47 | 46 | emits: ['reload', 'register'], |
48 | 47 | setup() { |
49 | 48 | const activeKey = ref('1'); | ... | ... |
... | ... | @@ -39,9 +39,10 @@ |
39 | 39 | import { createOrEditDevice } from '/@/api/device/deviceManager'; |
40 | 40 | import DeviceStep1 from '../step/DeviceStep1.vue'; |
41 | 41 | import DeviceStep2 from '../step/DeviceStep2.vue'; |
42 | - import { Steps, Step } from 'ant-design-vue'; | |
42 | + import { Steps } from 'ant-design-vue'; | |
43 | 43 | import { useMessage } from '/@/hooks/web/useMessage'; |
44 | 44 | import { credentialTypeEnum } from '../../config/data'; |
45 | + | |
45 | 46 | export default defineComponent({ |
46 | 47 | name: 'DeviceModal', |
47 | 48 | components: { |
... | ... | @@ -49,7 +50,7 @@ |
49 | 50 | DeviceStep1, |
50 | 51 | DeviceStep2, |
51 | 52 | Steps, |
52 | - Step, | |
53 | + Step: Steps.Step, | |
53 | 54 | }, |
54 | 55 | props: { |
55 | 56 | userData: { type: Object }, | ... | ... |
... | ... | @@ -44,6 +44,13 @@ |
44 | 44 | labelWidth: 120, |
45 | 45 | schemas: alarmSearchSchemas, |
46 | 46 | }, |
47 | + showTableSetting: true, | |
48 | + tableSetting: { | |
49 | + redo: true, | |
50 | + size: false, | |
51 | + setting: false, | |
52 | + fullScreen: false, | |
53 | + }, | |
47 | 54 | useSearchForm: true, |
48 | 55 | bordered: true, |
49 | 56 | showIndexColumn: false, | ... | ... |
... | ... | @@ -10,8 +10,8 @@ |
10 | 10 | bordered |
11 | 11 | :columns="columns" |
12 | 12 | :data-source="[deviceDetail]" |
13 | + :rowKey="(_, index) => index" | |
13 | 14 | :pagination="false" |
14 | - rowKey="tbDeviceId" | |
15 | 15 | style="width: 800px" |
16 | 16 | /> |
17 | 17 | </div> |
... | ... | @@ -23,7 +23,7 @@ |
23 | 23 | </div> |
24 | 24 | <div v-if="deviceDetail?.deviceInfo?.address" class="mt-4"> |
25 | 25 | <p>设备位置</p> |
26 | - <div ref="wrapRef" style="height: 400px; width: 90%"></div> | |
26 | + <div ref="wrapRef" style="height: 400px; width: 100%"></div> | |
27 | 27 | </div> |
28 | 28 | </div> |
29 | 29 | </template> | ... | ... |
... | ... | @@ -24,7 +24,7 @@ |
24 | 24 | setup(props) { |
25 | 25 | const token: string = getAuthCache(JWT_TOKEN_KEY); |
26 | 26 | const state = reactive({ |
27 | - server: `ws://101.133.234.90:8080/api/ws/plugins/telemetry?token=${token}`, | |
27 | + server: `${import.meta.env.VITE_WEB_SOCKET}${token}`, | |
28 | 28 | sendValue: JSON.stringify({ |
29 | 29 | attrSubCmds: [], |
30 | 30 | tsSubCmds: [ | ... | ... |
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 | @cancel="handleCancel" |
9 | 9 | > |
10 | 10 | <div class="step-form-form"> |
11 | - <a-steps :current="current"> | |
11 | + <a-steps :current="current" @change="handleChange"> | |
12 | 12 | <a-step title="设备配置" /> |
13 | 13 | <a-step title="传输配置" /> |
14 | 14 | <a-step title="告警配置" /> |
... | ... | @@ -34,10 +34,9 @@ |
34 | 34 | @next="handleStep3Next" |
35 | 35 | @redo="handleRedo" |
36 | 36 | /></div> |
37 | - | |
38 | 37 | <div v-show="current === 3"> |
39 | - <DeviceProfileStep4 ref="DeviceProfileStep4Ref" @prev="handleStepPrev" | |
40 | - /></div> | |
38 | + <DeviceProfileStep4 ref="DeviceProfileStep4Ref" @prev="handleStepPrev" /> | |
39 | + </div> | |
41 | 40 | </div> |
42 | 41 | </BasicModal> |
43 | 42 | </template> |
... | ... | @@ -86,13 +85,21 @@ |
86 | 85 | const current = ref(0); |
87 | 86 | const isUpdate = ref(true); |
88 | 87 | const getTitle = computed(() => (!unref(isUpdate) ? '新增设备配置' : '编辑设备配置')); |
88 | + const handleChange = (v) => { | |
89 | + console.log(v); | |
90 | + }; | |
89 | 91 | const [register, { closeModal }] = useModalInner(async (data) => { |
90 | 92 | isUpdate.value = !!data?.isUpdate; |
91 | 93 | if (!unref(isUpdate)) { |
92 | 94 | current.value = 0; |
95 | + proxy.$refs.DeviceProfileStep3Ref.clearProfileDataFunc(); | |
96 | + proxy.$refs.DeviceProfileStep3Ref.addAlarmRule(); | |
97 | + // proxy.$refs.DeviceProfileStep4Ref.customResetAndFunc(); | |
98 | + | |
93 | 99 | switch (current.value) { |
94 | 100 | case 0: |
95 | 101 | proxy.$refs.DeviceProfileStep1Ref.customResetFunc(); |
102 | + proxy.$refs.DeviceProfileStep1Ref.resetIconFunc(); | |
96 | 103 | break; |
97 | 104 | case 1: |
98 | 105 | proxy.$refs.DeviceProfileStep2Ref.customResetAndFunc(); |
... | ... | @@ -109,32 +116,15 @@ |
109 | 116 | } |
110 | 117 | if (unref(isUpdate)) { |
111 | 118 | current.value = 0; |
119 | + proxy.$refs.DeviceProfileStep3Ref.clearProfileDataFunc(); | |
120 | + proxy.$refs.DeviceProfileStep3Ref.addAlarmRule(); | |
112 | 121 | postEditId.value = data.record.id; |
113 | 122 | const getBackendData = await deviceConfigGetDetail(postEditId.value); |
114 | 123 | editEchoData.value = { ...getBackendData }; |
115 | - console.log(editEchoData.value); | |
116 | 124 | switch (current.value) { |
117 | 125 | case 0: |
118 | 126 | proxy.$refs.DeviceProfileStep1Ref.resetFieldsFunc(editEchoData.value); |
119 | - break; | |
120 | - case 1: | |
121 | - proxy.$refs.DeviceProfileStep2Ref.resetFieldsFunc({ | |
122 | - transportType: editEchoData.value.profileData.transportConfiguration.type, | |
123 | - }); | |
124 | - break; | |
125 | - case 2: | |
126 | - proxy.$refs.DeviceProfileStep3Ref.retryRegisterFormFunc({ | |
127 | - alarmType: editEchoData.value.profileData?.alarms[0].alarmType, | |
128 | - }); | |
129 | - proxy.$refs.DeviceProfileStep3Ref.retryRegisterFormHighSettingmFunc( | |
130 | - editEchoData.value | |
131 | - ); | |
132 | - proxy.$refs.DeviceProfileStep3Ref.retryRegisterFormCreateAlarmFunc( | |
133 | - editEchoData.value | |
134 | - ); | |
135 | - break; | |
136 | - case 3: | |
137 | - proxy.$refs.DeviceProfileStep4Ref.resetFieldsFunc(editEchoData.value); | |
127 | + proxy.$refs.DeviceProfileStep1Ref.editIconFunc(editEchoData.value.icon); | |
138 | 128 | break; |
139 | 129 | } |
140 | 130 | } |
... | ... | @@ -142,18 +132,132 @@ |
142 | 132 | function handleStepPrev() { |
143 | 133 | current.value--; |
144 | 134 | } |
145 | - function handleStepNext1(v) { | |
135 | + function handleStepNext1(v, v1) { | |
136 | + console.log(v, v1); | |
146 | 137 | current.value++; |
147 | 138 | getStepOneData.value = v; |
139 | + getStepOneData.value.icon = v1; | |
140 | + console.log(getStepOneData.value); | |
141 | + if (unref(isUpdate)) { | |
142 | + proxy.$refs.DeviceProfileStep2Ref.resetFieldsFunc({ | |
143 | + transportType: editEchoData.value.profileData.transportConfiguration.type, | |
144 | + }); | |
145 | + } else { | |
146 | + // proxy.$refs.DeviceProfileStep2Ref.customResetAndFunc(); | |
147 | + } | |
148 | 148 | } |
149 | 149 | function handleStep2Next(v) { |
150 | 150 | current.value++; |
151 | + | |
151 | 152 | getStepTwoData.value = v; |
152 | - proxy.$refs.DeviceProfileStep3Ref.addAlarmRule(); | |
153 | + if (unref(isUpdate)) { | |
154 | + proxy.$refs.DeviceProfileStep3Ref.retryRegisterFormFunc({ | |
155 | + alarmType: editEchoData.value.profileData.alarms[0].alarmType, | |
156 | + }); | |
157 | + proxy.$refs.DeviceProfileStep3Ref.retryRegisterFormHighSettingmFunc({ | |
158 | + propagate: editEchoData.value.profileData.alarms[0].propagate, | |
159 | + propagateRelationTypes: | |
160 | + editEchoData.value.profileData?.alarms[0].propagateRelationTypes, | |
161 | + }); | |
162 | + const getKey = Object.keys(editEchoData.value.profileData?.alarms[0].createRules); | |
163 | + proxy.$refs.DeviceProfileStep3Ref.retryRegisterFormCreateAlarmFunc({ | |
164 | + default: getKey[0], | |
165 | + }); | |
166 | + const findDay = [ | |
167 | + { label: '等于', value: 'EQUAL' }, | |
168 | + { label: '不等于', value: 'NOT_EQUAL' }, | |
169 | + { label: '开始于', value: 'STARTS_WITH' }, | |
170 | + { label: '结束于', value: 'ENDS_WITH' }, | |
171 | + { label: '包含', value: 'CONTAINS' }, | |
172 | + { label: '不包含', value: 'NOT_CONTAINS' }, | |
173 | + { label: '等于', value: 'EQUAL' }, | |
174 | + { label: '不等于', value: 'NOT_EQUAL' }, | |
175 | + { label: '大于', value: 'GREATER' }, | |
176 | + { label: '小于', value: 'LESS' }, | |
177 | + { label: '大于或等于', value: 'GREATER_OR_EQUAL' }, | |
178 | + { label: '小于或等于', value: 'LESS_OR_EQUAL' }, | |
179 | + ]; | |
180 | + const findRuleByValue = findDay.find((f) => { | |
181 | + if ( | |
182 | + f.value == | |
183 | + editEchoData.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
184 | + .condition[0].predicate.operation | |
185 | + ) { | |
186 | + return f.label; | |
187 | + } | |
188 | + }); | |
189 | + const findClearRuleByValue = findDay.find((f) => { | |
190 | + if ( | |
191 | + f.value == | |
192 | + editEchoData.value.profileData?.alarms[0].clearRule.condition.condition[0].predicate | |
193 | + .operation | |
194 | + ) { | |
195 | + return f.label; | |
196 | + } | |
197 | + }); | |
198 | + proxy.$refs.DeviceProfileStep3Ref.retryRulesFormDataFunc( | |
199 | + ` | |
200 | + 键名:${ | |
201 | + editEchoData.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
202 | + .condition[0].key.key | |
203 | + }...操作:${findRuleByValue?.label}...值:${ | |
204 | + editEchoData.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
205 | + .condition[0].predicate.value.defaultValue | |
206 | + } | |
207 | + ` | |
208 | + ); | |
209 | + proxy.$refs.DeviceProfileStep3Ref.retryEnableFormDataFunc(`始终启用`); | |
210 | + proxy.$refs.DeviceProfileStep3Ref.retryTemplateFormDataFunc( | |
211 | + ` | |
212 | + 报警详细信息:${ | |
213 | + editEchoData.value.profileData?.alarms[0].createRules[getKey[0]].alarmDetails | |
214 | + } | |
215 | + ` | |
216 | + ); | |
217 | + //清除报警 | |
218 | + proxy.$refs.DeviceProfileStep3Ref.retryRulesClearFormDataFunc( | |
219 | + ` | |
220 | + 键名:${editEchoData.value.profileData?.alarms[0].clearRule.condition.condition[0].key.key}...操作:${findClearRuleByValue?.label}...值:${editEchoData.value.profileData?.alarms[0].clearRule.condition.condition[0].predicate.value.defaultValue} | |
221 | + ` | |
222 | + ); | |
223 | + proxy.$refs.DeviceProfileStep3Ref.retryEnableClearFormDataFunc(`始终启用`); | |
224 | + proxy.$refs.DeviceProfileStep3Ref.retryTemplateClearFormDataFunc( | |
225 | + ` | |
226 | + 报警详细信息:${editEchoData.value.profileData?.alarms[0].clearRule.alarmDetails} | |
227 | + ` | |
228 | + ); | |
229 | + } else { | |
230 | + proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormFunc(); | |
231 | + proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormHighSettingmFunc(); | |
232 | + proxy.$refs.DeviceProfileStep3Ref.resetRegisterFormCreateAlarmFunc(); | |
233 | + proxy.$refs.DeviceProfileStep3Ref.resetRulesFormDataFunc(); | |
234 | + proxy.$refs.DeviceProfileStep3Ref.resetEnableFormDataFunc(); | |
235 | + proxy.$refs.DeviceProfileStep3Ref.resetTemplateFormDataFunc(); | |
236 | + proxy.$refs.DeviceProfileStep3Ref.resetRulesClearFormDataFunc(); | |
237 | + proxy.$refs.DeviceProfileStep3Ref.resetEnableClearFormDataFunc(); | |
238 | + proxy.$refs.DeviceProfileStep3Ref.resetTemplateClearFormDataFunc(); | |
239 | + } | |
153 | 240 | } |
154 | 241 | function handleStep3Next(v) { |
155 | 242 | current.value++; |
156 | 243 | getStepThreeData.value = v; |
244 | + try { | |
245 | + if (unref(isUpdate)) { | |
246 | + setTimeout(() => { | |
247 | + proxy.$refs.DeviceProfileStep4Ref.resetFieldsFunc({ | |
248 | + alarmContactId: editEchoData.value.alarmProfile.alarmContactId, | |
249 | + messageMode: editEchoData.value.alarmProfile.messageMode, | |
250 | + }); | |
251 | + }, 1000); | |
252 | + } | |
253 | + // if (!unref(isUpdate)) { | |
254 | + // setTimeout(() => { | |
255 | + // proxy.$refs.DeviceProfileStep4Ref.customResetAndFunc(); | |
256 | + // }, 1000); | |
257 | + // } | |
258 | + } catch (e) { | |
259 | + return e; | |
260 | + } | |
157 | 261 | } |
158 | 262 | function handleRedo() { |
159 | 263 | current.value = 0; |
... | ... | @@ -197,6 +301,7 @@ |
197 | 301 | return; |
198 | 302 | }; |
199 | 303 | return { |
304 | + handleChange, | |
200 | 305 | DeviceProfileStep2Ref, |
201 | 306 | DeviceProfileStep3Ref, |
202 | 307 | DeviceProfileStep4Ref, | ... | ... |
... | ... | @@ -2,8 +2,9 @@ import { BasicColumn } from '/@/components/Table'; |
2 | 2 | import { FormSchema } from '/@/components/Table'; |
3 | 3 | import { findDictItemByCode } from '/@/api/system/dict'; |
4 | 4 | import { MessageEnum } from '/@/enums/messageEnum'; |
5 | -import { getOrganizationList } from '/@/api/system/system'; | |
6 | -import { copyTransFun } from '/@/utils/fnUtils'; | |
5 | +// import { getOrganizationList } from '/@/api/system/system'; | |
6 | +// import { copyTransFun } from '/@/utils/fnUtils'; | |
7 | +import { numberRule } from '/@/utils/rules'; | |
7 | 8 | |
8 | 9 | export const columns: BasicColumn[] = [ |
9 | 10 | { |
... | ... | @@ -30,23 +31,27 @@ export const columns: BasicColumn[] = [ |
30 | 31 | |
31 | 32 | export const searchFormSchema: FormSchema[] = [ |
32 | 33 | { |
33 | - field: 'organizationId', | |
34 | - label: '请选择组织', | |
35 | - component: 'ApiTreeSelect', | |
36 | - colProps: { span: 6 }, | |
37 | - componentProps: { | |
38 | - api: async () => { | |
39 | - const data = await getOrganizationList(); | |
40 | - copyTransFun(data as any as any[]); | |
41 | - return data; | |
42 | - }, | |
43 | - }, | |
44 | - }, | |
45 | - { | |
46 | 34 | field: 'name', |
47 | 35 | label: '配置名称', |
48 | 36 | component: 'Input', |
49 | 37 | colProps: { span: 8 }, |
38 | + componentProps: { | |
39 | + maxLength: 255, | |
40 | + placeholder: '请输入配置名称', | |
41 | + }, | |
42 | + dynamicRules: () => { | |
43 | + return [ | |
44 | + { | |
45 | + required: false, | |
46 | + validator: (_, value) => { | |
47 | + if (String(value).length > 255) { | |
48 | + return Promise.reject('字数不超过255个字'); | |
49 | + } | |
50 | + return Promise.resolve(); | |
51 | + }, | |
52 | + }, | |
53 | + ]; | |
54 | + }, | |
50 | 55 | }, |
51 | 56 | ]; |
52 | 57 | |
... | ... | @@ -63,6 +68,10 @@ export const formSchema: FormSchema[] = [ |
63 | 68 | label: '配置名称', |
64 | 69 | required: true, |
65 | 70 | component: 'Input', |
71 | + componentProps: { | |
72 | + maxLength: 255, | |
73 | + placeholder: '请输入配置名称', | |
74 | + }, | |
66 | 75 | }, |
67 | 76 | { |
68 | 77 | field: 'messageType', |
... | ... | @@ -98,6 +107,11 @@ export const formSchema: FormSchema[] = [ |
98 | 107 | label: 'accessKeyId', |
99 | 108 | required: true, |
100 | 109 | component: 'Input', |
110 | + componentProps: { | |
111 | + maxLength: 36, | |
112 | + placeholder: '请输入accessKeyId', | |
113 | + }, | |
114 | + | |
101 | 115 | ifShow: ({ values }) => isMessage(Reflect.get(values, 'messageType')), |
102 | 116 | }, |
103 | 117 | { |
... | ... | @@ -105,6 +119,11 @@ export const formSchema: FormSchema[] = [ |
105 | 119 | label: 'accessKeySecret', |
106 | 120 | required: true, |
107 | 121 | component: 'Input', |
122 | + componentProps: { | |
123 | + maxLength: 36, | |
124 | + placeholder: '请输入accessKeySecret', | |
125 | + }, | |
126 | + | |
108 | 127 | ifShow: ({ values }) => isMessage(Reflect.get(values, 'messageType')), |
109 | 128 | }, |
110 | 129 | { |
... | ... | @@ -113,6 +132,11 @@ export const formSchema: FormSchema[] = [ |
113 | 132 | defaultValue: 'smtp.163.com', |
114 | 133 | required: true, |
115 | 134 | component: 'Input', |
135 | + componentProps: { | |
136 | + maxLength: 36, | |
137 | + placeholder: '请输入accessKeySecret', | |
138 | + }, | |
139 | + | |
116 | 140 | ifShow: ({ values }) => isEmail(Reflect.get(values, 'messageType')), |
117 | 141 | }, |
118 | 142 | { |
... | ... | @@ -121,6 +145,12 @@ export const formSchema: FormSchema[] = [ |
121 | 145 | defaultValue: 25, |
122 | 146 | required: true, |
123 | 147 | component: 'InputNumber', |
148 | + rules: numberRule, | |
149 | + componentProps: { | |
150 | + maxLength: 36, | |
151 | + placeholder: '请输入端口', | |
152 | + }, | |
153 | + | |
124 | 154 | ifShow: ({ values }) => isEmail(Reflect.get(values, 'messageType')), |
125 | 155 | }, |
126 | 156 | { |
... | ... | @@ -128,6 +158,11 @@ export const formSchema: FormSchema[] = [ |
128 | 158 | label: '用户名', |
129 | 159 | required: true, |
130 | 160 | component: 'Input', |
161 | + componentProps: { | |
162 | + maxLength: 255, | |
163 | + placeholder: '请输入用户名', | |
164 | + }, | |
165 | + | |
131 | 166 | ifShow: ({ values }) => isEmail(Reflect.get(values, 'messageType')), |
132 | 167 | }, |
133 | 168 | { |
... | ... | @@ -142,12 +177,46 @@ export const formSchema: FormSchema[] = [ |
142 | 177 | label: '消息配置', |
143 | 178 | component: 'Input', |
144 | 179 | show: false, |
180 | + componentProps: { | |
181 | + maxLength: 255, | |
182 | + placeholder: '请输入消息配置', | |
183 | + }, | |
184 | + dynamicRules: () => { | |
185 | + return [ | |
186 | + { | |
187 | + required: false, | |
188 | + validator: (_, value) => { | |
189 | + if (String(value).length > 255) { | |
190 | + return Promise.reject('字数不超过255个字'); | |
191 | + } | |
192 | + return Promise.resolve(); | |
193 | + }, | |
194 | + }, | |
195 | + ]; | |
196 | + }, | |
145 | 197 | }, |
146 | 198 | { |
147 | 199 | field: 'id', |
148 | 200 | label: '主键', |
149 | 201 | component: 'Input', |
150 | 202 | show: false, |
203 | + componentProps: { | |
204 | + maxLength: 36, | |
205 | + placeholder: '请输入主键', | |
206 | + }, | |
207 | + dynamicRules: () => { | |
208 | + return [ | |
209 | + { | |
210 | + required: false, | |
211 | + validator: (_, value) => { | |
212 | + if (String(value).length > 36) { | |
213 | + return Promise.reject('字数不超过36个字'); | |
214 | + } | |
215 | + return Promise.resolve(); | |
216 | + }, | |
217 | + }, | |
218 | + ]; | |
219 | + }, | |
151 | 220 | }, |
152 | 221 | { |
153 | 222 | field: 'status', |
... | ... | @@ -165,5 +234,22 @@ export const formSchema: FormSchema[] = [ |
165 | 234 | label: '备注', |
166 | 235 | field: 'remark', |
167 | 236 | component: 'InputTextArea', |
237 | + componentProps: { | |
238 | + maxLength: 255, | |
239 | + placeholder: '请输入备注', | |
240 | + }, | |
241 | + dynamicRules: () => { | |
242 | + return [ | |
243 | + { | |
244 | + required: false, | |
245 | + validator: (_, value) => { | |
246 | + if (String(value).length > 255) { | |
247 | + return Promise.reject('字数不超过255个字'); | |
248 | + } | |
249 | + return Promise.resolve(); | |
250 | + }, | |
251 | + }, | |
252 | + ]; | |
253 | + }, | |
168 | 254 | }, |
169 | 255 | ]; | ... | ... |
... | ... | @@ -21,65 +21,69 @@ |
21 | 21 | /></TabPane> |
22 | 22 | <TabPane key="3" tab="报警规则"> |
23 | 23 | <div style="padding-top: 10px"> |
24 | - <div style="border-radius: 10px; border: 1px solid grey"> | |
25 | - <BasicForm | |
26 | - :showSubmitButton="false" | |
27 | - :showResetButton="false" | |
28 | - @register="registerStep3Schemas" | |
29 | - /> | |
30 | - <BasicForm | |
31 | - :showSubmitButton="false" | |
32 | - :showResetButton="false" | |
33 | - @register="registerStep3HighSetting" | |
34 | - /> | |
35 | - <BasicForm | |
36 | - :showSubmitButton="false" | |
37 | - :showResetButton="false" | |
38 | - @register="registerStep3CreateAlarm" | |
39 | - /> | |
40 | - <BasicForm | |
41 | - :showSubmitButton="false" | |
42 | - :showResetButton="false" | |
43 | - @register="registerStep3RuleAlarm" | |
44 | - /> | |
45 | - <BasicForm | |
46 | - :showSubmitButton="false" | |
47 | - :showResetButton="false" | |
48 | - @register="registerStep3Condition" | |
49 | - /> | |
50 | - <BasicForm | |
51 | - :showSubmitButton="false" | |
52 | - :showResetButton="false" | |
53 | - @register="registerStep3Enable" | |
54 | - /> | |
55 | - <BasicForm | |
56 | - :showSubmitButton="false" | |
57 | - :showResetButton="false" | |
58 | - @register="registerStep3TemplateDetail" | |
59 | - /> | |
24 | + <div style="border-radius: 10px; border: 1px solid #f0f0f0"> | |
25 | + <div style="margin-left: 15px"> | |
26 | + <BasicForm | |
27 | + :showSubmitButton="false" | |
28 | + :showResetButton="false" | |
29 | + @register="registerStep3Schemas" | |
30 | + /> | |
31 | + <BasicForm | |
32 | + :showSubmitButton="false" | |
33 | + :showResetButton="false" | |
34 | + @register="registerStep3HighSetting" | |
35 | + /> | |
36 | + <BasicForm | |
37 | + :showSubmitButton="false" | |
38 | + :showResetButton="false" | |
39 | + @register="registerStep3CreateAlarm" | |
40 | + /> | |
41 | + <BasicForm | |
42 | + :showSubmitButton="false" | |
43 | + :showResetButton="false" | |
44 | + @register="registerStep3RuleAlarm" | |
45 | + /> | |
46 | + <BasicForm | |
47 | + :showSubmitButton="false" | |
48 | + :showResetButton="false" | |
49 | + @register="registerStep3Condition" | |
50 | + /> | |
51 | + <BasicForm | |
52 | + :showSubmitButton="false" | |
53 | + :showResetButton="false" | |
54 | + @register="registerStep3Enable" | |
55 | + /> | |
56 | + <BasicForm | |
57 | + :showSubmitButton="false" | |
58 | + :showResetButton="false" | |
59 | + @register="registerStep3TemplateDetail" | |
60 | + /> | |
61 | + </div> | |
60 | 62 | </div> |
61 | - <div style="border-radius: 10px; border: 1px solid grey; margin-top: 15px"> | |
63 | + <div style="border-radius: 10px; border: 1px solid #f0f0f0; margin-top: 15px"> | |
62 | 64 | <p>清除报警规则</p> |
63 | - <BasicForm | |
64 | - :showSubmitButton="false" | |
65 | - :showResetButton="false" | |
66 | - @register="registerStep3ClearRuleAlarm" | |
67 | - /> | |
68 | - <BasicForm | |
69 | - :showSubmitButton="false" | |
70 | - :showResetButton="false" | |
71 | - @register="registerStep3ClearCondition" | |
72 | - /> | |
73 | - <BasicForm | |
74 | - :showSubmitButton="false" | |
75 | - :showResetButton="false" | |
76 | - @register="registerStep3ClearEnable" | |
77 | - /> | |
78 | - <BasicForm | |
79 | - :showSubmitButton="false" | |
80 | - :showResetButton="false" | |
81 | - @register="registerStep3ClearTemplateDetail" | |
82 | - /> | |
65 | + <div style="margin-left: 15px"> | |
66 | + <BasicForm | |
67 | + :showSubmitButton="false" | |
68 | + :showResetButton="false" | |
69 | + @register="registerStep3ClearRuleAlarm" | |
70 | + /> | |
71 | + <BasicForm | |
72 | + :showSubmitButton="false" | |
73 | + :showResetButton="false" | |
74 | + @register="registerStep3ClearCondition" | |
75 | + /> | |
76 | + <BasicForm | |
77 | + :showSubmitButton="false" | |
78 | + :showResetButton="false" | |
79 | + @register="registerStep3ClearEnable" | |
80 | + /> | |
81 | + <BasicForm | |
82 | + :showSubmitButton="false" | |
83 | + :showResetButton="false" | |
84 | + @register="registerStep3ClearTemplateDetail" | |
85 | + /> | |
86 | + </div> | |
83 | 87 | </div> |
84 | 88 | </div> |
85 | 89 | </TabPane> |
... | ... | @@ -93,7 +97,7 @@ |
93 | 97 | <script lang="ts"> |
94 | 98 | import { defineComponent, ref, computed, watch } from 'vue'; |
95 | 99 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
96 | - import { Tabs, TabPane } from 'ant-design-vue'; | |
100 | + import { Tabs } from 'ant-design-vue'; | |
97 | 101 | import { deviceConfigGetDetail } from '/@/api/device/deviceConfigApi'; |
98 | 102 | import { BasicForm, useForm } from '/@/components/Form/index'; |
99 | 103 | import { |
... | ... | @@ -116,14 +120,14 @@ |
116 | 120 | |
117 | 121 | export default defineComponent({ |
118 | 122 | name: 'ConfigDrawer', |
119 | - components: { Tabs, TabPane, BasicModal, BasicForm }, | |
123 | + components: { Tabs, TabPane: Tabs.TabPane, BasicModal, BasicForm }, | |
120 | 124 | emits: ['success', 'register'], |
121 | 125 | setup() { |
122 | 126 | const activeKey = ref('1'); |
123 | 127 | const isUpdate = ref(true); |
124 | 128 | const descInfo: any = ref(null); |
125 | 129 | const dataInfo: any = ref(''); |
126 | - const [registerDetail, { setFieldsValue: setRegisterDetail }] = useForm({ | |
130 | + const [registerDetail, { resetFields, setFieldsValue: setRegisterDetail }] = useForm({ | |
127 | 131 | schemas: step1Schemas, |
128 | 132 | actionColOptions: { |
129 | 133 | span: 24, |
... | ... | @@ -219,8 +223,10 @@ |
219 | 223 | const [register] = useModalInner(async (data) => { |
220 | 224 | activeKey.value = '1'; |
221 | 225 | isUpdate.value = !!data?.isUpdate; |
222 | - descInfo.value = await deviceConfigGetDetail(data.record.id); | |
226 | + const getV = await deviceConfigGetDetail(data.record.id); | |
227 | + descInfo.value = getV; | |
223 | 228 | try { |
229 | + resetFields(); | |
224 | 230 | await setRegisterDetail({ ...descInfo.value }); |
225 | 231 | } catch (e) { |
226 | 232 | return e; |
... | ... | @@ -229,84 +235,90 @@ |
229 | 235 | const handleChange = (v) => { |
230 | 236 | try { |
231 | 237 | switch (v) { |
232 | - case '1': | |
233 | - setRegisterDetail({ ...descInfo.value }); | |
234 | - break; | |
238 | + // case '1': | |
239 | + // setRegisterDetail({ ...descInfo.value }); | |
240 | + // break; | |
235 | 241 | case '2': |
236 | 242 | setRegisterTrans({ |
237 | 243 | transportType: descInfo.value.profileData?.transportConfiguration.type, |
238 | 244 | }); |
239 | 245 | break; |
240 | 246 | case '3': |
241 | - setRegisterStep3Schemas({ | |
242 | - alarmType: descInfo.value.profileData?.alarms[0].alarmType, | |
243 | - }); | |
244 | - setRegisterStep3HighSetting({ | |
245 | - propagate: descInfo.value.profileData?.alarms[0].propagate, | |
246 | - propagateRelationTypes: | |
247 | - descInfo.value.profileData?.alarms[0].propagateRelationTypes, | |
248 | - }); | |
249 | - const getKey = Object.keys(descInfo.value.profileData?.alarms[0].createRules); | |
250 | - setRegisterStep3CreateAlarm({ | |
251 | - default: getKey[0], | |
252 | - }); | |
253 | - setRegisterStep3RuleAlarm({ | |
254 | - type: descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
255 | - .condition[0].key.type, | |
256 | - key1: descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
257 | - .condition[0].key.key, | |
258 | - type1: | |
259 | - descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
260 | - .condition[0].valueType, | |
261 | - value1: | |
262 | - descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
263 | - .condition[0].predicate.value.defaultValue, | |
264 | - operation: | |
265 | - descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
266 | - .condition[0].predicate.operation, | |
267 | - }); | |
268 | - setRegisterStep3Condition({ | |
269 | - conditionType: | |
270 | - descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition.spec.type, | |
271 | - }); | |
272 | - setRegisterStep3Enable({ | |
273 | - schedule: | |
274 | - descInfo.value.profileData?.alarms[0].createRules[getKey[0]].schedule.type, | |
275 | - }); | |
276 | - setRegisterStep3TemplateDetail({ | |
277 | - alarmDetails: | |
278 | - descInfo.value.profileData?.alarms[0].createRules[getKey[0]].alarmDetails, | |
279 | - }); | |
280 | - //清楚报警 | |
281 | - setRegisterStep3ClearRuleAlarm({ | |
282 | - type: descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0].key | |
283 | - .type, | |
284 | - key1: descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0].key | |
285 | - .key, | |
286 | - type1: | |
287 | - descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0].valueType, | |
288 | - value1: | |
289 | - descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0].predicate | |
290 | - .value.defaultValue, | |
291 | - operation: | |
292 | - descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0].predicate | |
293 | - .operation, | |
294 | - }); | |
295 | - setRegisterStep3ClearCondition({ | |
296 | - conditionType: descInfo.value.profileData?.alarms[0].clearRule.condition.spec.type, | |
297 | - }); | |
298 | - setRegisterStep3ClearEnable({ | |
299 | - schedule: descInfo.value.profileData?.alarms[0].clearRule.schedule.type, | |
300 | - }); | |
301 | - setRegisterStep3ClearTemplateDetail({ | |
302 | - alarmDetails: descInfo.value.profileData?.alarms[0].clearRule.alarmDetails, | |
303 | - }); | |
304 | - break; | |
247 | + setTimeout(() => { | |
248 | + setRegisterStep3Schemas({ | |
249 | + alarmType: descInfo.value.profileData?.alarms[0]?.alarmType, | |
250 | + }); | |
251 | + setRegisterStep3HighSetting({ | |
252 | + propagate: descInfo.value.profileData?.alarms[0]?.propagate, | |
253 | + propagateRelationTypes: | |
254 | + descInfo.value.profileData?.alarms[0]?.propagateRelationTypes, | |
255 | + }); | |
256 | + const getKey = Object.keys(descInfo.value.profileData?.alarms[0]?.createRules); | |
257 | + setRegisterStep3CreateAlarm({ | |
258 | + default: getKey[0], | |
259 | + }); | |
260 | + setRegisterStep3RuleAlarm({ | |
261 | + type: descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
262 | + .condition[0].key.type, | |
263 | + key1: descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
264 | + .condition[0].key.key, | |
265 | + type1: | |
266 | + descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
267 | + .condition[0].valueType, | |
268 | + value1: | |
269 | + descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
270 | + .condition[0].predicate.value.defaultValue, | |
271 | + operation: | |
272 | + descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition | |
273 | + .condition[0].predicate.operation, | |
274 | + }); | |
275 | + setRegisterStep3Condition({ | |
276 | + conditionType: | |
277 | + descInfo.value.profileData?.alarms[0].createRules[getKey[0]].condition.spec | |
278 | + .type, | |
279 | + }); | |
280 | + setRegisterStep3Enable({ | |
281 | + schedule: | |
282 | + descInfo.value.profileData?.alarms[0].createRules[getKey[0]].schedule.type, | |
283 | + }); | |
284 | + setRegisterStep3TemplateDetail({ | |
285 | + alarmDetails: | |
286 | + descInfo.value.profileData?.alarms[0].createRules[getKey[0]].alarmDetails, | |
287 | + }); | |
288 | + //清除报警 | |
289 | + setRegisterStep3ClearRuleAlarm({ | |
290 | + type: descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0].key | |
291 | + .type, | |
292 | + key1: descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0].key | |
293 | + .key, | |
294 | + type1: | |
295 | + descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0] | |
296 | + .valueType, | |
297 | + value1: | |
298 | + descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0].predicate | |
299 | + .value.defaultValue, | |
300 | + operation: | |
301 | + descInfo.value.profileData?.alarms[0].clearRule.condition.condition[0].predicate | |
302 | + .operation, | |
303 | + }); | |
304 | + setRegisterStep3ClearCondition({ | |
305 | + conditionType: | |
306 | + descInfo.value.profileData?.alarms[0].clearRule.condition.spec.type, | |
307 | + }); | |
308 | + setRegisterStep3ClearEnable({ | |
309 | + schedule: descInfo.value.profileData?.alarms[0].clearRule.schedule.type, | |
310 | + }); | |
311 | + setRegisterStep3ClearTemplateDetail({ | |
312 | + alarmDetails: descInfo.value.profileData?.alarms[0].clearRule.alarmDetails, | |
313 | + }); | |
314 | + }, 1000); | |
305 | 315 | case '4': |
306 | - setRegisterContact({ | |
307 | - alarmContactId: descInfo.value.alarmProfile.alarmContactId, | |
308 | - messageMode: descInfo.value.alarmProfile.messageMode, | |
309 | - }); | |
316 | + setTimeout(() => { | |
317 | + setRegisterContact({ | |
318 | + alarmContactId: descInfo.value?.alarmProfile?.alarmContactId, | |
319 | + messageMode: descInfo.value?.alarmProfile?.messageMode, | |
320 | + }); | |
321 | + }, 1000); | |
310 | 322 | break; |
311 | 323 | } |
312 | 324 | } catch (e) { | ... | ... |
... | ... | @@ -45,12 +45,12 @@ |
45 | 45 | </BasicTable> |
46 | 46 | <DeviceProfileModal v-if="isJudgeStatus" @register="registerModal" @success="handleSuccess" /> |
47 | 47 | <DeviceConfigDetail @register="registerModalDetail" @success="handleSuccess" /> |
48 | - <ExpExcelModal @register="register1" @success="defaultHeader" /> | |
48 | + <!-- <ExpExcelModal @register="register1" @success="defaultHeader" /> --> | |
49 | 49 | </div> |
50 | 50 | </template> |
51 | 51 | <script lang="ts"> |
52 | 52 | import { defineComponent, ref, reactive } from 'vue'; |
53 | - import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
53 | + import { BasicTable, useTable, TableAction, BasicColumn } from '/@/components/Table'; | |
54 | 54 | import { columns, searchFormSchema } from './device.profile.data'; |
55 | 55 | import { useMessage } from '/@/hooks/web/useMessage'; |
56 | 56 | import { deviceConfigGetQuery, deviceConfigDelete } from '/@/api/device/deviceConfigApi'; |
... | ... | @@ -58,7 +58,7 @@ |
58 | 58 | import DeviceProfileModal from '/@/views/device/profile/DeviceProfileModal.vue'; |
59 | 59 | import DeviceConfigDetail from '/@/views/device/profile/deviceConfigDetail.vue'; |
60 | 60 | import { ImpExcel, ExcelData } from '/@/components/Excel'; |
61 | - import { jsonToSheetXlsx, ExportModalResult } from '/@/components/Excel'; | |
61 | + // import { jsonToSheetXlsx, ExportModalResult } from '/@/components/Excel'; | |
62 | 62 | |
63 | 63 | export default defineComponent({ |
64 | 64 | name: 'DeviceProfileManagement', |
... | ... | @@ -156,23 +156,23 @@ |
156 | 156 | isJudgeStatus.value = false; |
157 | 157 | } |
158 | 158 | |
159 | - function defaultHeader({ filename, bookType }: ExportModalResult) { | |
160 | - // 默认Object.keys(data[0])作为header | |
161 | - jsonToSheetXlsx({ | |
162 | - data, | |
163 | - filename, | |
164 | - write2excelOpts: { | |
165 | - bookType, | |
166 | - }, | |
167 | - }); | |
168 | - } | |
159 | + // function defaultHeader({ filename, bookType }: ExportModalResult) { | |
160 | + // // 默认Object.keys(data[0])作为header | |
161 | + // jsonToSheetXlsx({ | |
162 | + // data, | |
163 | + // filename, | |
164 | + // write2excelOpts: { | |
165 | + // bookType, | |
166 | + // }, | |
167 | + // }); | |
168 | + // } | |
169 | 169 | |
170 | - const [register1, { openModal: openModalExcel }] = useModal(); | |
170 | + // const [register1, { openModal: openModalExcel }] = useModal(); | |
171 | 171 | const handleExport = (record: Recordable) => { |
172 | 172 | console.log(record); |
173 | - setTimeout(() => { | |
174 | - openModalExcel(); | |
175 | - }, 50); | |
173 | + // setTimeout(() => { | |
174 | + // openModalExcel(); | |
175 | + // }, 50); | |
176 | 176 | }; |
177 | 177 | function handleImport() { |
178 | 178 | console.log('record'); |
... | ... | @@ -182,8 +182,8 @@ |
182 | 182 | } |
183 | 183 | return { |
184 | 184 | registerModalDetail, |
185 | - register1, | |
186 | - defaultHeader, | |
185 | + // register1, | |
186 | + // defaultHeader, | |
187 | 187 | useSelectionChange, |
188 | 188 | handleTableDel, |
189 | 189 | isJudgeStatus, | ... | ... |
1 | 1 | <template> |
2 | 2 | <div class="step1"> |
3 | 3 | <div class="step1-form"> |
4 | + <div | |
5 | + style=" | |
6 | + width: 12vw; | |
7 | + height: 24vh; | |
8 | + margin-left: 25px; | |
9 | + display: flex; | |
10 | + justify-content: space-between; | |
11 | + align-items: center; | |
12 | + " | |
13 | + > | |
14 | + <div style="width: 4vw; height: 24vh">请上传图片</div> | |
15 | + <div style="width: 8vw; height: 24vh"> | |
16 | + <Upload | |
17 | + style="width: 20vw" | |
18 | + name="avatar" | |
19 | + list-type="picture-card" | |
20 | + class="avatar-uploader" | |
21 | + :show-upload-list="false" | |
22 | + :customRequest="customUploadqrcodePic" | |
23 | + :before-upload="beforeUploadqrcodePic" | |
24 | + > | |
25 | + <img | |
26 | + style="text-align: center; border-radius: 50%; width: 10vw; height: 15vh" | |
27 | + v-if="peresonalPic" | |
28 | + :src="peresonalPic" | |
29 | + alt="avatar" | |
30 | + /> | |
31 | + <div v-else> | |
32 | + <div style="margin-top: 30px"> | |
33 | + <PlusOutlined style="font-size: 30px" /> | |
34 | + </div> | |
35 | + <div | |
36 | + class="ant-upload-text flex" | |
37 | + style="width: 280px; height: 130px; align-items: center" | |
38 | + > | |
39 | + 支持.PNG、.JPG、.JPEG格式,建议大小不超过2M。</div | |
40 | + > | |
41 | + </div> | |
42 | + </Upload> | |
43 | + </div> | |
44 | + </div> | |
4 | 45 | <BasicForm @register="register" /> |
5 | 46 | </div> |
6 | 47 | </div> |
7 | 48 | </template> |
8 | 49 | <script lang="ts"> |
9 | - import { defineComponent } from 'vue'; | |
50 | + import { defineComponent, ref } from 'vue'; | |
10 | 51 | import { BasicForm, useForm } from '/@/components/Form'; |
11 | 52 | import { step1Schemas } from './data'; |
12 | 53 | import { Select, Input, Divider } from 'ant-design-vue'; |
54 | + import { uploadApi } from '/@/api/personal/index'; | |
55 | + import { Upload } from 'ant-design-vue'; | |
56 | + import { PlusOutlined } from '@ant-design/icons-vue'; | |
57 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
58 | + import type { FileItem } from '/@/components/Upload/src/typing'; | |
13 | 59 | |
14 | 60 | export default defineComponent({ |
15 | 61 | components: { |
... | ... | @@ -18,9 +64,13 @@ |
18 | 64 | [Input.name]: Input, |
19 | 65 | [Input.Group.name]: Input.Group, |
20 | 66 | [Divider.name]: Divider, |
67 | + Upload, | |
68 | + PlusOutlined, | |
21 | 69 | }, |
22 | 70 | emits: ['next', 'resetFunc'], |
23 | 71 | setup(_, { emit }) { |
72 | + const { createMessage } = useMessage(); | |
73 | + | |
24 | 74 | const [register, { validate, setFieldsValue, resetFields }] = useForm({ |
25 | 75 | labelWidth: 100, |
26 | 76 | schemas: step1Schemas, |
... | ... | @@ -36,16 +86,59 @@ |
36 | 86 | const resetFieldsFunc = (v) => { |
37 | 87 | setFieldsValue(v); |
38 | 88 | }; |
89 | + const peresonalPic = ref(); | |
90 | + | |
91 | + const resetIconFunc = () => { | |
92 | + peresonalPic.value = ''; | |
93 | + }; | |
94 | + | |
95 | + const editIconFunc = (v) => { | |
96 | + peresonalPic.value = v; | |
97 | + }; | |
98 | + | |
99 | + const customUploadqrcodePic = async ({ file }) => { | |
100 | + if (beforeUploadqrcodePic(file)) { | |
101 | + const formData = new FormData(); | |
102 | + formData.append('file', file); | |
103 | + const response = await uploadApi(formData); | |
104 | + if (response.fileStaticUri) { | |
105 | + peresonalPic.value = response.fileStaticUri; | |
106 | + } | |
107 | + } | |
108 | + }; | |
109 | + | |
110 | + const beforeUploadqrcodePic = (file: FileItem) => { | |
111 | + const isJpgOrPng = | |
112 | + file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg'; | |
113 | + if (!isJpgOrPng) { | |
114 | + createMessage.error('只能上传图片文件!'); | |
115 | + } | |
116 | + const isLt2M = (file.size as number) / 1024 / 1024 < 2; | |
117 | + if (!isLt2M) { | |
118 | + createMessage.error('图片大小不能超过5MB!'); | |
119 | + } | |
120 | + return isJpgOrPng && isLt2M; | |
121 | + }; | |
39 | 122 | async function customSubmitFunc() { |
40 | 123 | try { |
41 | 124 | const values = await validate(); |
42 | - emit('next', values); | |
125 | + emit('next', values, peresonalPic.value); | |
43 | 126 | } catch (error) {} |
44 | 127 | } |
45 | 128 | const customResetFunc = async () => { |
46 | 129 | await resetFields(); |
47 | 130 | }; |
48 | - return { register, resetFieldsFunc, customResetFunc }; | |
131 | + return { | |
132 | + editIconFunc, | |
133 | + resetIconFunc, | |
134 | + register, | |
135 | + resetFieldsFunc, | |
136 | + customResetFunc, | |
137 | + uploadApi, | |
138 | + peresonalPic, | |
139 | + beforeUploadqrcodePic, | |
140 | + customUploadqrcodePic, | |
141 | + }; | |
49 | 142 | }, |
50 | 143 | }); |
51 | 144 | </script> | ... | ... |
... | ... | @@ -31,7 +31,7 @@ |
31 | 31 | <template v-for="(childItem, createIndex) in item.alarms" :key="childItem.id"> |
32 | 32 | <div class="aic" style="border: 1px solid #bfbfbf"> |
33 | 33 | <div class="w-3/4"> |
34 | - <div style="margin-left: -30px; margin-top: 20px" | |
34 | + <div style="margin-left: -33px; margin-top: 20px" | |
35 | 35 | ><BasicForm @register="registerFormCreateAlarm" /> |
36 | 36 | </div> |
37 | 37 | <div style="margin-left: 5px; margin-top: -50px"> |
... | ... | @@ -78,7 +78,7 @@ |
78 | 78 | <div style="height: 20px"></div> |
79 | 79 | <p>清除报警规则</p> |
80 | 80 | <template |
81 | - v-for="(childClearItem, clearIndexItem) in item.alarms[clearIndex].clearRule" | |
81 | + v-for="(childClearItem, clearIndexItem) in item.clearRule" | |
82 | 82 | :key="childClearItem.id" |
83 | 83 | > |
84 | 84 | <div class="aic mb-1" style="border: 1px solid #bfbfbf"> |
... | ... | @@ -222,12 +222,20 @@ |
222 | 222 | const ruleClearTemplateData: any = ref(null); |
223 | 223 | const enableClearTemplateData: any = ref(null); |
224 | 224 | const detailClearTemplateData: any = ref(null); |
225 | + const scheduleCustomValue: any = ref({}); | |
226 | + const scheduleCustomClearValue: any = ref({}); | |
225 | 227 | const clearIndex = ref(-1); |
228 | + const getSchduleCustomValue: any = ref([]); | |
229 | + const getSchduleClearCustomValue: any = ref([]); | |
226 | 230 | //告警列表 |
227 | 231 | let profileData = ref<IProfileData[]>([]); |
228 | 232 | const log = (e) => { |
229 | 233 | console.log(e); |
230 | 234 | }; |
235 | + //编辑清空操作 | |
236 | + const clearProfileDataFunc = () => { | |
237 | + unref(profileData).splice(0, 1); | |
238 | + }; | |
231 | 239 | //删除告警配置 |
232 | 240 | const deleteAlarmRule = (index: number) => { |
233 | 241 | unref(profileData).splice(index, 1); |
... | ... | @@ -254,26 +262,27 @@ |
254 | 262 | id: Date.now() + Math.random() + '', |
255 | 263 | alarmType: '', |
256 | 264 | createRules: {}, |
257 | - clearRule: [ | |
258 | - { | |
259 | - id: Date.now() + Math.random() + '', | |
260 | - alarmDetails: '', | |
261 | - dashboardId: { | |
262 | - id: '', | |
263 | - entityType: '', | |
264 | - }, | |
265 | - propagate: '', | |
266 | - propagateRelationTypes: [''], | |
267 | - schedule: { | |
268 | - type: 'string', | |
269 | - }, | |
270 | - condition: {}, | |
271 | - }, | |
272 | - ], | |
265 | + | |
273 | 266 | propagate: false, |
274 | 267 | propagateRelationTypes: [''], |
275 | 268 | }, |
276 | 269 | ], |
270 | + clearRule: [ | |
271 | + { | |
272 | + id: Date.now() + Math.random() + '', | |
273 | + alarmDetails: '', | |
274 | + dashboardId: { | |
275 | + id: '', | |
276 | + entityType: '', | |
277 | + }, | |
278 | + propagate: '', | |
279 | + propagateRelationTypes: [''], | |
280 | + schedule: { | |
281 | + type: 'string', | |
282 | + }, | |
283 | + condition: {}, | |
284 | + }, | |
285 | + ], | |
277 | 286 | }); |
278 | 287 | }; |
279 | 288 | //TODO Mobile dashboard: |
... | ... | @@ -342,6 +351,25 @@ |
342 | 351 | const resetRegisterFormCreateAlarmFunc = () => { |
343 | 352 | resetRegisterFormCreateAlarm(); |
344 | 353 | }; |
354 | + const resetRulesFormDataFunc = () => { | |
355 | + ruleTemplateData.value = ``; | |
356 | + }; | |
357 | + const resetEnableFormDataFunc = () => { | |
358 | + enableTemplateData.value = ``; | |
359 | + }; | |
360 | + const resetTemplateFormDataFunc = () => { | |
361 | + detailTemplateData.value = ``; | |
362 | + }; | |
363 | + const resetRulesClearFormDataFunc = () => { | |
364 | + ruleClearTemplateData.value = ``; | |
365 | + }; | |
366 | + const resetEnableClearFormDataFunc = () => { | |
367 | + enableClearTemplateData.value = ``; | |
368 | + }; | |
369 | + const resetTemplateClearFormDataFunc = () => { | |
370 | + detailClearTemplateData.value = ``; | |
371 | + }; | |
372 | + | |
345 | 373 | //回显表单数据 |
346 | 374 | const retryRegisterFormFunc = (v) => { |
347 | 375 | setRegisterForm(v); |
... | ... | @@ -352,6 +380,25 @@ |
352 | 380 | const retryRegisterFormCreateAlarmFunc = (v) => { |
353 | 381 | setRegisterFormCreateAlarm(v); |
354 | 382 | }; |
383 | + const retryRulesFormDataFunc = (v) => { | |
384 | + ruleTemplateData.value = v; | |
385 | + }; | |
386 | + const retryEnableFormDataFunc = (v) => { | |
387 | + enableTemplateData.value = v; | |
388 | + }; | |
389 | + const retryTemplateFormDataFunc = (v) => { | |
390 | + detailTemplateData.value = v; | |
391 | + }; | |
392 | + const retryRulesClearFormDataFunc = (v) => { | |
393 | + ruleClearTemplateData.value = v; | |
394 | + }; | |
395 | + const retryEnableClearFormDataFunc = (v) => { | |
396 | + enableClearTemplateData.value = v; | |
397 | + }; | |
398 | + const retryTemplateClearFormDataFunc = (v) => { | |
399 | + detailClearTemplateData.value = v; | |
400 | + }; | |
401 | + | |
355 | 402 | const tempValue1: string = ref<string>(''); |
356 | 403 | // 添加‘创建条件’ |
357 | 404 | const addCreateRole = (index: number) => { |
... | ... | @@ -400,27 +447,26 @@ |
400 | 447 | }; |
401 | 448 | }, |
402 | 449 | }); |
403 | - | |
404 | 450 | unref(profileData)[index].alarms.push({ |
405 | 451 | id: Date.now() + Math.random() + '', |
406 | 452 | alarmType: '', |
407 | 453 | createRules: {}, |
408 | - clearRule: [ | |
409 | - { | |
410 | - id: Date.now() + Math.random() + '', | |
411 | - alarmDetails: '', | |
412 | - dashboardId: { | |
413 | - id: '', | |
414 | - entityType: '', | |
415 | - }, | |
416 | - propagate: '', | |
417 | - propagateRelationTypes: [''], | |
418 | - schedule: { | |
419 | - type: 'string', | |
420 | - }, | |
421 | - condition: {}, | |
422 | - }, | |
423 | - ], | |
454 | + // clearRule: [ | |
455 | + // { | |
456 | + // id: Date.now() + Math.random() + '', | |
457 | + // alarmDetails: '', | |
458 | + // dashboardId: { | |
459 | + // id: '', | |
460 | + // entityType: '', | |
461 | + // }, | |
462 | + // propagate: '', | |
463 | + // propagateRelationTypes: [''], | |
464 | + // schedule: { | |
465 | + // type: 'string', | |
466 | + // }, | |
467 | + // condition: {}, | |
468 | + // }, | |
469 | + // ], | |
424 | 470 | propagate: false, |
425 | 471 | propagateRelationTypes: [''], |
426 | 472 | }); |
... | ... | @@ -486,12 +532,23 @@ |
486 | 532 | console.log(e); |
487 | 533 | } |
488 | 534 | }); |
535 | + const findDayCustomByValue = findDay.map((f, i) => { | |
536 | + try { | |
537 | + if (f.value == v.daysOfWeek1[i]) { | |
538 | + return f.label; | |
539 | + } | |
540 | + } catch (e) { | |
541 | + console.log(e); | |
542 | + } | |
543 | + }); | |
489 | 544 | enableTemplateData.value = |
490 | - v.startsOn == undefined | |
545 | + v.schedule == 'ANY_TIME' | |
491 | 546 | ? `始终启用` |
492 | - : ` | |
547 | + : v.schedule == 'SPECIFIC_TIME' | |
548 | + ? ` | |
493 | 549 | 开始时间:${v.startsOn},结束时间:${v.endsOn},天数:${findDayByValue} |
494 | - `; | |
550 | + ` | |
551 | + : `天数:${findDayCustomByValue},开始时间: ${v.startsOn1},结束时间:${v.endsOn1}`; | |
495 | 552 | }; |
496 | 553 | //规则条件 |
497 | 554 | const getAllFieldsRuleFunc = (v, v1) => { |
... | ... | @@ -516,7 +573,7 @@ |
516 | 573 | } |
517 | 574 | }); |
518 | 575 | ruleTemplateData.value = ` |
519 | - 键名:${v.key1}...操作:${findRuleByValue?.label}...值:${v.value1} | |
576 | + 键名:${v.key1} 操作:${findRuleByValue?.label} 值:${v.value1} | |
520 | 577 | `; |
521 | 578 | |
522 | 579 | ruleLastObj.value = v1; |
... | ... | @@ -607,11 +664,23 @@ |
607 | 664 | console.log(e); |
608 | 665 | } |
609 | 666 | }); |
667 | + const findDayCustomByValue = findDay.map((f, i) => { | |
668 | + try { | |
669 | + if (f.value == v.daysOfWeek1[i]) { | |
670 | + return f.label; | |
671 | + } | |
672 | + } catch (e) { | |
673 | + console.log(e); | |
674 | + } | |
675 | + }); | |
610 | 676 | enableClearTemplateData.value = |
611 | - v.startsOn == undefined | |
677 | + v.schedule == 'ANY_TIME' | |
612 | 678 | ? `始终启用` |
613 | - : `开始时间:${v.startsOn},结束时间:${v.endsOn},天数:${findDayByValue} | |
614 | - `; | |
679 | + : v.schedule == 'SPECIFIC_TIME' | |
680 | + ? ` | |
681 | + 开始时间:${v.startsOn},结束时间:${v.endsOn},天数:${findDayByValue} | |
682 | + ` | |
683 | + : `天数:${findDayCustomByValue},开始时间: ${v.startsOn1},结束时间:${v.endsOn1}`; | |
615 | 684 | }; |
616 | 685 | //规则条件 |
617 | 686 | const getAllClearFieldsRuleFunc = (v, v1) => { |
... | ... | @@ -636,7 +705,7 @@ |
636 | 705 | } |
637 | 706 | }); |
638 | 707 | ruleClearTemplateData.value = ` |
639 | - 键名:${v.key1}...操作:${findRuleByValue?.label}...值:${v.value1} | |
708 | + 键名:${v.key1} 操作:${findRuleByValue?.label} 值:${v.value1} | |
640 | 709 | `; |
641 | 710 | |
642 | 711 | ruleLastObj.value = v1; |
... | ... | @@ -677,7 +746,7 @@ |
677 | 746 | }; |
678 | 747 | Object.assign(addClearitionalObj.value, getValueConditon); |
679 | 748 | }; |
680 | - //用于生成uuid | |
749 | + //生成uuid | |
681 | 750 | function generateUUID() { |
682 | 751 | let d = new Date().getTime(); |
683 | 752 | if (window.performance && typeof window.performance.now === 'function') { |
... | ... | @@ -691,28 +760,111 @@ |
691 | 760 | return uuid; |
692 | 761 | } |
693 | 762 | const handleFormStep3toStep4Next = async () => { |
763 | + console.log(enableObj.value); | |
694 | 764 | try { |
765 | + if (enableObj.value.schedule == 'CUSTOM') { | |
766 | + for (let i in enableObj.value) { | |
767 | + console.log(enableObj.value[i]); | |
768 | + console.log(i); | |
769 | + // let o = {}; | |
770 | + // if(enableObj.value[i]=='1') | |
771 | + // o[i] = enableObj.value[i]; | |
772 | + // getSchduleCustomValue.value.push(o); | |
773 | + // getSchduleCustomValue.value.push(enableObj.value[i]); | |
774 | + } | |
775 | + console.log(getSchduleCustomValue.value); | |
776 | + // switch (enableObj.value.daysOfWeek1[0]) { | |
777 | + // case '1': | |
778 | + // getSchduleCustomValue.value.push({ | |
779 | + // enabled: true, | |
780 | + // dayOfWeek: enableObj.value.daysOfWeek1[0], | |
781 | + // startsOn: enableObj.value.startsOn1, | |
782 | + // endsOn: enableObj.value.endsOn1, | |
783 | + // }); | |
784 | + // break; | |
785 | + // case '2': | |
786 | + // getSchduleCustomValue.value.push({ | |
787 | + // enabled: true, | |
788 | + // dayOfWeek: enableObj.value.daysOfWeek2[0], | |
789 | + // startsOn: enableObj.value.startsOn2, | |
790 | + // endsOn: enableObj.value.endsOn2, | |
791 | + // }); | |
792 | + // break; | |
793 | + // case '3': | |
794 | + // getSchduleCustomValue.value.push({ | |
795 | + // enabled: true, | |
796 | + // dayOfWeek: enableObj.value.daysOfWeek3[0], | |
797 | + // startsOn: enableObj.value.startsOn3, | |
798 | + // endsOn: enableObj.value.endsOn3, | |
799 | + // }); | |
800 | + // break; | |
801 | + // } | |
802 | + scheduleCustomValue.value = { | |
803 | + type: enableObj.value.schedule, | |
804 | + timezone: enableObj.value.timezone, | |
805 | + items: getSchduleCustomValue.value, | |
806 | + }; | |
807 | + } | |
808 | + //清除报警规则---报警日程表 | |
809 | + if (enableClearObj.value.schedule == 'CUSTOM') { | |
810 | + switch (enableClearObj.value.daysOfWeek1[0]) { | |
811 | + case '1': | |
812 | + getSchduleClearCustomValue.value.push({ | |
813 | + enabled: true, | |
814 | + dayOfWeek: enableClearObj.value.daysOfWeek1[0], | |
815 | + startsOn: enableClearObj.value.startsOn1, | |
816 | + endsOn: enableClearObj.value.endsOn1, | |
817 | + }); | |
818 | + break; | |
819 | + case '2': | |
820 | + getSchduleClearCustomValue.value.push({ | |
821 | + enabled: true, | |
822 | + dayOfWeek: enableClearObj.value.daysOfWeek2[0], | |
823 | + startsOn: enableClearObj.value.startsOn2, | |
824 | + endsOn: enableClearObj.value.endsOn2, | |
825 | + }); | |
826 | + break; | |
827 | + case '3': | |
828 | + getSchduleClearCustomValue.value.push({ | |
829 | + enabled: true, | |
830 | + dayOfWeek: enableClearObj.value.daysOfWeek3[0], | |
831 | + startsOn: enableClearObj.value.startsOn3, | |
832 | + endsOn: enableClearObj.value.endsOn3, | |
833 | + }); | |
834 | + break; | |
835 | + } | |
836 | + scheduleCustomClearValue.value = { | |
837 | + type: enableClearObj.value.schedule, | |
838 | + timezone: enableClearObj.value.timezone, | |
839 | + items: getSchduleClearCustomValue.value, | |
840 | + }; | |
841 | + } | |
695 | 842 | const scheduleClearValue = { |
696 | 843 | type: enableClearObj.value.schedule, |
697 | 844 | daysOfWeek: enableClearObj.value.daysOfWeek, |
698 | - // endsOn: enableClearObj.value.endsOn, | |
699 | - // startsOn: enableClearObj.value.startOn, | |
845 | + endsOn: enableClearObj.value.endsOn, | |
846 | + startsOn: enableClearObj.value.startOn, | |
700 | 847 | timezone: enableClearObj.value.timezone, |
701 | 848 | }; |
702 | 849 | const getClearSchedule = { |
703 | - schedule: scheduleClearValue, | |
850 | + schedule: | |
851 | + enableClearObj.value.schedule == 'CUSTOM' | |
852 | + ? scheduleCustomClearValue.value | |
853 | + : scheduleClearValue, | |
704 | 854 | }; |
705 | 855 | const getClearAdditionalProp = Object.assign({}, detailClearObj.value, getClearSchedule); |
706 | 856 | const scheduleValue = { |
707 | 857 | type: enableObj.value.schedule, |
708 | 858 | daysOfWeek: enableObj.value.daysOfWeek, |
709 | - // endsOn: enableObj.value.endsOn, | |
710 | - // startsOn: enableObj.value.startOn, | |
859 | + endsOn: enableObj.value.endsOn, | |
860 | + startsOn: enableObj.value.startOn, | |
711 | 861 | timezone: enableObj.value.timezone, |
712 | 862 | }; |
713 | 863 | const getSchedule = { |
714 | - schedule: scheduleValue, | |
864 | + schedule: | |
865 | + enableObj.value.schedule == 'CUSTOM' ? scheduleCustomValue.value : scheduleValue, | |
715 | 866 | }; |
867 | + | |
716 | 868 | const getAdditionalProp = Object.assign({}, detailObj.value, getSchedule); |
717 | 869 | const getScheduleAndAlarmDetails = Object.assign( |
718 | 870 | {}, |
... | ... | @@ -746,7 +898,7 @@ |
746 | 898 | console.log(valueRegisterFormCreateAlarm); |
747 | 899 | const getValueRegisterFormHighSetting = { |
748 | 900 | propagate: valueRegisterFormHighSetting?.propagate, |
749 | - propagateRelationTypes: [valueRegisterFormHighSetting?.propagateRelationTypes], | |
901 | + propagateRelationTypes: [valueRegisterFormHighSetting?.propagateRelationTypes].flat(1), | |
750 | 902 | }; |
751 | 903 | Object.assign( |
752 | 904 | emptyObj.value, |
... | ... | @@ -756,7 +908,9 @@ |
756 | 908 | getClearRulesAllObj, |
757 | 909 | objectId |
758 | 910 | ); |
759 | - alarmss.value.push(emptyObj.value); | |
911 | + if (alarmss.value.length == 0) { | |
912 | + alarmss.value.push(emptyObj.value); | |
913 | + } | |
760 | 914 | const getAlarms = { |
761 | 915 | alarms: alarmss.value, |
762 | 916 | }; |
... | ... | @@ -795,7 +949,11 @@ |
795 | 949 | isRuleAlarmRuleConditions.value = 4; |
796 | 950 | setTimeout(() => { |
797 | 951 | openModal4(true); |
798 | - proxy.$refs.getChildData1.resetDataFunc(); | |
952 | + try { | |
953 | + proxy.$refs.getChildData1.resetDataFunc(); | |
954 | + } catch (e) { | |
955 | + return e; | |
956 | + } | |
799 | 957 | }, 50); |
800 | 958 | }; |
801 | 959 | const handleOpenClearEnableRule = () => { |
... | ... | @@ -814,6 +972,19 @@ |
814 | 972 | }; |
815 | 973 | |
816 | 974 | return { |
975 | + resetEnableClearFormDataFunc, | |
976 | + resetTemplateClearFormDataFunc, | |
977 | + resetRulesClearFormDataFunc, | |
978 | + resetEnableFormDataFunc, | |
979 | + resetTemplateFormDataFunc, | |
980 | + resetRulesFormDataFunc, | |
981 | + retryEnableClearFormDataFunc, | |
982 | + retryTemplateClearFormDataFunc, | |
983 | + retryRulesClearFormDataFunc, | |
984 | + retryEnableFormDataFunc, | |
985 | + retryTemplateFormDataFunc, | |
986 | + retryRulesFormDataFunc, | |
987 | + clearProfileDataFunc, | |
817 | 988 | clearIndex, |
818 | 989 | retryRegisterFormFunc, |
819 | 990 | retryRegisterFormHighSettingmFunc, | ... | ... |
... | ... | @@ -99,7 +99,7 @@ export const formSchema: FormSchema[] = [ |
99 | 99 | { |
100 | 100 | field: 'conditionType', |
101 | 101 | label: '条件类型', |
102 | - colProps: { span: 24 }, | |
102 | + colProps: { span: 13 }, | |
103 | 103 | component: 'Select', |
104 | 104 | componentProps: { |
105 | 105 | placeholder: '请选择报警日程表', |
... | ... | @@ -177,11 +177,28 @@ export const formSchema: FormSchema[] = [ |
177 | 177 | { |
178 | 178 | field: 'defaultValue', |
179 | 179 | label: '持续时间值', |
180 | - colProps: { span: 24 }, | |
180 | + colProps: { span: 13 }, | |
181 | 181 | component: 'Input', |
182 | 182 | componentProps: { |
183 | + maxLength: 16, | |
183 | 184 | placeholder: '请输入持续时间值(请输入数字)', |
184 | 185 | }, |
186 | + dynamicRules: () => { | |
187 | + return [ | |
188 | + { | |
189 | + validator: (_, value) => { | |
190 | + if (!value) { | |
191 | + return Promise.reject('持续时间值不能为空'); | |
192 | + } | |
193 | + const pwdRegex = new RegExp(/-?\d+/); | |
194 | + if (!pwdRegex.test(value)) { | |
195 | + return Promise.reject('只能为数字,且最长不超过16位'); | |
196 | + } | |
197 | + return Promise.resolve(); | |
198 | + }, | |
199 | + }, | |
200 | + ]; | |
201 | + }, | |
185 | 202 | ifShow: ({ values }) => isWenDu(Reflect.get(values, 'conditionType')), |
186 | 203 | show: ({ values }) => { |
187 | 204 | return !values.field5; |
... | ... | @@ -210,7 +227,7 @@ export const formSchema: FormSchema[] = [ |
210 | 227 | { |
211 | 228 | field: 'unit', |
212 | 229 | label: '时间单位', |
213 | - colProps: { span: 24 }, | |
230 | + colProps: { span: 13 }, | |
214 | 231 | component: 'Select', |
215 | 232 | componentProps: { |
216 | 233 | placeholder: '请选择时间单位', |
... | ... | @@ -226,12 +243,28 @@ export const formSchema: FormSchema[] = [ |
226 | 243 | { |
227 | 244 | field: 'defaultValue', |
228 | 245 | label: '事件计数值必填', |
229 | - colProps: { span: 24 }, | |
246 | + colProps: { span: 13 }, | |
230 | 247 | component: 'Input', |
231 | 248 | componentProps: { |
249 | + maxLength: 2147483637, | |
232 | 250 | placeholder: '请输入事件计数值(应在1到2147483637之间)', |
233 | 251 | }, |
234 | - rules: [{ message: '事件计数应在1到2147483637之间', trigger: 'blur' }], | |
252 | + dynamicRules: () => { | |
253 | + return [ | |
254 | + { | |
255 | + validator: (_, value) => { | |
256 | + if (!value) { | |
257 | + return Promise.reject('事件计数不能为空'); | |
258 | + } | |
259 | + const pwdRegex = new RegExp(/-?\d+/); | |
260 | + if (!pwdRegex.test(value)) { | |
261 | + return Promise.reject('只能为数字,且最长不超过16位'); | |
262 | + } | |
263 | + return Promise.resolve(); | |
264 | + }, | |
265 | + }, | |
266 | + ]; | |
267 | + }, | |
235 | 268 | ifShow: ({ values }) => isTimeAll(Reflect.get(values, 'conditionType')), |
236 | 269 | show: ({ values }) => { |
237 | 270 | return !values.field6; |
... | ... | @@ -240,6 +273,7 @@ export const formSchema: FormSchema[] = [ |
240 | 273 | { |
241 | 274 | field: 'inherit', |
242 | 275 | label: '', |
276 | + colProps: { span: 13 }, | |
243 | 277 | component: 'Checkbox', |
244 | 278 | renderComponentContent: 'Inherit from owner', |
245 | 279 | ifShow: ({ values }) => | ... | ... |