Commit dec40da981ad0b97b0a2235f89ec97abb96bc449

Authored by 1400859700@qq.com
2 parents 37a80607 8484ee22

fix:所有字段验证失效问题

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,12 +6,18 @@ VITE_PUBLIC_PATH = /
6 6
7 # Cross-domain proxy, you can configure multiple 7 # Cross-domain proxy, you can configure multiple
8 # Please note that no line breaks 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 # Delete console 19 # Delete console
14 -VITE_DROP_CONSOLE = false 20 +VITE_DROP_CONSOLE = true
15 21
16 # Basic interface address SPA 22 # Basic interface address SPA
17 VITE_GLOB_API_URL=/api 23 VITE_GLOB_API_URL=/api
@@ -10,26 +10,29 @@ VITE_DROP_CONSOLE = true @@ -10,26 +10,29 @@ VITE_DROP_CONSOLE = true
10 # Whether to enable gzip or brotli compression 10 # Whether to enable gzip or brotli compression
11 # Optional: gzip | brotli | none 11 # Optional: gzip | brotli | none
12 # If you need multiple forms, you can use `,` to separate 12 # If you need multiple forms, you can use `,` to separate
13 -VITE_BUILD_COMPRESS = 'none' 13 +VITE_BUILD_COMPRESS = 'gzip'
14 14
15 # Whether to delete origin files when using compress, default false 15 # Whether to delete origin files when using compress, default false
16 VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false 16 VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
17 17
18 # Basic interface address SPA 18 # Basic interface address SPA
19 -VITE_GLOB_API_URL=/api 19 +VITE_GLOB_API_URL=http://localhost:8080/api
20 20
21 # File upload address, optional 21 # File upload address, optional
22 # It can be forwarded by nginx or write the actual address directly 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 # Interface prefix 25 # Interface prefix
26 -VITE_GLOB_API_URL_PREFIX=/v1 26 +VITE_GLOB_API_URL_PREFIX=/yt
27 27
28 # Whether to enable image compression 28 # Whether to enable image compression
29 -VITE_USE_IMAGEMIN= true 29 +VITE_USE_IMAGEMIN= false
30 30
31 # use pwa 31 # use pwa
32 VITE_USE_PWA = false 32 VITE_USE_PWA = false
33 33
34 # Is it compatible with older browsers 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=
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,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 +};
  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 +};
1 -import { defHttp } from '/@/utils/http/axios';  
2 -  
3 -enum Api {  
4 - // The address does not exist  
5 - Error = '/error',  
6 -}  
7 -  
8 -/**  
9 - * @description: Trigger ajax error  
10 - */  
11 -  
12 -export const fireErrorApi = () => defHttp.get({ url: Api.Error });  
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 import { IPutPersonal } from './model/index'; 2 import { IPutPersonal } from './model/index';
3 import { defHttp } from '/@/utils/http/axios'; 3 import { defHttp } from '/@/utils/http/axios';
4 -import { UploadFileParams } from '/#/axios';  
5 4
6 enum API { 5 enum API {
7 - BaseUploadUrl = '/api/yt/oss/upload', 6 + BaseUploadUrl = '/oss/upload',
8 PutPersonalUrl = '/user/center', 7 PutPersonalUrl = '/user/center',
9 GetPersonalUrl = '/user/', 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 export const personalGet = (id: string) => { 14 export const personalGet = (id: string) => {
1 -export interface UploadApiResult {  
2 - message: string;  
3 - code: number;  
4 - url: string; 1 +export interface FileUploadResponse {
  2 + fileName: string;
  3 + fileDownloadUri: string;
  4 + fileType: string;
  5 + size: number;
  6 + fileStaticUri: string;
5 } 7 }
@@ -17,7 +17,7 @@ enum Api { @@ -17,7 +17,7 @@ enum Api {
17 export const getMenuList = () => { 17 export const getMenuList = () => {
18 const userStore = useUserStore(); 18 const userStore = useUserStore();
19 let url = Api.GetMenuList; 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 url = Api.SysAdminMenuList; 21 url = Api.SysAdminMenuList;
22 } 22 }
23 return defHttp.get<getMenuListResultModel>({ url }); 23 return defHttp.get<getMenuListResultModel>({ url });
@@ -4,13 +4,14 @@ @@ -4,13 +4,14 @@
4 --> 4 -->
5 5
6 <template> 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 <span 10 <span
10 class="ml-2 md:opacity-100" 11 class="ml-2 md:opacity-100"
11 :class="getTitleClass" 12 :class="getTitleClass"
12 v-show="showTitle" 13 v-show="showTitle"
13 - style="white-space: nowrap" 14 + style="white-space: nowrap; font-size: small"
14 > 15 >
15 {{ getTitle }} 16 {{ getTitle }}
16 </span> 17 </span>
@@ -19,10 +20,8 @@ @@ -19,10 +20,8 @@
19 <script lang="ts" setup> 20 <script lang="ts" setup>
20 import { computed, unref } from 'vue'; 21 import { computed, unref } from 'vue';
21 import { useGlobSetting } from '/@/hooks/setting'; 22 import { useGlobSetting } from '/@/hooks/setting';
22 - import { useGo } from '/@/hooks/web/usePage';  
23 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting'; 23 import { useMenuSetting } from '/@/hooks/setting/useMenuSetting';
24 import { useDesign } from '/@/hooks/web/useDesign'; 24 import { useDesign } from '/@/hooks/web/useDesign';
25 - import { PageEnum } from '/@/enums/pageEnum';  
26 import { useUserStore } from '/@/store/modules/user'; 25 import { useUserStore } from '/@/store/modules/user';
27 const props = defineProps({ 26 const props = defineProps({
28 /** 27 /**
@@ -43,7 +42,6 @@ @@ -43,7 +42,6 @@
43 const { getCollapsedShowTitle } = useMenuSetting(); 42 const { getCollapsedShowTitle } = useMenuSetting();
44 const userStore = useUserStore(); 43 const userStore = useUserStore();
45 const { title } = useGlobSetting(); 44 const { title } = useGlobSetting();
46 - const go = useGo();  
47 45
48 const getAppLogoClass = computed(() => [ 46 const getAppLogoClass = computed(() => [
49 prefixCls, 47 prefixCls,
@@ -56,12 +54,8 @@ @@ -56,12 +54,8 @@
56 'xs:opacity-0': !props.alwaysShowTitle, 54 'xs:opacity-0': !props.alwaysShowTitle,
57 }, 55 },
58 ]); 56 ]);
59 -  
60 - function goHome() {  
61 - go(userStore.getUserInfo.homePath || PageEnum.BASE_HOME);  
62 - }  
63 const getLogo = computed(() => { 57 const getLogo = computed(() => {
64 - return userStore.platInfo?.logo ?? '/src/assets/images/logo.png'; 58 + return userStore.platInfo?.logo;
65 }); 59 });
66 const getTitle = computed(() => { 60 const getTitle = computed(() => {
67 // 设置icon 61 // 设置icon
@@ -82,7 +76,6 @@ @@ -82,7 +76,6 @@
82 padding-left: 7px; 76 padding-left: 7px;
83 cursor: pointer; 77 cursor: pointer;
84 transition: all 0.2s ease; 78 transition: all 0.2s ease;
85 -  
86 &.light { 79 &.light {
87 border-bottom: 1px solid @border-color-base; 80 border-bottom: 1px solid @border-color-base;
88 } 81 }
1 export enum RoleEnum { 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 }
  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 +};
@@ -78,6 +78,7 @@ @@ -78,6 +78,7 @@
78 78
79 .ant-badge { 79 .ant-badge {
80 font-size: 18px; 80 font-size: 18px;
  81 + display: none;
81 82
82 .ant-badge-multiple-words { 83 .ant-badge-multiple-words {
83 padding: 0 4px; 84 padding: 0 4px;
1 import { FormSchema } from '/@/components/Table'; 1 import { FormSchema } from '/@/components/Table';
  2 +import { phoneRule, emailRule } from '/@/utils/rules';
2 3
3 export const formSchema: FormSchema[] = [ 4 export const formSchema: FormSchema[] = [
4 { 5 {
5 - field: 'nickName', 6 + field: 'realName',
6 label: '用户昵称', 7 label: '用户昵称',
7 colProps: { span: 13 }, 8 colProps: { span: 13 },
8 required: true, 9 required: true,
@@ -20,6 +21,7 @@ export const formSchema: FormSchema[] = [ @@ -20,6 +21,7 @@ export const formSchema: FormSchema[] = [
20 componentProps: { 21 componentProps: {
21 placeholder: '请输入手机号码', 22 placeholder: '请输入手机号码',
22 }, 23 },
  24 + rules: phoneRule,
23 }, 25 },
24 { 26 {
25 field: 'email', 27 field: 'email',
@@ -30,5 +32,6 @@ export const formSchema: FormSchema[] = [ @@ -30,5 +32,6 @@ export const formSchema: FormSchema[] = [
30 componentProps: { 32 componentProps: {
31 placeholder: '请输入邮箱', 33 placeholder: '请输入邮箱',
32 }, 34 },
  35 + rules: emailRule,
33 }, 36 },
34 ]; 37 ];
1 <template> 1 <template>
2 <BasicModal 2 <BasicModal
3 :useWrapper="true" 3 :useWrapper="true"
4 - width="80vw" 4 + width="82vw"
5 :height="compHeight" 5 :height="compHeight"
6 v-bind="$attrs" 6 v-bind="$attrs"
7 @register="registerModal" 7 @register="registerModal"
@@ -22,15 +22,34 @@ @@ -22,15 +22,34 @@
22 ><p style="font-size: 17px; margin-top: 7px; margin-left: 10px">个人信息</p></div 22 ><p style="font-size: 17px; margin-top: 7px; margin-left: 10px">个人信息</p></div
23 > 23 >
24 <div class="change-avatar" style="text-align: center"> 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 </div> 53 </div>
35 <Description 54 <Description
36 class="mt-8" 55 class="mt-8"
@@ -66,13 +85,13 @@ @@ -66,13 +85,13 @@
66 import { BasicForm, useForm } from '/@/components/Form/index'; 85 import { BasicForm, useForm } from '/@/components/Form/index';
67 import { formSchema } from './config'; 86 import { formSchema } from './config';
68 import { Description, DescItem, useDescription } from '/@/components/Description/index'; 87 import { Description, DescItem, useDescription } from '/@/components/Description/index';
69 - import { CropperAvatar } from '/@/components/Cropper';  
70 - import defaultImage from '/@/assets/images/logo.png';  
71 import { uploadApi, personalPut } from '/@/api/personal/index'; 88 import { uploadApi, personalPut } from '/@/api/personal/index';
72 import { useMessage } from '/@/hooks/web/useMessage'; 89 import { useMessage } from '/@/hooks/web/useMessage';
73 import { USER_INFO_KEY } from '/@/enums/cacheEnum'; 90 import { USER_INFO_KEY } from '/@/enums/cacheEnum';
74 import { getAuthCache } from '/@/utils/auth'; 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 const schema: DescItem[] = [ 96 const schema: DescItem[] = [
78 { 97 {
@@ -102,68 +121,91 @@ @@ -102,68 +121,91 @@
102 ]; 121 ];
103 export default defineComponent({ 122 export default defineComponent({
104 name: 'index', 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 const userInfo = getAuthCache(USER_INFO_KEY); 127 const userInfo = getAuthCache(USER_INFO_KEY);
109 const { createMessage } = useMessage(); 128 const { createMessage } = useMessage();
110 const getPersonalValue: any = ref({}); 129 const getPersonalValue: any = ref({});
111 const getPersonalDetailValue: any = ref({}); 130 const getPersonalDetailValue: any = ref({});
112 - const avatarUrl: any = ref(''); 131 + const updatePersonalData: any = ref({});
113 const getBackendV: any = ref({}); 132 const getBackendV: any = ref({});
114 const [registerDesc] = useDescription({ 133 const [registerDesc] = useDescription({
115 title: '个人详情', 134 title: '个人详情',
116 schema: schema, 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 showActionButtonGroup: false, 164 showActionButtonGroup: false,
122 schemas: formSchema, 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 const handleSubmit = async () => { 188 const handleSubmit = async () => {
129 - // console.log(userStore.getUserInfo);  
130 const getUserInfo = await userInfo; 189 const getUserInfo = await userInfo;
131 - // console.log(getUserInfo);  
132 getPersonalValue.value = await validate(); 190 getPersonalValue.value = await validate();
133 getPersonalValue.value.id = getUserInfo.userId; 191 getPersonalValue.value.id = getUserInfo.userId;
134 getPersonalValue.value.username = getBackendV.value.username; 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 createMessage.success('修改成功'); 196 createMessage.success('修改成功');
138 closeModal(); 197 closeModal();
139 resetFields(); 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 const compHeight = computed(() => { 201 const compHeight = computed(() => {
160 return 1000; 202 return 1000;
161 }); 203 });
162 return { 204 return {
163 - uploadApi, 205 + peresonalPic,
  206 + beforeUploadqrcodePic,
  207 + customUploadqrcodePic,
164 compHeight, 208 compHeight,
165 - updateAvatar,  
166 - avatar,  
167 handleSubmit, 209 handleSubmit,
168 getPersonalDetailValue, 210 getPersonalDetailValue,
169 registerDesc, 211 registerDesc,
@@ -174,4 +216,22 @@ @@ -174,4 +216,22 @@
174 }, 216 },
175 }); 217 });
176 </script> 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 <template> 1 <template>
2 <Dropdown placement="bottomLeft" :overlayClassName="`${prefixCls}-dropdown-overlay`"> 2 <Dropdown placement="bottomLeft" :overlayClassName="`${prefixCls}-dropdown-overlay`">
3 <span :class="[prefixCls, `${prefixCls}--${theme}`]" class="flex"> 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 <span :class="`${prefixCls}__info hidden md:block`"> 8 <span :class="`${prefixCls}__info hidden md:block`">
6 <span :class="`${prefixCls}__name `" class="truncate"> 9 <span :class="`${prefixCls}__name `" class="truncate">
7 - {{ getUserInfo.realName }} 10 + {{ refreshPersonlData.realName ? refreshPersonlData.realName : getUserInfo.realName }}
8 </span> 11 </span>
9 </span> 12 </span>
10 </span> 13 </span>
@@ -12,12 +15,10 @@ @@ -12,12 +15,10 @@
12 <template #overlay> 15 <template #overlay>
13 <Menu @click="handleMenuClick"> 16 <Menu @click="handleMenuClick">
14 <MenuItem 17 <MenuItem
15 - key="doc"  
16 - :text="t('layout.header.dropdownItemDoc')" 18 + key="personal"
  19 + :text="t('layout.header.dropdownItemPersonal')"
17 icon="ion:document-text-outline" 20 icon="ion:document-text-outline"
18 - v-if="getShowDoc"  
19 /> 21 />
20 - <MenuDivider v-if="getShowDoc" />  
21 <MenuItem 22 <MenuItem
22 v-if="getUseLockPage" 23 v-if="getUseLockPage"
23 key="lock" 24 key="lock"
@@ -29,22 +30,21 @@ @@ -29,22 +30,21 @@
29 :text="t('layout.header.dropdownItemLoginOut')" 30 :text="t('layout.header.dropdownItemLoginOut')"
30 icon="ion:power-outline" 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 </Menu> 33 </Menu>
38 </template> 34 </template>
39 </Dropdown> 35 </Dropdown>
40 <LockAction @register="register" /> 36 <LockAction @register="register" />
41 - <PersonalChild @register="registerPersonal" /> 37 + <PersonalChild
  38 + @refreshPersonl="refreshPersonlFunc"
  39 + ref="personalRef"
  40 + @register="registerPersonal"
  41 + />
42 </template> 42 </template>
43 <script lang="ts"> 43 <script lang="ts">
44 // components 44 // components
45 import { Dropdown, Menu } from 'ant-design-vue'; 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 import { DOC_URL } from '/@/settings/siteSetting'; 49 import { DOC_URL } from '/@/settings/siteSetting';
50 50
@@ -53,13 +53,12 @@ @@ -53,13 +53,12 @@
53 import { useI18n } from '/@/hooks/web/useI18n'; 53 import { useI18n } from '/@/hooks/web/useI18n';
54 import { useDesign } from '/@/hooks/web/useDesign'; 54 import { useDesign } from '/@/hooks/web/useDesign';
55 import { useModal } from '/@/components/Modal'; 55 import { useModal } from '/@/components/Modal';
56 -  
57 import headerImg from '/@/assets/images/header.jpg'; 56 import headerImg from '/@/assets/images/header.jpg';
58 import { propTypes } from '/@/utils/propTypes'; 57 import { propTypes } from '/@/utils/propTypes';
59 import { openWindow } from '/@/utils'; 58 import { openWindow } from '/@/utils';
60 -  
61 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; 59 import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
62 - 60 + import { USER_INFO_KEY } from '/@/enums/cacheEnum';
  61 + import { getAuthCache } from '/@/utils/auth';
63 type MenuEvent = 'logout' | 'doc' | 'lock' | 'personal'; 62 type MenuEvent = 'logout' | 'doc' | 'lock' | 'personal';
64 63
65 export default defineComponent({ 64 export default defineComponent({
@@ -68,7 +67,6 @@ @@ -68,7 +67,6 @@
68 Dropdown, 67 Dropdown,
69 Menu, 68 Menu,
70 MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')), 69 MenuItem: createAsyncComponent(() => import('./DropMenuItem.vue')),
71 - MenuDivider: Menu.Divider,  
72 LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')), 70 LockAction: createAsyncComponent(() => import('../lock/LockModal.vue')),
73 PersonalChild: createAsyncComponent(() => import('../personal/index.vue')), 71 PersonalChild: createAsyncComponent(() => import('../personal/index.vue')),
74 }, 72 },
@@ -76,14 +74,21 @@ @@ -76,14 +74,21 @@
76 theme: propTypes.oneOf(['dark', 'light']), 74 theme: propTypes.oneOf(['dark', 'light']),
77 }, 75 },
78 setup() { 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 const { prefixCls } = useDesign('header-user-dropdown'); 84 const { prefixCls } = useDesign('header-user-dropdown');
80 const { t } = useI18n(); 85 const { t } = useI18n();
81 const { getShowDoc, getUseLockPage } = useHeaderSetting(); 86 const { getShowDoc, getUseLockPage } = useHeaderSetting();
82 const userStore = useUserStore(); 87 const userStore = useUserStore();
83 88
84 const getUserInfo = computed(() => { 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 const [register, { openModal }] = useModal(); 94 const [register, { openModal }] = useModal();
@@ -122,11 +127,21 @@ @@ -122,11 +127,21 @@
122 127
123 const openPersonalFunc = () => { 128 const openPersonalFunc = () => {
124 setTimeout(() => { 129 setTimeout(() => {
125 - openModalPersonal(true); 130 + openModalPersonal(true, {
  131 + userInfo,
  132 + });
126 }, 10); 133 }, 10);
127 }; 134 };
128 135
  136 + const refreshPersonlFunc = (v) => {
  137 + refreshPersonlData.avatar = v.avatar;
  138 + refreshPersonlData.realName = v.realName;
  139 + };
  140 +
129 return { 141 return {
  142 + refreshPersonlData,
  143 + refreshPersonlFunc,
  144 + personalRef,
130 registerPersonal, 145 registerPersonal,
131 openPersonalFunc, 146 openPersonalFunc,
132 prefixCls, 147 prefixCls,
@@ -21,43 +21,18 @@ @@ -21,43 +21,18 @@
21 </transition> 21 </transition>
22 </template> 22 </template>
23 </RouterView> 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 <FrameLayout v-if="getCanEmbedIFramePage" /> 25 <FrameLayout v-if="getCanEmbedIFramePage" />
43 </template> 26 </template>
44 27
45 <script lang="ts"> 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 import FrameLayout from '/@/layouts/iframe/index.vue'; 30 import FrameLayout from '/@/layouts/iframe/index.vue';
50 -  
51 import { useRootSetting } from '/@/hooks/setting/useRootSetting'; 31 import { useRootSetting } from '/@/hooks/setting/useRootSetting';
52 -  
53 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting'; 32 import { useTransitionSetting } from '/@/hooks/setting/useTransitionSetting';
54 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting'; 33 import { useMultipleTabSetting } from '/@/hooks/setting/useMultipleTabSetting';
55 import { getTransitionName } from './transition'; 34 import { getTransitionName } from './transition';
56 -  
57 import { useMultipleTabStore } from '/@/store/modules/multipleTab'; 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 export default defineComponent({ 36 export default defineComponent({
62 name: 'PageLayout', 37 name: 'PageLayout',
63 components: { FrameLayout }, 38 components: { FrameLayout },
@@ -78,17 +53,6 @@ @@ -78,17 +53,6 @@
78 return tabStore.getCachedTabList; 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 return { 56 return {
93 getTransitionName, 57 getTransitionName,
94 openCache, 58 openCache,
@@ -96,8 +60,6 @@ @@ -96,8 +60,6 @@
96 getBasicTransition, 60 getBasicTransition,
97 getCaches, 61 getCaches,
98 getCanEmbedIFramePage, 62 getCanEmbedIFramePage,
99 - // register,  
100 - // maskColor,  
101 }; 63 };
102 }, 64 },
103 }); 65 });
@@ -12,7 +12,7 @@ export default { @@ -12,7 +12,7 @@ export default {
12 networkExceptionMsg: 12 networkExceptionMsg:
13 'Please check if your network connection is normal! The network is abnormal', 13 'Please check if your network connection is normal! The network is abnormal',
14 14
15 - errMsg401: 'no permission', 15 + errMsg401: '',
16 errMsg403: 'not authorized', 16 errMsg403: 'not authorized',
17 errMsg404: 'the resource was not found!', 17 errMsg404: 'the resource was not found!',
18 errMsg405: 'Network request error, request method not allowed!', 18 errMsg405: 'Network request error, request method not allowed!',
@@ -10,8 +10,7 @@ export default { @@ -10,8 +10,7 @@ export default {
10 apiRequestFailed: '请求出错,请稍候重试', 10 apiRequestFailed: '请求出错,请稍候重试',
11 networkException: '网络异常', 11 networkException: '网络异常',
12 networkExceptionMsg: '网络异常,请检查您的网络连接是否正常!', 12 networkExceptionMsg: '网络异常,请检查您的网络连接是否正常!',
13 -  
14 - errMsg401: '没有权限!', 13 + errMsg401: '',
15 errMsg403: '未授权', 14 errMsg403: '未授权',
16 errMsg404: '未找到该资源!', 15 errMsg404: '未找到该资源!',
17 errMsg405: '网络请求错误,请求方法未允许!', 16 errMsg405: '网络请求错误,请求方法未允许!',
@@ -14,13 +14,7 @@ import { setupStore } from '/@/store'; @@ -14,13 +14,7 @@ import { setupStore } from '/@/store';
14 import { setupGlobDirectives } from '/@/directives'; 14 import { setupGlobDirectives } from '/@/directives';
15 import { setupI18n } from '/@/locales/setupI18n'; 15 import { setupI18n } from '/@/locales/setupI18n';
16 import { registerGlobComp } from '/@/components/registerGlobComp'; 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 async function bootstrap() { 19 async function bootstrap() {
26 const app = createApp(App); 20 const app = createApp(App);
@@ -129,7 +129,6 @@ export const useUserStore = defineStore({ @@ -129,7 +129,6 @@ export const useUserStore = defineStore({
129 try { 129 try {
130 const { goHome = true, mode, ...loginParams } = params; 130 const { goHome = true, mode, ...loginParams } = params;
131 const data = await loginApi(loginParams, mode); 131 const data = await loginApi(loginParams, mode);
132 - console.log(data);  
133 return this.process(data, goHome); 132 return this.process(data, goHome);
134 } catch (error) { 133 } catch (error) {
135 return Promise.reject(error); 134 return Promise.reject(error);
@@ -10,7 +10,6 @@ import { SessionTimeoutProcessingEnum } from '/@/enums/appEnum'; @@ -10,7 +10,6 @@ import { SessionTimeoutProcessingEnum } from '/@/enums/appEnum';
10 const { createMessage, createErrorModal } = useMessage(); 10 const { createMessage, createErrorModal } = useMessage();
11 const error = createMessage.error!; 11 const error = createMessage.error!;
12 const stp = projectSetting.sessionTimeoutProcessing; 12 const stp = projectSetting.sessionTimeoutProcessing;
13 -  
14 export function checkStatus( 13 export function checkStatus(
15 status: number, 14 status: number,
16 msg: string, 15 msg: string,
@@ -19,7 +18,6 @@ export function checkStatus( @@ -19,7 +18,6 @@ export function checkStatus(
19 const { t } = useI18n(); 18 const { t } = useI18n();
20 const userStore = useUserStoreWithOut(); 19 const userStore = useUserStoreWithOut();
21 let errMessage = ''; 20 let errMessage = '';
22 -  
23 switch (status) { 21 switch (status) {
24 case 400: 22 case 400:
25 errMessage = `${msg}`; 23 errMessage = `${msg}`;
@@ -10,58 +10,17 @@ import { useGlobSetting } from '/@/hooks/setting'; @@ -10,58 +10,17 @@ import { useGlobSetting } from '/@/hooks/setting';
10 import { useMessage } from '/@/hooks/web/useMessage'; 10 import { useMessage } from '/@/hooks/web/useMessage';
11 import { RequestEnum, ContentTypeEnum } from '/@/enums/httpEnum'; 11 import { RequestEnum, ContentTypeEnum } from '/@/enums/httpEnum';
12 import { isString } from '/@/utils/is'; 12 import { isString } from '/@/utils/is';
13 -import { getJwtToken, getAuthCache } from '/@/utils/auth'; 13 +import { getJwtToken } from '/@/utils/auth';
14 import { setObjToUrlParams, deepMerge } from '/@/utils'; 14 import { setObjToUrlParams, deepMerge } from '/@/utils';
15 import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog'; 15 import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog';
16 import { useI18n } from '/@/hooks/web/useI18n'; 16 import { useI18n } from '/@/hooks/web/useI18n';
17 import { joinTimestamp, formatRequestDate } from './helper'; 17 import { joinTimestamp, formatRequestDate } from './helper';
18 import { PageEnum } from '/@/enums/pageEnum'; 18 import { PageEnum } from '/@/enums/pageEnum';
19 -import { REFRESH_TOKEN_KEY } from '/@/enums/cacheEnum';  
20 import { router } from '/@/router'; 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 const globSetting = useGlobSetting(); 21 const globSetting = useGlobSetting();
56 const urlPrefix = globSetting.urlPrefix; 22 const urlPrefix = globSetting.urlPrefix;
57 const { createMessage, createErrorModal } = useMessage(); 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 * @description: 数据处理,方便区分多种处理方式 26 * @description: 数据处理,方便区分多种处理方式
@@ -162,32 +121,13 @@ const transform: AxiosTransform = { @@ -162,32 +121,13 @@ const transform: AxiosTransform = {
162 const msg: string = response?.data?.msg ?? ''; 121 const msg: string = response?.data?.msg ?? '';
163 const err: string = error?.toString?.() ?? ''; 122 const err: string = error?.toString?.() ?? '';
164 let errMessage = ''; 123 let errMessage = '';
165 -  
166 try { 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 if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) { 131 if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
192 errMessage = t('sys.api.apiTimeoutMessage'); 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,3 +60,171 @@ export const EmailRegexp = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a
60 60
61 // 手机号正则 61 // 手机号正则
62 export const PhoneRegexp = /^[1][3,4,5,6,7,8,9][0-9]{9}$/; 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,6 +33,23 @@ export const alarmSearchSchemas: FormSchema[] = [
33 label: '告警类型', 33 label: '告警类型',
34 component: 'Input', 34 component: 'Input',
35 colProps: { span: 6 }, 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 field: 'endTime', 55 field: 'endTime',
@@ -51,7 +51,6 @@ @@ -51,7 +51,6 @@
51 severity: alarmLevel(data.severity), 51 severity: alarmLevel(data.severity),
52 status: statusType(data.status), 52 status: statusType(data.status),
53 }); 53 });
54 - console.log(data.status);  
55 alarmStatus.value = data.status; 54 alarmStatus.value = data.status;
56 alarmId.value = data.id; 55 alarmId.value = data.id;
57 }); 56 });
@@ -41,6 +41,7 @@ export const formSchema: FormSchema[] = [ @@ -41,6 +41,7 @@ export const formSchema: FormSchema[] = [
41 label: '', 41 label: '',
42 component: 'Input', 42 component: 'Input',
43 componentProps: { 43 componentProps: {
  44 + maxLength: 255,
44 placeholder: '请输入设备名称', 45 placeholder: '请输入设备名称',
45 }, 46 },
46 }, 47 },
@@ -34,8 +34,16 @@ @@ -34,8 +34,16 @@
34 :canFullscreen="false" 34 :canFullscreen="false"
35 > 35 >
36 <BasicForm @register="registerForm" /> 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 </BasicModal> 45 </BasicModal>
  46 + <DeviceDetailDrawer @register="registerDetailDrawer" />
39 </div> 47 </div>
40 </template> 48 </template>
41 <script lang="ts"> 49 <script lang="ts">
@@ -44,22 +52,30 @@ @@ -44,22 +52,30 @@
44 import { formSchema, columns } from './config.data'; 52 import { formSchema, columns } from './config.data';
45 import { BasicTable, useTable } from '/@/components/Table'; 53 import { BasicTable, useTable } from '/@/components/Table';
46 import { devicePage } from '/@/api/alarm/contact/alarmContact'; 54 import { devicePage } from '/@/api/alarm/contact/alarmContact';
47 - import { Tag } from 'ant-design-vue'; 55 + import { Tag, Alert } from 'ant-design-vue';
48 import { DeviceState } from '/@/api/device/model/deviceModel'; 56 import { DeviceState } from '/@/api/device/model/deviceModel';
49 import { BAI_DU_MAP_URL } from '/@/utils/fnUtils'; 57 import { BAI_DU_MAP_URL } from '/@/utils/fnUtils';
50 import { useModal, BasicModal } from '/@/components/Modal'; 58 import { useModal, BasicModal } from '/@/components/Modal';
51 import { BasicForm, useForm } from '/@/components/Form'; 59 import { BasicForm, useForm } from '/@/components/Form';
52 import { schemas } from './config.data'; 60 import { schemas } from './config.data';
53 import { useECharts } from '/@/hooks/web/useECharts'; 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 import moment from 'moment'; 69 import moment from 'moment';
56 export default defineComponent({ 70 export default defineComponent({
57 name: 'BaiduMap', 71 name: 'BaiduMap',
58 components: { 72 components: {
59 BasicTable, 73 BasicTable,
60 Tag, 74 Tag,
  75 + Alert,
61 BasicModal, 76 BasicModal,
62 BasicForm, 77 BasicForm,
  78 + DeviceDetailDrawer,
63 }, 79 },
64 props: { 80 props: {
65 width: { 81 width: {
@@ -74,7 +90,10 @@ @@ -74,7 +90,10 @@
74 setup() { 90 setup() {
75 const wrapRef = ref<HTMLDivElement | null>(null); 91 const wrapRef = ref<HTMLDivElement | null>(null);
76 const { toPromise } = useScript({ src: BAI_DU_MAP_URL }); 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 async function initMap() { 97 async function initMap() {
79 await toPromise(); 98 await toPromise();
80 await nextTick(); 99 await nextTick();
@@ -101,13 +120,14 @@ @@ -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 const BMap = (window as any).BMap; 126 const BMap = (window as any).BMap;
107 const wrapEl = unref(wrapRef); 127 const wrapEl = unref(wrapRef);
108 const map = new BMap.Map(wrapEl); 128 const map = new BMap.Map(wrapEl);
109 if (record.deviceInfo.address) { 129 if (record.deviceInfo.address) {
110 - const { name, organizationDTO, updateTime, deviceState, deviceProfile } = record; 130 + const { name, organizationDTO, deviceState, deviceProfile } = record;
111 const { longitude, latitude, address } = record.deviceInfo; 131 const { longitude, latitude, address } = record.deviceInfo;
112 const point = new BMap.Point(longitude, latitude); 132 const point = new BMap.Point(longitude, latitude);
113 let options = { 133 let options = {
@@ -117,6 +137,10 @@ @@ -117,6 +137,10 @@
117 map.centerAndZoom(point, 15); 137 map.centerAndZoom(point, 15);
118 map.enableScrollWheelZoom(true); 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 let infoWindow = new BMap.InfoWindow( 144 let infoWindow = new BMap.InfoWindow(
121 ` 145 `
122 <div style="display:flex;justify-content:space-between; margin:20px 0px;"> 146 <div style="display:flex;justify-content:space-between; margin:20px 0px;">
@@ -132,10 +156,9 @@ @@ -132,10 +156,9 @@
132 <div>所属组织:${organizationDTO.name}</div> 156 <div>所属组织:${organizationDTO.name}</div>
133 <div style="margin-top:6px;">接入协议:${deviceProfile.transportType}</div> 157 <div style="margin-top:6px;">接入协议:${deviceProfile.transportType}</div>
134 <div style="margin-top:6px;">设备位置:${address}</div> 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 <button onclick="openHistoryModal()" style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">历史数据</button> 162 <button onclick="openHistoryModal()" style="color:#fff;background-color:#409eff;padding:4px; border-radius:4px;">历史数据</button>
140 </div> 163 </div>
141 `, 164 `,
@@ -185,13 +208,20 @@ @@ -185,13 +208,20 @@
185 endTs = Date.now(); 208 endTs = Date.now();
186 // 发送请求 209 // 发送请求
187 const res = await getDeviceHistoryInfo({ 210 const res = await getDeviceHistoryInfo({
188 - entityId: entityId.value, 211 + entityId,
189 keys: keys.join(), 212 keys: keys.join(),
190 startTs, 213 startTs,
191 endTs, 214 endTs,
192 interval, 215 interval,
193 agg, 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 for (const key in res) { 226 for (const key in res) {
197 for (const item1 of res[key]) { 227 for (const item1 of res[key]) {
@@ -250,24 +280,38 @@ @@ -250,24 +280,38 @@
250 280
251 const chartRef = ref<HTMLDivElement | null>(null); 281 const chartRef = ref<HTMLDivElement | null>(null);
252 const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); 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 const openHistoryModal = async () => { 292 const openHistoryModal = async () => {
255 openModal(true); 293 openModal(true);
256 -  
257 // 收集参数 294 // 收集参数
258 const dataArray: any[] = []; 295 const dataArray: any[] = [];
259 const startTs = Date.now() - 86400000; //最近一天 296 const startTs = Date.now() - 86400000; //最近一天
260 const endTs = Date.now(); 297 const endTs = Date.now();
261 // 发送请求 298 // 发送请求
262 - keys = await getDeviceDataKeys(entityId.value); 299 + keys = await getDeviceDataKeys(entityId);
263 const res = await getDeviceHistoryInfo({ 300 const res = await getDeviceHistoryInfo({
264 - entityId: entityId.value, 301 + entityId,
265 keys: keys.join(), 302 keys: keys.join(),
266 startTs, 303 startTs,
267 endTs, 304 endTs,
268 interval: 7200000, //间隔两小时 305 interval: 7200000, //间隔两小时
269 agg: 'AVG', 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 for (const key in res) { 316 for (const key in res) {
273 for (const item1 of res[key]) { 317 for (const item1 of res[key]) {
@@ -327,12 +371,14 @@ @@ -327,12 +371,14 @@
327 agg: 'AVG', 371 agg: 'AVG',
328 }); 372 });
329 }; 373 };
  374 +
330 const cancelHistoryModal = () => { 375 const cancelHistoryModal = () => {
331 resetFields(); 376 resetFields();
332 setOptions({}); 377 setOptions({});
333 }; 378 };
334 onMounted(() => { 379 onMounted(() => {
335 initMap(); 380 initMap();
  381 + (window as any).openDeviceInfoDrawer = openDeviceInfoDrawer;
336 (window as any).openHistoryModal = openHistoryModal; 382 (window as any).openHistoryModal = openHistoryModal;
337 }); 383 });
338 return { 384 return {
@@ -343,7 +389,9 @@ @@ -343,7 +389,9 @@
343 registerModal, 389 registerModal,
344 registerForm, 390 registerForm,
345 chartRef, 391 chartRef,
  392 + isNull,
346 cancelHistoryModal, 393 cancelHistoryModal,
  394 + registerDetailDrawer,
347 }; 395 };
348 }, 396 },
349 }); 397 });
@@ -56,6 +56,7 @@ export const searchFormSchema: FormSchema[] = [ @@ -56,6 +56,7 @@ export const searchFormSchema: FormSchema[] = [
56 component: 'Input', 56 component: 'Input',
57 colProps: { span: 6 }, 57 colProps: { span: 6 },
58 componentProps: { 58 componentProps: {
  59 + maxLength: 36,
59 placeholder: '请输入联系人姓名', 60 placeholder: '请输入联系人姓名',
60 }, 61 },
61 }, 62 },
@@ -70,6 +71,7 @@ export const formSchema: FormSchema[] = [ @@ -70,6 +71,7 @@ export const formSchema: FormSchema[] = [
70 component: 'Input', 71 component: 'Input',
71 componentProps: { 72 componentProps: {
72 placeholder: '请输入联系人姓名', 73 placeholder: '请输入联系人姓名',
  74 + maxLength: 255,
73 }, 75 },
74 }, 76 },
75 { 77 {
@@ -108,6 +110,7 @@ export const formSchema: FormSchema[] = [ @@ -108,6 +110,7 @@ export const formSchema: FormSchema[] = [
108 component: 'Input', 110 component: 'Input',
109 componentProps: { 111 componentProps: {
110 placeholder: '请输入微信号', 112 placeholder: '请输入微信号',
  113 + maxLength: 255,
111 }, 114 },
112 }, 115 },
113 { 116 {
@@ -115,7 +118,8 @@ export const formSchema: FormSchema[] = [ @@ -115,7 +118,8 @@ export const formSchema: FormSchema[] = [
115 label: '备注', 118 label: '备注',
116 component: 'InputTextArea', 119 component: 'InputTextArea',
117 componentProps: { 120 componentProps: {
118 - placeholder: '', 121 + placeholder: '请输入备注',
  122 + maxLength: 255,
119 }, 123 },
120 }, 124 },
121 { 125 {
@@ -123,5 +127,8 @@ export const formSchema: FormSchema[] = [ @@ -123,5 +127,8 @@ export const formSchema: FormSchema[] = [
123 label: '', 127 label: '',
124 component: 'Input', 128 component: 'Input',
125 show: false, 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 <template> 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 </div> 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 </div> 88 </div>
49 </div> 89 </div>
50 </div> 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 </div> 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 </div> 110 </div>
55 </template> 111 </template>
56 <script lang="ts" setup> 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 <template> 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 </template> 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 </template> 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 </Card> 105 </Card>
55 - </Card> 106 + </div>
56 </template> 107 </template>
57 108
58 <script lang="ts"> 109 <script lang="ts">
59 import { defineComponent, ref, computed, onMounted } from 'vue'; 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 import { useUserStore } from '/@/store/modules/user'; 112 import { useUserStore } from '/@/store/modules/user';
62 import { getEnterPriseDetail } from '/@/api/oem'; 113 import { getEnterPriseDetail } from '/@/api/oem';
63 import { notifyMyGetrPageApi } from '/@/api/stationnotification/stationnotifyApi'; 114 import { notifyMyGetrPageApi } from '/@/api/stationnotification/stationnotifyApi';
64 import { Time } from '/@/components/Time'; 115 import { Time } from '/@/components/Time';
65 import { useGo } from '/@/hooks/web/usePage'; 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 export default defineComponent({ 121 export default defineComponent({
67 components: { 122 components: {
68 Card, 123 Card,
69 - AnchorLink, 124 + CardMeta: Card.Meta,
  125 + AnchorLink: Anchor.Link,
70 List, 126 List,
71 - ListItem,  
72 - ListItemMeta, 127 + ListItem: List.Item,
  128 + ListItemMeta: List.Item.Meta,
  129 + Descriptions,
  130 + DescriptionsItem: Descriptions.Item,
73 Avatar, 131 Avatar,
74 Time, 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 const helpDoc = ref([ 146 const helpDoc = ref([
83 { 147 {
84 title: '如何接入设备?', 148 title: '如何接入设备?',
@@ -109,6 +173,18 @@ @@ -109,6 +173,18 @@
109 activeKey.value = key; 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 const userStore = useUserStore(); 188 const userStore = useUserStore();
113 const getContacts = computed(() => { 189 const getContacts = computed(() => {
114 return userStore.enterPriseInfo?.contacts; 190 return userStore.enterPriseInfo?.contacts;
@@ -122,32 +198,35 @@ @@ -122,32 +198,35 @@
122 const getQrCode = computed(() => { 198 const getQrCode = computed(() => {
123 return userStore.enterPriseInfo?.qrCode; 199 return userStore.enterPriseInfo?.qrCode;
124 }); 200 });
125 -  
126 - // 通知数据  
127 - const dataSource = ref([]);  
128 - const go = useGo();  
129 onMounted(async () => { 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 return { 210 return {
135 activeKey, 211 activeKey,
136 tabListTitle, 212 tabListTitle,
137 - onTabChange,  
138 helpDoc, 213 helpDoc,
139 getQrCode, 214 getQrCode,
140 getContacts, 215 getContacts,
141 getAddress, 216 getAddress,
142 getTel, 217 getTel,
143 dataSource, 218 dataSource,
  219 + onTabChange,
144 go, 220 go,
  221 + registerTable,
  222 + isAdmin,
  223 + redoHeight,
145 }; 224 };
146 }, 225 },
147 }); 226 });
148 </script> 227 </script>
149 228
150 -<style lang="less" scoped> 229 +<style scoped>
151 .noticeTitle:hover { 230 .noticeTitle:hover {
152 border-bottom: 1px solid #ccc; 231 border-bottom: 1px solid #ccc;
153 } 232 }
@@ -4,59 +4,347 @@ @@ -4,59 +4,347 @@
4 v-bind="$attrs" 4 v-bind="$attrs"
5 :active-tab-key="activeKey" 5 :active-tab-key="activeKey"
6 @tabChange="onTabChange" 6 @tabChange="onTabChange"
  7 + v-if="!isAdmin(role)"
7 > 8 >
8 <template #tabBarExtraContent> 9 <template #tabBarExtraContent>
9 <div class="extra-date"> 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 </template> 17 </template>
15 - <DatePicker @change="onDateChange" /> 18 + <DatePicker @change="onDateChange" v-model:value="dateValue" />
16 </div> 19 </div>
17 </template> 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 </div> 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 </div> 28 </div>
26 </Card> 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 </template> 36 </template>
28 <script lang="ts" setup> 37 <script lang="ts" setup>
29 - import { ref } from 'vue'; 38 + import { ref, reactive } from 'vue';
30 import { Card, DatePicker } from 'ant-design-vue'; 39 import { Card, DatePicker } from 'ant-design-vue';
31 import VisitAnalysis from './VisitAnalysis.vue'; 40 import VisitAnalysis from './VisitAnalysis.vue';
32 import VisitAnalysisBar from './VisitAnalysisBar.vue'; 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 const tabListTitle = [ 59 const tabListTitle = [
37 { 60 {
38 - key: 'tab1', 61 + key: '1',
39 tab: '告警数统计', 62 tab: '告警数统计',
40 }, 63 },
41 { 64 {
42 - key: 'tab2', 65 + key: '2',
43 tab: '消息量统计', 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 activeKey.value = key; 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 activeIndex.value = index; 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 </script> 345 </script>
58 346
59 -<style scoped lang="less"> 347 +<style lang="less">
60 .center { 348 .center {
61 display: flex; 349 display: flex;
62 justify-content: center; 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 <template> 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 </template> 7 </template>
4 <script lang="ts" setup> 8 <script lang="ts" setup>
5 - import { onMounted, ref, Ref } from 'vue'; 9 + import { onMounted, ref, Ref, withDefaults, watch } from 'vue';
6 import { useECharts } from '/@/hooks/web/useECharts'; 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 const chartRef = ref<HTMLDivElement | null>(null); 23 const chartRef = ref<HTMLDivElement | null>(null);
13 const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); 24 const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
14 25
@@ -16,79 +27,60 @@ @@ -16,79 +27,60 @@
16 setOptions({ 27 setOptions({
17 tooltip: { 28 tooltip: {
18 trigger: 'axis', 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 xAxis: { 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 series: [ 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 </script> 86 </script>
1 <template> 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 </template> 7 </template>
4 <script lang="ts" setup> 8 <script lang="ts" setup>
5 - import { onMounted, ref, Ref } from 'vue'; 9 + import { ref, Ref, watch, withDefaults } from 'vue';
6 import { useECharts } from '/@/hooks/web/useECharts'; 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 const chartRef = ref<HTMLDivElement | null>(null); 24 const chartRef = ref<HTMLDivElement | null>(null);
14 const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); 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 </script> 83 </script>
1 import { PropType } from 'vue'; 1 import { PropType } from 'vue';
2 - 2 +import type { BasicColumn } from '/@/components/Table';
3 export interface BasicProps { 3 export interface BasicProps {
4 width: string; 4 width: string;
5 height: string; 5 height: string;
@@ -14,3 +14,16 @@ export const basicProps = { @@ -14,3 +14,16 @@ export const basicProps = {
14 default: '280px', 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 +];
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 <template> 1 <template>
2 <div class="p-4 md:flex"> 2 <div class="p-4 md:flex">
3 <div class="md:w-7/10 w-full !mr-4 enter-y"> 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 <Card title="核心流程指南" style="width: 100%"> 7 <Card title="核心流程指南" style="width: 100%">
8 - <img alt="核心流程指南" src="../../../assets/images/flow.png" /> 8 + <img alt="核心流程指南" src="/src/assets/images/flow.png" />
9 </Card> 9 </Card>
10 </div> 10 </div>
11 </div> 11 </div>
12 <div class="md:w-3/10 w-full enter-y"> 12 <div class="md:w-3/10 w-full enter-y">
13 - <HelpDoc /> 13 + <HelpDoc :role="role" />
14 </div> 14 </div>
15 </div> 15 </div>
16 </template> 16 </template>
@@ -20,8 +20,19 @@ @@ -20,8 +20,19 @@
20 import SiteAnalysis from './components/SiteAnalysis.vue'; 20 import SiteAnalysis from './components/SiteAnalysis.vue';
21 import { Card } from 'ant-design-vue'; 21 import { Card } from 'ant-design-vue';
22 import HelpDoc from './components/HelpDoc.vue'; 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 const loading = ref(true); 32 const loading = ref(true);
  33 +
  34 + console.log(role);
  35 +
25 setTimeout(() => { 36 setTimeout(() => {
26 loading.value = false; 37 loading.value = false;
27 }, 1500); 38 }, 1500);
@@ -3,6 +3,7 @@ import { findDictItemByCode } from '/@/api/system/dict'; @@ -3,6 +3,7 @@ import { findDictItemByCode } from '/@/api/system/dict';
3 import { deviceProfile } from '/@/api/device/deviceManager'; 3 import { deviceProfile } from '/@/api/device/deviceManager';
4 import { getOrganizationList } from '/@/api/system/system'; 4 import { getOrganizationList } from '/@/api/system/system';
5 import { copyTransFun } from '/@/utils/fnUtils'; 5 import { copyTransFun } from '/@/utils/fnUtils';
  6 +
6 // 第一步的表单 7 // 第一步的表单
7 export const step1Schemas: FormSchema[] = [ 8 export const step1Schemas: FormSchema[] = [
8 { 9 {
@@ -17,6 +18,7 @@ export const step1Schemas: FormSchema[] = [ @@ -17,6 +18,7 @@ export const step1Schemas: FormSchema[] = [
17 required: true, 18 required: true,
18 component: 'Input', 19 component: 'Input',
19 componentProps: { 20 componentProps: {
  21 + placeholder: '设备名称',
20 maxLength: 30, 22 maxLength: 30,
21 }, 23 },
22 }, 24 },
@@ -26,6 +28,7 @@ export const step1Schemas: FormSchema[] = [ @@ -26,6 +28,7 @@ export const step1Schemas: FormSchema[] = [
26 required: true, 28 required: true,
27 component: 'ApiSelect', 29 component: 'ApiSelect',
28 componentProps: { 30 componentProps: {
  31 + placeholder: '设备类型',
29 api: findDictItemByCode, 32 api: findDictItemByCode,
30 params: { 33 params: {
31 dictCode: 'device_type', 34 dictCode: 'device_type',
@@ -64,6 +67,20 @@ export const step1Schemas: FormSchema[] = [ @@ -64,6 +67,20 @@ export const step1Schemas: FormSchema[] = [
64 component: 'Input', 67 component: 'Input',
65 componentProps: { 68 componentProps: {
66 maxLength: 255, 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,24 +93,92 @@ export const step1Schemas: FormSchema[] = [
76 field: 'description', 93 field: 'description',
77 label: '备注', 94 label: '备注',
78 component: 'InputTextArea', 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 field: 'id', 115 field: 'id',
82 label: 'id', 116 label: 'id',
83 component: 'Input', 117 component: 'Input',
84 show: false, 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 field: 'tenantId', 138 field: 'tenantId',
88 label: '租户Code', 139 label: '租户Code',
89 component: 'Input', 140 component: 'Input',
90 show: false, 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 field: 'tbDeviceId', 161 field: 'tbDeviceId',
94 label: 'tbDeviceId', 162 label: 'tbDeviceId',
95 component: 'Input', 163 component: 'Input',
96 show: false, 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,6 +329,10 @@ export const step2Schemas: FormSchema[] = [
244 field: 'credentialsId', 329 field: 'credentialsId',
245 required: true, 330 required: true,
246 ifShow: false, 331 ifShow: false,
  332 + componentProps: {
  333 + maxLength: 36,
  334 + placeholder: '请输入访问令牌',
  335 + },
247 }, 336 },
248 { 337 {
249 label: 'RSA公钥', 338 label: 'RSA公钥',
@@ -251,6 +340,10 @@ export const step2Schemas: FormSchema[] = [ @@ -251,6 +340,10 @@ export const step2Schemas: FormSchema[] = [
251 field: 'publicKey', 340 field: 'publicKey',
252 required: true, 341 required: true,
253 ifShow: false, 342 ifShow: false,
  343 + componentProps: {
  344 + maxLength: 36,
  345 + placeholder: '请输入RSA公钥',
  346 + },
254 }, 347 },
255 { 348 {
256 label: '客户端ID', 349 label: '客户端ID',
@@ -258,6 +351,10 @@ export const step2Schemas: FormSchema[] = [ @@ -258,6 +351,10 @@ export const step2Schemas: FormSchema[] = [
258 field: 'clientId', 351 field: 'clientId',
259 required: true, 352 required: true,
260 ifShow: false, 353 ifShow: false,
  354 + componentProps: {
  355 + maxLength: 36,
  356 + placeholder: '请输入客户端ID',
  357 + },
261 }, 358 },
262 { 359 {
263 label: '用户名', 360 label: '用户名',
@@ -265,11 +362,32 @@ export const step2Schemas: FormSchema[] = [ @@ -265,11 +362,32 @@ export const step2Schemas: FormSchema[] = [
265 field: 'username', 362 field: 'username',
266 required: true, 363 required: true,
267 ifShow: false, 364 ifShow: false,
  365 + componentProps: {
  366 + maxLength: 255,
  367 + placeholder: '请输入用户名',
  368 + },
268 }, 369 },
269 { 370 {
270 label: '密码', 371 label: '密码',
271 component: 'InputPassword', 372 component: 'InputPassword',
272 field: 'password', 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 ifShow: false, 391 ifShow: false,
274 }, 392 },
275 ]; 393 ];
@@ -409,6 +527,10 @@ export const TokenSchemas: FormSchema[] = [ @@ -409,6 +527,10 @@ export const TokenSchemas: FormSchema[] = [
409 field: 'credentialsId', 527 field: 'credentialsId',
410 required: true, 528 required: true,
411 ifShow: false, 529 ifShow: false,
  530 + componentProps: {
  531 + maxLength: 36,
  532 + placeholder: '请输入访问令牌',
  533 + },
412 }, 534 },
413 { 535 {
414 label: 'RSA公钥', 536 label: 'RSA公钥',
@@ -416,6 +538,10 @@ export const TokenSchemas: FormSchema[] = [ @@ -416,6 +538,10 @@ export const TokenSchemas: FormSchema[] = [
416 field: 'publicKey', 538 field: 'publicKey',
417 required: true, 539 required: true,
418 ifShow: false, 540 ifShow: false,
  541 + componentProps: {
  542 + maxLength: 36,
  543 + placeholder: '请输入RSA公钥',
  544 + },
419 }, 545 },
420 { 546 {
421 label: '客户端ID', 547 label: '客户端ID',
@@ -423,6 +549,10 @@ export const TokenSchemas: FormSchema[] = [ @@ -423,6 +549,10 @@ export const TokenSchemas: FormSchema[] = [
423 field: 'clientId', 549 field: 'clientId',
424 required: true, 550 required: true,
425 ifShow: false, 551 ifShow: false,
  552 + componentProps: {
  553 + maxLength: 36,
  554 + placeholder: '请输入客户端ID',
  555 + },
426 }, 556 },
427 { 557 {
428 label: '用户名', 558 label: '用户名',
@@ -430,23 +560,78 @@ export const TokenSchemas: FormSchema[] = [ @@ -430,23 +560,78 @@ export const TokenSchemas: FormSchema[] = [
430 field: 'username', 560 field: 'username',
431 required: true, 561 required: true,
432 ifShow: false, 562 ifShow: false,
  563 + componentProps: {
  564 + maxLength: 255,
  565 + placeholder: '请输入用户名',
  566 + },
433 }, 567 },
434 { 568 {
435 label: '密码', 569 label: '密码',
436 component: 'InputPassword', 570 component: 'InputPassword',
437 field: 'password', 571 field: 'password',
438 ifShow: false, 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 label: 'id', 592 label: 'id',
442 component: 'Input', 593 component: 'Input',
443 field: 'id', 594 field: 'id',
444 show: false, 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 label: 'tbDeviceId', 615 label: 'tbDeviceId',
448 component: 'Input', 616 component: 'Input',
449 field: 'tbDeviceId', 617 field: 'tbDeviceId',
450 show: false, 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 import { formatToDateTime } from '/@/utils/dateUtil'; 1 import { formatToDateTime } from '/@/utils/dateUtil';
2 import { FormSchema } from '/@/components/Form'; 2 import { FormSchema } from '/@/components/Form';
3 import { BasicColumn } from '/@/components/Table'; 3 import { BasicColumn } from '/@/components/Table';
  4 +
4 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; 5 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
5 6
6 export const columns: BasicColumn[] = [ 7 export const columns: BasicColumn[] = [
@@ -8,25 +9,20 @@ export const columns: BasicColumn[] = [ @@ -8,25 +9,20 @@ export const columns: BasicColumn[] = [
8 title: '设备名称', 9 title: '设备名称',
9 dataIndex: 'name', 10 dataIndex: 'name',
10 width: 120, 11 width: 120,
11 - key: 'name',  
12 }, 12 },
13 { 13 {
14 title: '设备标签', 14 title: '设备标签',
15 dataIndex: 'label', 15 dataIndex: 'label',
16 width: 100, 16 width: 100,
17 - key: 'label',  
18 }, 17 },
19 { 18 {
20 title: '设备配置', 19 title: '设备配置',
21 dataIndex: 'deviceProfile.name', 20 dataIndex: 'deviceProfile.name',
22 width: 160, 21 width: 160,
23 - key: 'deviceProfile.name',  
24 }, 22 },
25 -  
26 { 23 {
27 title: '设备类型', 24 title: '设备类型',
28 dataIndex: 'deviceType', 25 dataIndex: 'deviceType',
29 - key: 'deviceType',  
30 customRender({ text }) { 26 customRender({ text }) {
31 return text === DeviceTypeEnum.GATEWAY 27 return text === DeviceTypeEnum.GATEWAY
32 ? '网关设备' 28 ? '网关设备'
@@ -39,7 +35,6 @@ export const columns: BasicColumn[] = [ @@ -39,7 +35,6 @@ export const columns: BasicColumn[] = [
39 title: '描述', 35 title: '描述',
40 dataIndex: 'description', 36 dataIndex: 'description',
41 width: 180, 37 width: 180,
42 - key: 'description',  
43 }, 38 },
44 ]; 39 ];
45 // 实时数据表格 40 // 实时数据表格
@@ -95,6 +90,9 @@ export const alarmSearchSchemas: FormSchema[] = [ @@ -95,6 +90,9 @@ export const alarmSearchSchemas: FormSchema[] = [
95 label: '告警类型', 90 label: '告警类型',
96 component: 'Input', 91 component: 'Input',
97 colProps: { span: 6 }, 92 colProps: { span: 6 },
  93 + componentProps: {
  94 + maxLength: 36,
  95 + },
98 }, 96 },
99 { 97 {
100 field: 'endTime', 98 field: 'endTime',
@@ -208,6 +206,9 @@ export const alarmSchemasForm: FormSchema[] = [ @@ -208,6 +206,9 @@ export const alarmSchemasForm: FormSchema[] = [
208 field: 'details', 206 field: 'details',
209 label: '详情', 207 label: '详情',
210 component: 'InputTextArea', 208 component: 'InputTextArea',
  209 + componentProps: {
  210 + maxLength: 255,
  211 + },
211 }, 212 },
212 ]; 213 ];
213 214
@@ -218,12 +219,18 @@ export const childDeviceSchemas: FormSchema[] = [ @@ -218,12 +219,18 @@ export const childDeviceSchemas: FormSchema[] = [
218 label: '设备配置', 219 label: '设备配置',
219 component: 'Select', 220 component: 'Select',
220 colProps: { span: 12 }, 221 colProps: { span: 12 },
  222 + componentProps: {
  223 + maxLength: 255,
  224 + },
221 }, 225 },
222 { 226 {
223 field: 'icon', 227 field: 'icon',
224 label: '设备名称', 228 label: '设备名称',
225 component: 'Input', 229 component: 'Input',
226 colProps: { span: 12 }, 230 colProps: { span: 12 },
  231 + componentProps: {
  232 + maxLength: 255,
  233 + },
227 }, 234 },
228 ]; 235 ];
229 export const childDeviceColumns: BasicColumn[] = [ 236 export const childDeviceColumns: BasicColumn[] = [
  1 +import { formatToDate } from '/@/utils/dateUtil';
1 import { BasicColumn } from '/@/components/Table'; 2 import { BasicColumn } from '/@/components/Table';
2 import { FormSchema } from '/@/components/Table'; 3 import { FormSchema } from '/@/components/Table';
3 import { DeviceTypeEnum, DeviceState } from '/@/api/device/model/deviceModel'; 4 import { DeviceTypeEnum, DeviceState } from '/@/api/device/model/deviceModel';
  5 +
4 // 表格列数据 6 // 表格列数据
5 export const columns: BasicColumn[] = [ 7 export const columns: BasicColumn[] = [
6 { 8 {
@@ -19,6 +21,7 @@ export const columns: BasicColumn[] = [ @@ -19,6 +21,7 @@ export const columns: BasicColumn[] = [
19 dataIndex: 'deviceProfile.name', 21 dataIndex: 'deviceProfile.name',
20 width: 160, 22 width: 160,
21 slots: { customRender: 'deviceProfile' }, 23 slots: { customRender: 'deviceProfile' },
  24 + ellipsis: true,
22 }, 25 },
23 26
24 { 27 {
@@ -36,10 +39,16 @@ export const columns: BasicColumn[] = [ @@ -36,10 +39,16 @@ export const columns: BasicColumn[] = [
36 width: 120, 39 width: 120,
37 slots: { customRender: 'deviceState' }, 40 slots: { customRender: 'deviceState' },
38 }, 41 },
39 -  
40 { 42 {
41 title: '最后连接时间', 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 width: 180, 52 width: 180,
44 }, 53 },
45 ]; 54 ];
@@ -76,6 +85,23 @@ export const searchFormSchema: FormSchema[] = [ @@ -76,6 +85,23 @@ export const searchFormSchema: FormSchema[] = [
76 field: 'name', 85 field: 'name',
77 label: '设备名称', 86 label: '设备名称',
78 component: 'Input', 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,7 +6,7 @@
6 :destroyOnClose="true" 6 :destroyOnClose="true"
7 @close="closeDrawer" 7 @close="closeDrawer"
8 :title="deviceDetail.name" 8 :title="deviceDetail.name"
9 - width="78%" 9 + width="70%"
10 > 10 >
11 <Tabs v-model:activeKey="activeKey" :size="size" type="card"> 11 <Tabs v-model:activeKey="activeKey" :size="size" type="card">
12 <TabPane key="1" tab="详情" 12 <TabPane key="1" tab="详情"
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 import { defineComponent, ref } from 'vue'; 26 import { defineComponent, ref } from 'vue';
27 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; 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 import Detail from '../tabs/Detail.vue'; 30 import Detail from '../tabs/Detail.vue';
31 import RealTimeData from '../tabs/RealTimeData.vue'; 31 import RealTimeData from '../tabs/RealTimeData.vue';
32 import Alarm from '../tabs/Alarm.vue'; 32 import Alarm from '../tabs/Alarm.vue';
@@ -37,13 +37,12 @@ @@ -37,13 +37,12 @@
37 components: { 37 components: {
38 BasicDrawer, 38 BasicDrawer,
39 Tabs, 39 Tabs,
40 - TabPane, 40 + TabPane: Tabs.TabPane,
41 Detail, 41 Detail,
42 RealTimeData, 42 RealTimeData,
43 Alarm, 43 Alarm,
44 ChildDevice, 44 ChildDevice,
45 }, 45 },
46 -  
47 emits: ['reload', 'register'], 46 emits: ['reload', 'register'],
48 setup() { 47 setup() {
49 const activeKey = ref('1'); 48 const activeKey = ref('1');
@@ -39,9 +39,10 @@ @@ -39,9 +39,10 @@
39 import { createOrEditDevice } from '/@/api/device/deviceManager'; 39 import { createOrEditDevice } from '/@/api/device/deviceManager';
40 import DeviceStep1 from '../step/DeviceStep1.vue'; 40 import DeviceStep1 from '../step/DeviceStep1.vue';
41 import DeviceStep2 from '../step/DeviceStep2.vue'; 41 import DeviceStep2 from '../step/DeviceStep2.vue';
42 - import { Steps, Step } from 'ant-design-vue'; 42 + import { Steps } from 'ant-design-vue';
43 import { useMessage } from '/@/hooks/web/useMessage'; 43 import { useMessage } from '/@/hooks/web/useMessage';
44 import { credentialTypeEnum } from '../../config/data'; 44 import { credentialTypeEnum } from '../../config/data';
  45 +
45 export default defineComponent({ 46 export default defineComponent({
46 name: 'DeviceModal', 47 name: 'DeviceModal',
47 components: { 48 components: {
@@ -49,7 +50,7 @@ @@ -49,7 +50,7 @@
49 DeviceStep1, 50 DeviceStep1,
50 DeviceStep2, 51 DeviceStep2,
51 Steps, 52 Steps,
52 - Step, 53 + Step: Steps.Step,
53 }, 54 },
54 props: { 55 props: {
55 userData: { type: Object }, 56 userData: { type: Object },
@@ -44,6 +44,13 @@ @@ -44,6 +44,13 @@
44 labelWidth: 120, 44 labelWidth: 120,
45 schemas: alarmSearchSchemas, 45 schemas: alarmSearchSchemas,
46 }, 46 },
  47 + showTableSetting: true,
  48 + tableSetting: {
  49 + redo: true,
  50 + size: false,
  51 + setting: false,
  52 + fullScreen: false,
  53 + },
47 useSearchForm: true, 54 useSearchForm: true,
48 bordered: true, 55 bordered: true,
49 showIndexColumn: false, 56 showIndexColumn: false,
@@ -10,8 +10,8 @@ @@ -10,8 +10,8 @@
10 bordered 10 bordered
11 :columns="columns" 11 :columns="columns"
12 :data-source="[deviceDetail]" 12 :data-source="[deviceDetail]"
  13 + :rowKey="(_, index) => index"
13 :pagination="false" 14 :pagination="false"
14 - rowKey="tbDeviceId"  
15 style="width: 800px" 15 style="width: 800px"
16 /> 16 />
17 </div> 17 </div>
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 </div> 23 </div>
24 <div v-if="deviceDetail?.deviceInfo?.address" class="mt-4"> 24 <div v-if="deviceDetail?.deviceInfo?.address" class="mt-4">
25 <p>设备位置</p> 25 <p>设备位置</p>
26 - <div ref="wrapRef" style="height: 400px; width: 90%"></div> 26 + <div ref="wrapRef" style="height: 400px; width: 100%"></div>
27 </div> 27 </div>
28 </div> 28 </div>
29 </template> 29 </template>
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 setup(props) { 24 setup(props) {
25 const token: string = getAuthCache(JWT_TOKEN_KEY); 25 const token: string = getAuthCache(JWT_TOKEN_KEY);
26 const state = reactive({ 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 sendValue: JSON.stringify({ 28 sendValue: JSON.stringify({
29 attrSubCmds: [], 29 attrSubCmds: [],
30 tsSubCmds: [ 30 tsSubCmds: [
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 @cancel="handleCancel" 8 @cancel="handleCancel"
9 > 9 >
10 <div class="step-form-form"> 10 <div class="step-form-form">
11 - <a-steps :current="current"> 11 + <a-steps :current="current" @change="handleChange">
12 <a-step title="设备配置" /> 12 <a-step title="设备配置" />
13 <a-step title="传输配置" /> 13 <a-step title="传输配置" />
14 <a-step title="告警配置" /> 14 <a-step title="告警配置" />
@@ -34,10 +34,9 @@ @@ -34,10 +34,9 @@
34 @next="handleStep3Next" 34 @next="handleStep3Next"
35 @redo="handleRedo" 35 @redo="handleRedo"
36 /></div> 36 /></div>
37 -  
38 <div v-show="current === 3"> 37 <div v-show="current === 3">
39 - <DeviceProfileStep4 ref="DeviceProfileStep4Ref" @prev="handleStepPrev"  
40 - /></div> 38 + <DeviceProfileStep4 ref="DeviceProfileStep4Ref" @prev="handleStepPrev" />
  39 + </div>
41 </div> 40 </div>
42 </BasicModal> 41 </BasicModal>
43 </template> 42 </template>
@@ -86,13 +85,21 @@ @@ -86,13 +85,21 @@
86 const current = ref(0); 85 const current = ref(0);
87 const isUpdate = ref(true); 86 const isUpdate = ref(true);
88 const getTitle = computed(() => (!unref(isUpdate) ? '新增设备配置' : '编辑设备配置')); 87 const getTitle = computed(() => (!unref(isUpdate) ? '新增设备配置' : '编辑设备配置'));
  88 + const handleChange = (v) => {
  89 + console.log(v);
  90 + };
89 const [register, { closeModal }] = useModalInner(async (data) => { 91 const [register, { closeModal }] = useModalInner(async (data) => {
90 isUpdate.value = !!data?.isUpdate; 92 isUpdate.value = !!data?.isUpdate;
91 if (!unref(isUpdate)) { 93 if (!unref(isUpdate)) {
92 current.value = 0; 94 current.value = 0;
  95 + proxy.$refs.DeviceProfileStep3Ref.clearProfileDataFunc();
  96 + proxy.$refs.DeviceProfileStep3Ref.addAlarmRule();
  97 + // proxy.$refs.DeviceProfileStep4Ref.customResetAndFunc();
  98 +
93 switch (current.value) { 99 switch (current.value) {
94 case 0: 100 case 0:
95 proxy.$refs.DeviceProfileStep1Ref.customResetFunc(); 101 proxy.$refs.DeviceProfileStep1Ref.customResetFunc();
  102 + proxy.$refs.DeviceProfileStep1Ref.resetIconFunc();
96 break; 103 break;
97 case 1: 104 case 1:
98 proxy.$refs.DeviceProfileStep2Ref.customResetAndFunc(); 105 proxy.$refs.DeviceProfileStep2Ref.customResetAndFunc();
@@ -109,32 +116,15 @@ @@ -109,32 +116,15 @@
109 } 116 }
110 if (unref(isUpdate)) { 117 if (unref(isUpdate)) {
111 current.value = 0; 118 current.value = 0;
  119 + proxy.$refs.DeviceProfileStep3Ref.clearProfileDataFunc();
  120 + proxy.$refs.DeviceProfileStep3Ref.addAlarmRule();
112 postEditId.value = data.record.id; 121 postEditId.value = data.record.id;
113 const getBackendData = await deviceConfigGetDetail(postEditId.value); 122 const getBackendData = await deviceConfigGetDetail(postEditId.value);
114 editEchoData.value = { ...getBackendData }; 123 editEchoData.value = { ...getBackendData };
115 - console.log(editEchoData.value);  
116 switch (current.value) { 124 switch (current.value) {
117 case 0: 125 case 0:
118 proxy.$refs.DeviceProfileStep1Ref.resetFieldsFunc(editEchoData.value); 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 break; 128 break;
139 } 129 }
140 } 130 }
@@ -142,18 +132,132 @@ @@ -142,18 +132,132 @@
142 function handleStepPrev() { 132 function handleStepPrev() {
143 current.value--; 133 current.value--;
144 } 134 }
145 - function handleStepNext1(v) { 135 + function handleStepNext1(v, v1) {
  136 + console.log(v, v1);
146 current.value++; 137 current.value++;
147 getStepOneData.value = v; 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 function handleStep2Next(v) { 149 function handleStep2Next(v) {
150 current.value++; 150 current.value++;
  151 +
151 getStepTwoData.value = v; 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 function handleStep3Next(v) { 241 function handleStep3Next(v) {
155 current.value++; 242 current.value++;
156 getStepThreeData.value = v; 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 function handleRedo() { 262 function handleRedo() {
159 current.value = 0; 263 current.value = 0;
@@ -197,6 +301,7 @@ @@ -197,6 +301,7 @@
197 return; 301 return;
198 }; 302 };
199 return { 303 return {
  304 + handleChange,
200 DeviceProfileStep2Ref, 305 DeviceProfileStep2Ref,
201 DeviceProfileStep3Ref, 306 DeviceProfileStep3Ref,
202 DeviceProfileStep4Ref, 307 DeviceProfileStep4Ref,
@@ -2,8 +2,9 @@ import { BasicColumn } from '/@/components/Table'; @@ -2,8 +2,9 @@ import { BasicColumn } from '/@/components/Table';
2 import { FormSchema } from '/@/components/Table'; 2 import { FormSchema } from '/@/components/Table';
3 import { findDictItemByCode } from '/@/api/system/dict'; 3 import { findDictItemByCode } from '/@/api/system/dict';
4 import { MessageEnum } from '/@/enums/messageEnum'; 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 export const columns: BasicColumn[] = [ 9 export const columns: BasicColumn[] = [
9 { 10 {
@@ -30,23 +31,27 @@ export const columns: BasicColumn[] = [ @@ -30,23 +31,27 @@ export const columns: BasicColumn[] = [
30 31
31 export const searchFormSchema: FormSchema[] = [ 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 field: 'name', 34 field: 'name',
47 label: '配置名称', 35 label: '配置名称',
48 component: 'Input', 36 component: 'Input',
49 colProps: { span: 8 }, 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,6 +68,10 @@ export const formSchema: FormSchema[] = [
63 label: '配置名称', 68 label: '配置名称',
64 required: true, 69 required: true,
65 component: 'Input', 70 component: 'Input',
  71 + componentProps: {
  72 + maxLength: 255,
  73 + placeholder: '请输入配置名称',
  74 + },
66 }, 75 },
67 { 76 {
68 field: 'messageType', 77 field: 'messageType',
@@ -98,6 +107,11 @@ export const formSchema: FormSchema[] = [ @@ -98,6 +107,11 @@ export const formSchema: FormSchema[] = [
98 label: 'accessKeyId', 107 label: 'accessKeyId',
99 required: true, 108 required: true,
100 component: 'Input', 109 component: 'Input',
  110 + componentProps: {
  111 + maxLength: 36,
  112 + placeholder: '请输入accessKeyId',
  113 + },
  114 +
101 ifShow: ({ values }) => isMessage(Reflect.get(values, 'messageType')), 115 ifShow: ({ values }) => isMessage(Reflect.get(values, 'messageType')),
102 }, 116 },
103 { 117 {
@@ -105,6 +119,11 @@ export const formSchema: FormSchema[] = [ @@ -105,6 +119,11 @@ export const formSchema: FormSchema[] = [
105 label: 'accessKeySecret', 119 label: 'accessKeySecret',
106 required: true, 120 required: true,
107 component: 'Input', 121 component: 'Input',
  122 + componentProps: {
  123 + maxLength: 36,
  124 + placeholder: '请输入accessKeySecret',
  125 + },
  126 +
108 ifShow: ({ values }) => isMessage(Reflect.get(values, 'messageType')), 127 ifShow: ({ values }) => isMessage(Reflect.get(values, 'messageType')),
109 }, 128 },
110 { 129 {
@@ -113,6 +132,11 @@ export const formSchema: FormSchema[] = [ @@ -113,6 +132,11 @@ export const formSchema: FormSchema[] = [
113 defaultValue: 'smtp.163.com', 132 defaultValue: 'smtp.163.com',
114 required: true, 133 required: true,
115 component: 'Input', 134 component: 'Input',
  135 + componentProps: {
  136 + maxLength: 36,
  137 + placeholder: '请输入accessKeySecret',
  138 + },
  139 +
116 ifShow: ({ values }) => isEmail(Reflect.get(values, 'messageType')), 140 ifShow: ({ values }) => isEmail(Reflect.get(values, 'messageType')),
117 }, 141 },
118 { 142 {
@@ -121,6 +145,12 @@ export const formSchema: FormSchema[] = [ @@ -121,6 +145,12 @@ export const formSchema: FormSchema[] = [
121 defaultValue: 25, 145 defaultValue: 25,
122 required: true, 146 required: true,
123 component: 'InputNumber', 147 component: 'InputNumber',
  148 + rules: numberRule,
  149 + componentProps: {
  150 + maxLength: 36,
  151 + placeholder: '请输入端口',
  152 + },
  153 +
124 ifShow: ({ values }) => isEmail(Reflect.get(values, 'messageType')), 154 ifShow: ({ values }) => isEmail(Reflect.get(values, 'messageType')),
125 }, 155 },
126 { 156 {
@@ -128,6 +158,11 @@ export const formSchema: FormSchema[] = [ @@ -128,6 +158,11 @@ export const formSchema: FormSchema[] = [
128 label: '用户名', 158 label: '用户名',
129 required: true, 159 required: true,
130 component: 'Input', 160 component: 'Input',
  161 + componentProps: {
  162 + maxLength: 255,
  163 + placeholder: '请输入用户名',
  164 + },
  165 +
131 ifShow: ({ values }) => isEmail(Reflect.get(values, 'messageType')), 166 ifShow: ({ values }) => isEmail(Reflect.get(values, 'messageType')),
132 }, 167 },
133 { 168 {
@@ -142,12 +177,46 @@ export const formSchema: FormSchema[] = [ @@ -142,12 +177,46 @@ export const formSchema: FormSchema[] = [
142 label: '消息配置', 177 label: '消息配置',
143 component: 'Input', 178 component: 'Input',
144 show: false, 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 field: 'id', 199 field: 'id',
148 label: '主键', 200 label: '主键',
149 component: 'Input', 201 component: 'Input',
150 show: false, 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 field: 'status', 222 field: 'status',
@@ -165,5 +234,22 @@ export const formSchema: FormSchema[] = [ @@ -165,5 +234,22 @@ export const formSchema: FormSchema[] = [
165 label: '备注', 234 label: '备注',
166 field: 'remark', 235 field: 'remark',
167 component: 'InputTextArea', 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,65 +21,69 @@
21 /></TabPane> 21 /></TabPane>
22 <TabPane key="3" tab="报警规则"> 22 <TabPane key="3" tab="报警规则">
23 <div style="padding-top: 10px"> 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 </div> 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 <p>清除报警规则</p> 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 </div> 87 </div>
84 </div> 88 </div>
85 </TabPane> 89 </TabPane>
@@ -93,7 +97,7 @@ @@ -93,7 +97,7 @@
93 <script lang="ts"> 97 <script lang="ts">
94 import { defineComponent, ref, computed, watch } from 'vue'; 98 import { defineComponent, ref, computed, watch } from 'vue';
95 import { BasicModal, useModalInner } from '/@/components/Modal'; 99 import { BasicModal, useModalInner } from '/@/components/Modal';
96 - import { Tabs, TabPane } from 'ant-design-vue'; 100 + import { Tabs } from 'ant-design-vue';
97 import { deviceConfigGetDetail } from '/@/api/device/deviceConfigApi'; 101 import { deviceConfigGetDetail } from '/@/api/device/deviceConfigApi';
98 import { BasicForm, useForm } from '/@/components/Form/index'; 102 import { BasicForm, useForm } from '/@/components/Form/index';
99 import { 103 import {
@@ -116,14 +120,14 @@ @@ -116,14 +120,14 @@
116 120
117 export default defineComponent({ 121 export default defineComponent({
118 name: 'ConfigDrawer', 122 name: 'ConfigDrawer',
119 - components: { Tabs, TabPane, BasicModal, BasicForm }, 123 + components: { Tabs, TabPane: Tabs.TabPane, BasicModal, BasicForm },
120 emits: ['success', 'register'], 124 emits: ['success', 'register'],
121 setup() { 125 setup() {
122 const activeKey = ref('1'); 126 const activeKey = ref('1');
123 const isUpdate = ref(true); 127 const isUpdate = ref(true);
124 const descInfo: any = ref(null); 128 const descInfo: any = ref(null);
125 const dataInfo: any = ref(''); 129 const dataInfo: any = ref('');
126 - const [registerDetail, { setFieldsValue: setRegisterDetail }] = useForm({ 130 + const [registerDetail, { resetFields, setFieldsValue: setRegisterDetail }] = useForm({
127 schemas: step1Schemas, 131 schemas: step1Schemas,
128 actionColOptions: { 132 actionColOptions: {
129 span: 24, 133 span: 24,
@@ -219,8 +223,10 @@ @@ -219,8 +223,10 @@
219 const [register] = useModalInner(async (data) => { 223 const [register] = useModalInner(async (data) => {
220 activeKey.value = '1'; 224 activeKey.value = '1';
221 isUpdate.value = !!data?.isUpdate; 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 try { 228 try {
  229 + resetFields();
224 await setRegisterDetail({ ...descInfo.value }); 230 await setRegisterDetail({ ...descInfo.value });
225 } catch (e) { 231 } catch (e) {
226 return e; 232 return e;
@@ -229,84 +235,90 @@ @@ -229,84 +235,90 @@
229 const handleChange = (v) => { 235 const handleChange = (v) => {
230 try { 236 try {
231 switch (v) { 237 switch (v) {
232 - case '1':  
233 - setRegisterDetail({ ...descInfo.value });  
234 - break; 238 + // case '1':
  239 + // setRegisterDetail({ ...descInfo.value });
  240 + // break;
235 case '2': 241 case '2':
236 setRegisterTrans({ 242 setRegisterTrans({
237 transportType: descInfo.value.profileData?.transportConfiguration.type, 243 transportType: descInfo.value.profileData?.transportConfiguration.type,
238 }); 244 });
239 break; 245 break;
240 case '3': 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 case '4': 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 break; 322 break;
311 } 323 }
312 } catch (e) { 324 } catch (e) {
@@ -45,12 +45,12 @@ @@ -45,12 +45,12 @@
45 </BasicTable> 45 </BasicTable>
46 <DeviceProfileModal v-if="isJudgeStatus" @register="registerModal" @success="handleSuccess" /> 46 <DeviceProfileModal v-if="isJudgeStatus" @register="registerModal" @success="handleSuccess" />
47 <DeviceConfigDetail @register="registerModalDetail" @success="handleSuccess" /> 47 <DeviceConfigDetail @register="registerModalDetail" @success="handleSuccess" />
48 - <ExpExcelModal @register="register1" @success="defaultHeader" /> 48 + <!-- <ExpExcelModal @register="register1" @success="defaultHeader" /> -->
49 </div> 49 </div>
50 </template> 50 </template>
51 <script lang="ts"> 51 <script lang="ts">
52 import { defineComponent, ref, reactive } from 'vue'; 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 import { columns, searchFormSchema } from './device.profile.data'; 54 import { columns, searchFormSchema } from './device.profile.data';
55 import { useMessage } from '/@/hooks/web/useMessage'; 55 import { useMessage } from '/@/hooks/web/useMessage';
56 import { deviceConfigGetQuery, deviceConfigDelete } from '/@/api/device/deviceConfigApi'; 56 import { deviceConfigGetQuery, deviceConfigDelete } from '/@/api/device/deviceConfigApi';
@@ -58,7 +58,7 @@ @@ -58,7 +58,7 @@
58 import DeviceProfileModal from '/@/views/device/profile/DeviceProfileModal.vue'; 58 import DeviceProfileModal from '/@/views/device/profile/DeviceProfileModal.vue';
59 import DeviceConfigDetail from '/@/views/device/profile/deviceConfigDetail.vue'; 59 import DeviceConfigDetail from '/@/views/device/profile/deviceConfigDetail.vue';
60 import { ImpExcel, ExcelData } from '/@/components/Excel'; 60 import { ImpExcel, ExcelData } from '/@/components/Excel';
61 - import { jsonToSheetXlsx, ExportModalResult } from '/@/components/Excel'; 61 + // import { jsonToSheetXlsx, ExportModalResult } from '/@/components/Excel';
62 62
63 export default defineComponent({ 63 export default defineComponent({
64 name: 'DeviceProfileManagement', 64 name: 'DeviceProfileManagement',
@@ -156,23 +156,23 @@ @@ -156,23 +156,23 @@
156 isJudgeStatus.value = false; 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 const handleExport = (record: Recordable) => { 171 const handleExport = (record: Recordable) => {
172 console.log(record); 172 console.log(record);
173 - setTimeout(() => {  
174 - openModalExcel();  
175 - }, 50); 173 + // setTimeout(() => {
  174 + // openModalExcel();
  175 + // }, 50);
176 }; 176 };
177 function handleImport() { 177 function handleImport() {
178 console.log('record'); 178 console.log('record');
@@ -182,8 +182,8 @@ @@ -182,8 +182,8 @@
182 } 182 }
183 return { 183 return {
184 registerModalDetail, 184 registerModalDetail,
185 - register1,  
186 - defaultHeader, 185 + // register1,
  186 + // defaultHeader,
187 useSelectionChange, 187 useSelectionChange,
188 handleTableDel, 188 handleTableDel,
189 isJudgeStatus, 189 isJudgeStatus,
1 <template> 1 <template>
2 <div class="step1"> 2 <div class="step1">
3 <div class="step1-form"> 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 <BasicForm @register="register" /> 45 <BasicForm @register="register" />
5 </div> 46 </div>
6 </div> 47 </div>
7 </template> 48 </template>
8 <script lang="ts"> 49 <script lang="ts">
9 - import { defineComponent } from 'vue'; 50 + import { defineComponent, ref } from 'vue';
10 import { BasicForm, useForm } from '/@/components/Form'; 51 import { BasicForm, useForm } from '/@/components/Form';
11 import { step1Schemas } from './data'; 52 import { step1Schemas } from './data';
12 import { Select, Input, Divider } from 'ant-design-vue'; 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 export default defineComponent({ 60 export default defineComponent({
15 components: { 61 components: {
@@ -18,9 +64,13 @@ @@ -18,9 +64,13 @@
18 [Input.name]: Input, 64 [Input.name]: Input,
19 [Input.Group.name]: Input.Group, 65 [Input.Group.name]: Input.Group,
20 [Divider.name]: Divider, 66 [Divider.name]: Divider,
  67 + Upload,
  68 + PlusOutlined,
21 }, 69 },
22 emits: ['next', 'resetFunc'], 70 emits: ['next', 'resetFunc'],
23 setup(_, { emit }) { 71 setup(_, { emit }) {
  72 + const { createMessage } = useMessage();
  73 +
24 const [register, { validate, setFieldsValue, resetFields }] = useForm({ 74 const [register, { validate, setFieldsValue, resetFields }] = useForm({
25 labelWidth: 100, 75 labelWidth: 100,
26 schemas: step1Schemas, 76 schemas: step1Schemas,
@@ -36,16 +86,59 @@ @@ -36,16 +86,59 @@
36 const resetFieldsFunc = (v) => { 86 const resetFieldsFunc = (v) => {
37 setFieldsValue(v); 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 async function customSubmitFunc() { 122 async function customSubmitFunc() {
40 try { 123 try {
41 const values = await validate(); 124 const values = await validate();
42 - emit('next', values); 125 + emit('next', values, peresonalPic.value);
43 } catch (error) {} 126 } catch (error) {}
44 } 127 }
45 const customResetFunc = async () => { 128 const customResetFunc = async () => {
46 await resetFields(); 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 </script> 144 </script>
@@ -31,7 +31,7 @@ @@ -31,7 +31,7 @@
31 <template v-for="(childItem, createIndex) in item.alarms" :key="childItem.id"> 31 <template v-for="(childItem, createIndex) in item.alarms" :key="childItem.id">
32 <div class="aic" style="border: 1px solid #bfbfbf"> 32 <div class="aic" style="border: 1px solid #bfbfbf">
33 <div class="w-3/4"> 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 ><BasicForm @register="registerFormCreateAlarm" /> 35 ><BasicForm @register="registerFormCreateAlarm" />
36 </div> 36 </div>
37 <div style="margin-left: 5px; margin-top: -50px"> 37 <div style="margin-left: 5px; margin-top: -50px">
@@ -78,7 +78,7 @@ @@ -78,7 +78,7 @@
78 <div style="height: 20px"></div> 78 <div style="height: 20px"></div>
79 <p>清除报警规则</p> 79 <p>清除报警规则</p>
80 <template 80 <template
81 - v-for="(childClearItem, clearIndexItem) in item.alarms[clearIndex].clearRule" 81 + v-for="(childClearItem, clearIndexItem) in item.clearRule"
82 :key="childClearItem.id" 82 :key="childClearItem.id"
83 > 83 >
84 <div class="aic mb-1" style="border: 1px solid #bfbfbf"> 84 <div class="aic mb-1" style="border: 1px solid #bfbfbf">
@@ -222,12 +222,20 @@ @@ -222,12 +222,20 @@
222 const ruleClearTemplateData: any = ref(null); 222 const ruleClearTemplateData: any = ref(null);
223 const enableClearTemplateData: any = ref(null); 223 const enableClearTemplateData: any = ref(null);
224 const detailClearTemplateData: any = ref(null); 224 const detailClearTemplateData: any = ref(null);
  225 + const scheduleCustomValue: any = ref({});
  226 + const scheduleCustomClearValue: any = ref({});
225 const clearIndex = ref(-1); 227 const clearIndex = ref(-1);
  228 + const getSchduleCustomValue: any = ref([]);
  229 + const getSchduleClearCustomValue: any = ref([]);
226 //告警列表 230 //告警列表
227 let profileData = ref<IProfileData[]>([]); 231 let profileData = ref<IProfileData[]>([]);
228 const log = (e) => { 232 const log = (e) => {
229 console.log(e); 233 console.log(e);
230 }; 234 };
  235 + //编辑清空操作
  236 + const clearProfileDataFunc = () => {
  237 + unref(profileData).splice(0, 1);
  238 + };
231 //删除告警配置 239 //删除告警配置
232 const deleteAlarmRule = (index: number) => { 240 const deleteAlarmRule = (index: number) => {
233 unref(profileData).splice(index, 1); 241 unref(profileData).splice(index, 1);
@@ -254,26 +262,27 @@ @@ -254,26 +262,27 @@
254 id: Date.now() + Math.random() + '', 262 id: Date.now() + Math.random() + '',
255 alarmType: '', 263 alarmType: '',
256 createRules: {}, 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 propagate: false, 266 propagate: false,
274 propagateRelationTypes: [''], 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 //TODO Mobile dashboard: 288 //TODO Mobile dashboard:
@@ -342,6 +351,25 @@ @@ -342,6 +351,25 @@
342 const resetRegisterFormCreateAlarmFunc = () => { 351 const resetRegisterFormCreateAlarmFunc = () => {
343 resetRegisterFormCreateAlarm(); 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 const retryRegisterFormFunc = (v) => { 374 const retryRegisterFormFunc = (v) => {
347 setRegisterForm(v); 375 setRegisterForm(v);
@@ -352,6 +380,25 @@ @@ -352,6 +380,25 @@
352 const retryRegisterFormCreateAlarmFunc = (v) => { 380 const retryRegisterFormCreateAlarmFunc = (v) => {
353 setRegisterFormCreateAlarm(v); 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 const tempValue1: string = ref<string>(''); 402 const tempValue1: string = ref<string>('');
356 // 添加‘创建条件’ 403 // 添加‘创建条件’
357 const addCreateRole = (index: number) => { 404 const addCreateRole = (index: number) => {
@@ -400,27 +447,26 @@ @@ -400,27 +447,26 @@
400 }; 447 };
401 }, 448 },
402 }); 449 });
403 -  
404 unref(profileData)[index].alarms.push({ 450 unref(profileData)[index].alarms.push({
405 id: Date.now() + Math.random() + '', 451 id: Date.now() + Math.random() + '',
406 alarmType: '', 452 alarmType: '',
407 createRules: {}, 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 propagate: false, 470 propagate: false,
425 propagateRelationTypes: [''], 471 propagateRelationTypes: [''],
426 }); 472 });
@@ -486,12 +532,23 @@ @@ -486,12 +532,23 @@
486 console.log(e); 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 enableTemplateData.value = 544 enableTemplateData.value =
490 - v.startsOn == undefined 545 + v.schedule == 'ANY_TIME'
491 ? `始终启用` 546 ? `始终启用`
492 - : ` 547 + : v.schedule == 'SPECIFIC_TIME'
  548 + ? `
493 开始时间:${v.startsOn},结束时间:${v.endsOn},天数:${findDayByValue} 549 开始时间:${v.startsOn},结束时间:${v.endsOn},天数:${findDayByValue}
494 - `; 550 + `
  551 + : `天数:${findDayCustomByValue},开始时间: ${v.startsOn1},结束时间:${v.endsOn1}`;
495 }; 552 };
496 //规则条件 553 //规则条件
497 const getAllFieldsRuleFunc = (v, v1) => { 554 const getAllFieldsRuleFunc = (v, v1) => {
@@ -516,7 +573,7 @@ @@ -516,7 +573,7 @@
516 } 573 }
517 }); 574 });
518 ruleTemplateData.value = ` 575 ruleTemplateData.value = `
519 - 键名:${v.key1}...操作:${findRuleByValue?.label}...值:${v.value1} 576 + 键名:${v.key1} 操作:${findRuleByValue?.label} 值:${v.value1}
520 `; 577 `;
521 578
522 ruleLastObj.value = v1; 579 ruleLastObj.value = v1;
@@ -607,11 +664,23 @@ @@ -607,11 +664,23 @@
607 console.log(e); 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 enableClearTemplateData.value = 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 const getAllClearFieldsRuleFunc = (v, v1) => { 686 const getAllClearFieldsRuleFunc = (v, v1) => {
@@ -636,7 +705,7 @@ @@ -636,7 +705,7 @@
636 } 705 }
637 }); 706 });
638 ruleClearTemplateData.value = ` 707 ruleClearTemplateData.value = `
639 - 键名:${v.key1}...操作:${findRuleByValue?.label}...值:${v.value1} 708 + 键名:${v.key1} 操作:${findRuleByValue?.label} 值:${v.value1}
640 `; 709 `;
641 710
642 ruleLastObj.value = v1; 711 ruleLastObj.value = v1;
@@ -677,7 +746,7 @@ @@ -677,7 +746,7 @@
677 }; 746 };
678 Object.assign(addClearitionalObj.value, getValueConditon); 747 Object.assign(addClearitionalObj.value, getValueConditon);
679 }; 748 };
680 - //用于生成uuid 749 + //生成uuid
681 function generateUUID() { 750 function generateUUID() {
682 let d = new Date().getTime(); 751 let d = new Date().getTime();
683 if (window.performance && typeof window.performance.now === 'function') { 752 if (window.performance && typeof window.performance.now === 'function') {
@@ -691,28 +760,111 @@ @@ -691,28 +760,111 @@
691 return uuid; 760 return uuid;
692 } 761 }
693 const handleFormStep3toStep4Next = async () => { 762 const handleFormStep3toStep4Next = async () => {
  763 + console.log(enableObj.value);
694 try { 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 const scheduleClearValue = { 842 const scheduleClearValue = {
696 type: enableClearObj.value.schedule, 843 type: enableClearObj.value.schedule,
697 daysOfWeek: enableClearObj.value.daysOfWeek, 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 timezone: enableClearObj.value.timezone, 847 timezone: enableClearObj.value.timezone,
701 }; 848 };
702 const getClearSchedule = { 849 const getClearSchedule = {
703 - schedule: scheduleClearValue, 850 + schedule:
  851 + enableClearObj.value.schedule == 'CUSTOM'
  852 + ? scheduleCustomClearValue.value
  853 + : scheduleClearValue,
704 }; 854 };
705 const getClearAdditionalProp = Object.assign({}, detailClearObj.value, getClearSchedule); 855 const getClearAdditionalProp = Object.assign({}, detailClearObj.value, getClearSchedule);
706 const scheduleValue = { 856 const scheduleValue = {
707 type: enableObj.value.schedule, 857 type: enableObj.value.schedule,
708 daysOfWeek: enableObj.value.daysOfWeek, 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 timezone: enableObj.value.timezone, 861 timezone: enableObj.value.timezone,
712 }; 862 };
713 const getSchedule = { 863 const getSchedule = {
714 - schedule: scheduleValue, 864 + schedule:
  865 + enableObj.value.schedule == 'CUSTOM' ? scheduleCustomValue.value : scheduleValue,
715 }; 866 };
  867 +
716 const getAdditionalProp = Object.assign({}, detailObj.value, getSchedule); 868 const getAdditionalProp = Object.assign({}, detailObj.value, getSchedule);
717 const getScheduleAndAlarmDetails = Object.assign( 869 const getScheduleAndAlarmDetails = Object.assign(
718 {}, 870 {},
@@ -746,7 +898,7 @@ @@ -746,7 +898,7 @@
746 console.log(valueRegisterFormCreateAlarm); 898 console.log(valueRegisterFormCreateAlarm);
747 const getValueRegisterFormHighSetting = { 899 const getValueRegisterFormHighSetting = {
748 propagate: valueRegisterFormHighSetting?.propagate, 900 propagate: valueRegisterFormHighSetting?.propagate,
749 - propagateRelationTypes: [valueRegisterFormHighSetting?.propagateRelationTypes], 901 + propagateRelationTypes: [valueRegisterFormHighSetting?.propagateRelationTypes].flat(1),
750 }; 902 };
751 Object.assign( 903 Object.assign(
752 emptyObj.value, 904 emptyObj.value,
@@ -756,7 +908,9 @@ @@ -756,7 +908,9 @@
756 getClearRulesAllObj, 908 getClearRulesAllObj,
757 objectId 909 objectId
758 ); 910 );
759 - alarmss.value.push(emptyObj.value); 911 + if (alarmss.value.length == 0) {
  912 + alarmss.value.push(emptyObj.value);
  913 + }
760 const getAlarms = { 914 const getAlarms = {
761 alarms: alarmss.value, 915 alarms: alarmss.value,
762 }; 916 };
@@ -795,7 +949,11 @@ @@ -795,7 +949,11 @@
795 isRuleAlarmRuleConditions.value = 4; 949 isRuleAlarmRuleConditions.value = 4;
796 setTimeout(() => { 950 setTimeout(() => {
797 openModal4(true); 951 openModal4(true);
798 - proxy.$refs.getChildData1.resetDataFunc(); 952 + try {
  953 + proxy.$refs.getChildData1.resetDataFunc();
  954 + } catch (e) {
  955 + return e;
  956 + }
799 }, 50); 957 }, 50);
800 }; 958 };
801 const handleOpenClearEnableRule = () => { 959 const handleOpenClearEnableRule = () => {
@@ -814,6 +972,19 @@ @@ -814,6 +972,19 @@
814 }; 972 };
815 973
816 return { 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 clearIndex, 988 clearIndex,
818 retryRegisterFormFunc, 989 retryRegisterFormFunc,
819 retryRegisterFormHighSettingmFunc, 990 retryRegisterFormHighSettingmFunc,
@@ -99,7 +99,7 @@ export const formSchema: FormSchema[] = [ @@ -99,7 +99,7 @@ export const formSchema: FormSchema[] = [
99 { 99 {
100 field: 'conditionType', 100 field: 'conditionType',
101 label: '条件类型', 101 label: '条件类型',
102 - colProps: { span: 24 }, 102 + colProps: { span: 13 },
103 component: 'Select', 103 component: 'Select',
104 componentProps: { 104 componentProps: {
105 placeholder: '请选择报警日程表', 105 placeholder: '请选择报警日程表',
@@ -177,11 +177,28 @@ export const formSchema: FormSchema[] = [ @@ -177,11 +177,28 @@ export const formSchema: FormSchema[] = [
177 { 177 {
178 field: 'defaultValue', 178 field: 'defaultValue',
179 label: '持续时间值', 179 label: '持续时间值',
180 - colProps: { span: 24 }, 180 + colProps: { span: 13 },
181 component: 'Input', 181 component: 'Input',
182 componentProps: { 182 componentProps: {
  183 + maxLength: 16,
183 placeholder: '请输入持续时间值(请输入数字)', 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 ifShow: ({ values }) => isWenDu(Reflect.get(values, 'conditionType')), 202 ifShow: ({ values }) => isWenDu(Reflect.get(values, 'conditionType')),
186 show: ({ values }) => { 203 show: ({ values }) => {
187 return !values.field5; 204 return !values.field5;
@@ -210,7 +227,7 @@ export const formSchema: FormSchema[] = [ @@ -210,7 +227,7 @@ export const formSchema: FormSchema[] = [
210 { 227 {
211 field: 'unit', 228 field: 'unit',
212 label: '时间单位', 229 label: '时间单位',
213 - colProps: { span: 24 }, 230 + colProps: { span: 13 },
214 component: 'Select', 231 component: 'Select',
215 componentProps: { 232 componentProps: {
216 placeholder: '请选择时间单位', 233 placeholder: '请选择时间单位',
@@ -226,12 +243,28 @@ export const formSchema: FormSchema[] = [ @@ -226,12 +243,28 @@ export const formSchema: FormSchema[] = [
226 { 243 {
227 field: 'defaultValue', 244 field: 'defaultValue',
228 label: '事件计数值必填', 245 label: '事件计数值必填',
229 - colProps: { span: 24 }, 246 + colProps: { span: 13 },
230 component: 'Input', 247 component: 'Input',
231 componentProps: { 248 componentProps: {
  249 + maxLength: 2147483637,
232 placeholder: '请输入事件计数值(应在1到2147483637之间)', 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 ifShow: ({ values }) => isTimeAll(Reflect.get(values, 'conditionType')), 268 ifShow: ({ values }) => isTimeAll(Reflect.get(values, 'conditionType')),
236 show: ({ values }) => { 269 show: ({ values }) => {
237 return !values.field6; 270 return !values.field6;
@@ -240,6 +273,7 @@ export const formSchema: FormSchema[] = [ @@ -240,6 +273,7 @@ export const formSchema: FormSchema[] = [
240 { 273 {
241 field: 'inherit', 274 field: 'inherit',
242 label: '', 275 label: '',
  276 + colProps: { span: 13 },
243 component: 'Checkbox', 277 component: 'Checkbox',
244 renderComponentContent: 'Inherit from owner', 278 renderComponentContent: 'Inherit from owner',
245 ifShow: ({ values }) => 279 ifShow: ({ values }) =>