Commit a60fcfe8f6eafd09e93a7c32cbc4f43ebf87f56a

Authored by fengistao
2 parents 9d634463 906f2771

Merge branch 'main' into ft-dev

@@ -72,18 +72,16 @@ export const deleteMessageTemplate = (ids: string[]) => @@ -72,18 +72,16 @@ export const deleteMessageTemplate = (ids: string[]) =>
72 * @param id 配置id 72 * @param id 配置id
73 * @param status 状态 73 * @param status 状态
74 */ 74 */
75 -export const setMessageTemplateStatus = (  
76 - id: string,  
77 - templatePurpose: string,  
78 - messageType: string,  
79 - status: number  
80 -) => 75 +
  76 +interface dataType {
  77 + id: string;
  78 + templatePurpose: string;
  79 + messageType: string;
  80 + status: number;
  81 + tenantId: string;
  82 +}
  83 +export const setMessageTemplateStatus = (data: dataType) =>
81 defHttp.put<MessageConfigResultModel>({ 84 defHttp.put<MessageConfigResultModel>({
82 url: MessageTemplateApi.TEMPLATE_URL, 85 url: MessageTemplateApi.TEMPLATE_URL,
83 - data: {  
84 - id,  
85 - status,  
86 - templatePurpose,  
87 - messageType,  
88 - }, 86 + data,
89 }); 87 });
1 -<template> 111</template>  
@@ -41,7 +41,7 @@ @@ -41,7 +41,7 @@
41 41
42 import { defineComponent } from 'vue'; 42 import { defineComponent } from 'vue';
43 import { Dropdown, Menu, Popconfirm } from 'ant-design-vue'; 43 import { Dropdown, Menu, Popconfirm } from 'ant-design-vue';
44 - // import { Icon } from '/@/components/Icon'; 44 + import { Icon } from '/@/components/Icon';
45 import { omit } from 'lodash-es'; 45 import { omit } from 'lodash-es';
46 import { isFunction } from '/@/utils/is'; 46 import { isFunction } from '/@/utils/is';
47 47
@@ -52,7 +52,7 @@ @@ -52,7 +52,7 @@
52 Menu, 52 Menu,
53 MenuItem: Menu.Item, 53 MenuItem: Menu.Item,
54 MenuDivider: Menu.Divider, 54 MenuDivider: Menu.Divider,
55 - // Icon, 55 + Icon,
56 Popconfirm, 56 Popconfirm,
57 }, 57 },
58 props: { 58 props: {
@@ -88,7 +88,7 @@ @@ -88,7 +88,7 @@
88 const wrapEl = unref(wrapRef); 88 const wrapEl = unref(wrapRef);
89 const map = new BMap.Map(wrapEl); 89 const map = new BMap.Map(wrapEl);
90 if (record.deviceInfo.address) { 90 if (record.deviceInfo.address) {
91 - const { name, organizationDTO, updateTime, deviceState } = record; 91 + const { name, organizationDTO, updateTime, deviceState, deviceProfile } = record;
92 const { longitude, latitude, address } = record.deviceInfo; 92 const { longitude, latitude, address } = record.deviceInfo;
93 const point = new BMap.Point(longitude, latitude); 93 const point = new BMap.Point(longitude, latitude);
94 let options = { 94 let options = {
@@ -110,7 +110,7 @@ @@ -110,7 +110,7 @@
110 } 110 }
111 </div> 111 </div>
112 <div>所属组织:${organizationDTO.name}</div> 112 <div>所属组织:${organizationDTO.name}</div>
113 - <div style="margin-top:6px;">接入协议:${address}</div> 113 + <div style="margin-top:6px;">接入协议:${deviceProfile.transportType}</div>
114 <div style="margin-top:6px;">设备位置:${address}</div> 114 <div style="margin-top:6px;">设备位置:${address}</div>
115 <div style="margin-top:6px;">下线时间:${updateTime}</div> 115 <div style="margin-top:6px;">下线时间:${updateTime}</div>
116 <div style="display:flex;justify-content:space-between; margin-top:10px"> 116 <div style="display:flex;justify-content:space-between; margin-top:10px">
1 <template> 1 <template>
2 <div> 2 <div>
3 <PageWrapper dense contentFullHeight fixedHeight contentClass="flex"> 3 <PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
4 - <OrganizationIdTree class="w-1/4 xl:w-1/5" @select="handleSelect" /> 4 + <OrganizationIdTree
  5 + class="w-1/4 xl:w-1/5"
  6 + @select="handleSelect"
  7 + ref="organizationIdTreeRef"
  8 + />
5 <BasicTable @register="registerTable" :searchInfo="searchInfo" class="w-3/4 xl:w-4/5"> 9 <BasicTable @register="registerTable" :searchInfo="searchInfo" class="w-3/4 xl:w-4/5">
6 <template #toolbar> 10 <template #toolbar>
7 <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增联系人 </a-button> 11 <a-button type="primary" @click="handleCreateOrEdit(null)"> 新增联系人 </a-button>
@@ -47,7 +51,8 @@ @@ -47,7 +51,8 @@
47 import { useMessage } from '/@/hooks/web/useMessage'; 51 import { useMessage } from '/@/hooks/web/useMessage';
48 import { useDrawer } from '/@/components/Drawer'; 52 import { useDrawer } from '/@/components/Drawer';
49 import ContactDrawer from './ContactDrawer.vue'; 53 import ContactDrawer from './ContactDrawer.vue';
50 - import OrganizationIdTree from '../../common/OrganizationIdTree.vue'; 54 + import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree';
  55 +
51 import { getAlarmContact, deleteAlarmContact } from '/@/api/alarm/contact/alarmContact'; 56 import { getAlarmContact, deleteAlarmContact } from '/@/api/alarm/contact/alarmContact';
52 import { searchFormSchema, columns } from './config.data'; 57 import { searchFormSchema, columns } from './config.data';
53 export default defineComponent({ 58 export default defineComponent({
@@ -65,6 +70,8 @@ @@ -65,6 +70,8 @@
65 const onSelectRowChange = (selectedRowKeys: string[]) => { 70 const onSelectRowChange = (selectedRowKeys: string[]) => {
66 selectedRowIds.value = selectedRowKeys; 71 selectedRowIds.value = selectedRowKeys;
67 }; 72 };
  73 + const searchInfo = reactive<Recordable>({});
  74 + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
68 // 表格hooks 75 // 表格hooks
69 const [registerTable, { reload }] = useTable({ 76 const [registerTable, { reload }] = useTable({
70 api: getAlarmContact, 77 api: getAlarmContact,
@@ -73,6 +80,7 @@ @@ -73,6 +80,7 @@
73 formConfig: { 80 formConfig: {
74 labelWidth: 120, 81 labelWidth: 120,
75 schemas: searchFormSchema, 82 schemas: searchFormSchema,
  83 + resetFunc: resetFn,
76 }, 84 },
77 useSearchForm: true, 85 useSearchForm: true,
78 showTableSetting: true, 86 showTableSetting: true,
@@ -93,7 +101,7 @@ @@ -93,7 +101,7 @@
93 // 弹框 101 // 弹框
94 const [registerDrawer, { openDrawer }] = useDrawer(); 102 const [registerDrawer, { openDrawer }] = useDrawer();
95 const { createMessage } = useMessage(); 103 const { createMessage } = useMessage();
96 - const searchInfo = reactive<Recordable>({}); 104 +
97 // 刷新 105 // 刷新
98 const handleSuccess = () => { 106 const handleSuccess = () => {
99 reload(); 107 reload();
@@ -147,6 +155,7 @@ @@ -147,6 +155,7 @@
147 handleSuccess, 155 handleSuccess,
148 registerTable, 156 registerTable,
149 registerDrawer, 157 registerDrawer,
  158 + organizationIdTreeRef,
150 }; 159 };
151 }, 160 },
152 }); 161 });
  1 +/**
  2 + * 这是一个重置OrganizationIdTree组件的hooks,目的是用于重置分页查询的字段。
  3 + *
  4 + * 使用方式 const {organizationIdTreeRef,resetFn} = useResetOrganizationTree()
  5 + *
  6 + * organizationIdTreeRef 将ref和organizationIdTreeRef绑定即可,第二个是重置的方法
  7 + */
  8 +
  9 +import { ref } from 'vue';
  10 +import organizationIdTree from '../OrganizationIdTree.vue';
  11 +export const useResetOrganizationTree = (searchInfo: Recordable) => {
  12 + const organizationIdTreeRef = ref<InstanceType<typeof organizationIdTree>>();
  13 + async function resetFn() {
  14 + organizationIdTreeRef.value.resetOrganization();
  15 + searchInfo.organizationId = null;
  16 + }
  17 + return { organizationIdTreeRef, resetFn };
  18 +};
  1 +import { useResetOrganizationTree } from './hooks/useOrganization';
  2 +import OrganizationIdTree from './src/OrganizationIdTree.vue';
  3 +
  4 +export { OrganizationIdTree, useResetOrganizationTree };
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 :clickRowToExpand="false" 7 :clickRowToExpand="false"
8 :treeData="treeData" 8 :treeData="treeData"
9 :replaceFields="{ key: 'id', title: 'name' }" 9 :replaceFields="{ key: 'id', title: 'name' }"
  10 + v-model:selectedKeys="selectedKeys"
10 @select="handleSelect" 11 @select="handleSelect"
11 /> 12 />
12 </div> 13 </div>
@@ -24,7 +25,7 @@ @@ -24,7 +25,7 @@
24 emits: ['select'], 25 emits: ['select'],
25 setup(_, { emit }) { 26 setup(_, { emit }) {
26 const treeData = ref<TreeItem[]>([]); 27 const treeData = ref<TreeItem[]>([]);
27 - 28 + const selectedKeys = ref<string[]>();
28 async function fetch() { 29 async function fetch() {
29 treeData.value = (await getOrganizationList()) as unknown as TreeItem[]; 30 treeData.value = (await getOrganizationList()) as unknown as TreeItem[];
30 } 31 }
@@ -32,11 +33,14 @@ @@ -32,11 +33,14 @@
32 function handleSelect(keys) { 33 function handleSelect(keys) {
33 emit('select', keys[0]); 34 emit('select', keys[0]);
34 } 35 }
  36 + function resetOrganization() {
  37 + selectedKeys.value = [];
  38 + }
35 39
36 onMounted(() => { 40 onMounted(() => {
37 fetch(); 41 fetch();
38 }); 42 });
39 - return { treeData, handleSelect }; 43 + return { treeData, handleSelect, resetOrganization, selectedKeys };
40 }, 44 },
41 }); 45 });
42 </script> 46 </script>
1 <template> 1 <template>
2 <div> 2 <div>
3 <PageWrapper dense contentFullHeight contentClass="flex"> 3 <PageWrapper dense contentFullHeight contentClass="flex">
4 - <OrganizationIdTree class="w-1/6 xl:w-1/5" @select="handleSelect" /> 4 + <OrganizationIdTree
  5 + class="w-1/6 xl:w-1/5"
  6 + @select="handleSelect"
  7 + ref="organizationIdTreeRef"
  8 + />
5 <BasicTable @register="registerTable" class="w-5/6 xl:w-4/5"> 9 <BasicTable @register="registerTable" class="w-5/6 xl:w-4/5">
6 <template #toolbar> 10 <template #toolbar>
7 <a-button type="primary" @click="handleCreate"> 新增设备 </a-button> 11 <a-button type="primary" @click="handleCreate"> 新增设备 </a-button>
@@ -86,7 +90,8 @@ @@ -86,7 +90,8 @@
86 import { useGo } from '/@/hooks/web/usePage'; 90 import { useGo } from '/@/hooks/web/usePage';
87 import { PageWrapper } from '/@/components/Page'; 91 import { PageWrapper } from '/@/components/Page';
88 import { useModal } from '/@/components/Modal'; 92 import { useModal } from '/@/components/Modal';
89 - import OrganizationIdTree from '/@/views/common/OrganizationIdTree.vue'; 93 + import { OrganizationIdTree, useResetOrganizationTree } from '/@/views/common/organizationIdTree';
  94 +
90 import DeviceModal from './cpns/modal/DeviceModal.vue'; 95 import DeviceModal from './cpns/modal/DeviceModal.vue';
91 import { useDrawer } from '/@/components/Drawer'; 96 import { useDrawer } from '/@/components/Drawer';
92 import DeviceDetailDrawer from './cpns/modal/DeviceDetailDrawer.vue'; 97 import DeviceDetailDrawer from './cpns/modal/DeviceDetailDrawer.vue';
@@ -107,6 +112,7 @@ @@ -107,6 +112,7 @@
107 const go = useGo(); 112 const go = useGo();
108 113
109 const searchInfo = reactive<Recordable>({}); 114 const searchInfo = reactive<Recordable>({});
  115 + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
110 const [registerModal, { openModal }] = useModal(); 116 const [registerModal, { openModal }] = useModal();
111 const [registerDetailDrawer, { openDrawer }] = useDrawer(); 117 const [registerDetailDrawer, { openDrawer }] = useDrawer();
112 const [registerTable, { reload }] = useTable({ 118 const [registerTable, { reload }] = useTable({
@@ -116,6 +122,7 @@ @@ -116,6 +122,7 @@
116 formConfig: { 122 formConfig: {
117 labelWidth: 120, 123 labelWidth: 120,
118 schemas: searchFormSchema, 124 schemas: searchFormSchema,
  125 + resetFunc: resetFn,
119 }, 126 },
120 useSearchForm: true, 127 useSearchForm: true,
121 showTableSetting: true, 128 showTableSetting: true,
@@ -188,6 +195,7 @@ @@ -188,6 +195,7 @@
188 DeviceTypeEnum, 195 DeviceTypeEnum,
189 DeviceState, 196 DeviceState,
190 searchInfo, 197 searchInfo,
  198 + organizationIdTreeRef,
191 }; 199 };
192 }, 200 },
193 }); 201 });
  1 +import { MessageTypeEnum } from '/@/api/tenant/tenantInfo';
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 { h } from 'vue'; 4 import { h } from 'vue';
@@ -28,7 +29,13 @@ export const columns: BasicColumn[] = [ @@ -28,7 +29,13 @@ export const columns: BasicColumn[] = [
28 title: '平台类型', 29 title: '平台类型',
29 dataIndex: 'platformType', 30 dataIndex: 'platformType',
30 format: (_, record: Recordable) => { 31 format: (_, record: Recordable) => {
31 - return record.platformType === 'ALI_CLOUD' ? '阿里云平台' : '腾讯云平台'; 32 + return record.messageType === MessageTypeEnum.EMAIL_MESSAGE
  33 + ? '无'
  34 + : record.messageType === MessageTypeEnum.PHONE_MESSAGE
  35 + ? record.platformType === 'ALI_CLOUD'
  36 + ? '阿里云平台'
  37 + : '腾讯云平台'
  38 + : '无';
32 }, 39 },
33 width: 180, 40 width: 180,
34 }, 41 },
@@ -39,9 +39,7 @@ @@ -39,9 +39,7 @@
39 for (const key in config) { 39 for (const key in config) {
40 Reflect.set(data.record, key + '', config[key]); 40 Reflect.set(data.record, key + '', config[key]);
41 } 41 }
42 - await setFieldsValue({  
43 - ...data.record,  
44 - }); 42 + await setFieldsValue(data.record);
45 } 43 }
46 }); 44 });
47 45
@@ -49,10 +49,17 @@ export const columns: BasicColumn[] = [ @@ -49,10 +49,17 @@ export const columns: BasicColumn[] = [
49 unCheckedChildren: '已禁用', 49 unCheckedChildren: '已禁用',
50 loading: record.pendingStatus, 50 loading: record.pendingStatus,
51 onChange(checked: boolean) { 51 onChange(checked: boolean) {
  52 + const { id, templatePurpose, messageType, tenantId } = record;
52 record.pendingStatus = true; 53 record.pendingStatus = true;
53 const newStatus = checked ? 1 : 0; 54 const newStatus = checked ? 1 : 0;
54 const { createMessage } = useMessage(); 55 const { createMessage } = useMessage();
55 - setMessageTemplateStatus(record.id, record.templatePurpose, record.messageType, newStatus) 56 + setMessageTemplateStatus({
  57 + id,
  58 + templatePurpose,
  59 + messageType,
  60 + tenantId,
  61 + status: newStatus,
  62 + })
56 .then(() => { 63 .then(() => {
57 record.status = newStatus; 64 record.status = newStatus;
58 createMessage.success(`修改成功`); 65 createMessage.success(`修改成功`);
@@ -163,4 +170,10 @@ export const formSchema: FormSchema[] = [ @@ -163,4 +170,10 @@ export const formSchema: FormSchema[] = [
163 valueField: 'itemValue', 170 valueField: 'itemValue',
164 }, 171 },
165 }, 172 },
  173 + {
  174 + field: 'tenantId',
  175 + label: '租户ID',
  176 + component: 'Input',
  177 + show: false,
  178 + },
166 ]; 179 ];
1 <template> 1 <template>
2 <div> 2 <div>
3 - <PageWrapper dense contentFullHeight fixedHeight contentClass="flex">  
4 - <OrganizationIdTree class="w-1/4 xl:w-1/5" @select="handleSelect" />  
5 - <BasicTable @register="registerTable" class="w-3/4 xl:w-4/5" :searchInfo="searchInfo"> 3 + <PageWrapper dense contentFullHeight contentClass="flex">
  4 + <OrganizationIdTree
  5 + class="w-1/4 xl:w-1/5"
  6 + @select="handleSelect"
  7 + ref="organizationIdTreeRef"
  8 + />
  9 + <BasicTable @register="registerTable" class="w-3/4 xl:w-4/5">
6 <template #toolbar> 10 <template #toolbar>
7 <a-button type="primary" @click="handleCreate">新增账号</a-button> 11 <a-button type="primary" @click="handleCreate">新增账号</a-button>
8 </template> 12 </template>
@@ -63,13 +67,10 @@ @@ -63,13 +67,10 @@
63 </template> 67 </template>
64 <script lang="ts"> 68 <script lang="ts">
65 import { defineComponent, reactive } from 'vue'; 69 import { defineComponent, reactive } from 'vue';
66 -  
67 - import { TenantCodeEnum } from '/@/enums/codeEnum';  
68 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 70 import { BasicTable, useTable, TableAction } from '/@/components/Table';
69 import { deleteUser, getAccountList } from '/@/api/system/system'; 71 import { deleteUser, getAccountList } from '/@/api/system/system';
70 import { PageWrapper } from '/@/components/Page'; 72 import { PageWrapper } from '/@/components/Page';
71 -  
72 - import OrganizationIdTree from '../../common/OrganizationIdTree.vue'; 73 + import { useResetOrganizationTree, OrganizationIdTree } from '/@/views/common/organizationIdTree';
73 import { Tag } from 'ant-design-vue'; 74 import { Tag } from 'ant-design-vue';
74 import { useModal } from '/@/components/Modal'; 75 import { useModal } from '/@/components/Modal';
75 import AccountModal from './AccountModal.vue'; 76 import AccountModal from './AccountModal.vue';
@@ -85,23 +86,23 @@ @@ -85,23 +86,23 @@
85 const go = useGo(); 86 const go = useGo();
86 const [registerModal, { openModal }] = useModal(); 87 const [registerModal, { openModal }] = useModal();
87 const { createMessage } = useMessage(); 88 const { createMessage } = useMessage();
88 - const searchInfo = reactive<Recordable>({}); 89 + let searchInfo = reactive<Recordable>({});
  90 + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
89 const [registerTable, { reload, updateTableDataRecord }] = useTable({ 91 const [registerTable, { reload, updateTableDataRecord }] = useTable({
90 title: '账号列表', 92 title: '账号列表',
91 api: getAccountList, 93 api: getAccountList,
92 rowKey: 'id', 94 rowKey: 'id',
93 columns, 95 columns,
  96 + searchInfo,
94 formConfig: { 97 formConfig: {
95 labelWidth: 120, 98 labelWidth: 120,
96 schemas: searchFormSchema, 99 schemas: searchFormSchema,
97 autoSubmitOnEnter: true, 100 autoSubmitOnEnter: true,
  101 + resetFunc: resetFn,
98 }, 102 },
99 useSearchForm: true, 103 useSearchForm: true,
100 showTableSetting: true, 104 showTableSetting: true,
101 bordered: true, 105 bordered: true,
102 - handleSearchInfoFn(info) {  
103 - return info;  
104 - },  
105 actionColumn: { 106 actionColumn: {
106 width: 220, 107 width: 220,
107 title: '操作', 108 title: '操作',
@@ -115,7 +116,6 @@ @@ -115,7 +116,6 @@
115 isUpdate: false, 116 isUpdate: false,
116 }); 117 });
117 } 118 }
118 -  
119 function handleEdit(record: Recordable) { 119 function handleEdit(record: Recordable) {
120 openModal(true, { 120 openModal(true, {
121 record, 121 record,
@@ -159,8 +159,7 @@ @@ -159,8 +159,7 @@
159 handleSuccess, 159 handleSuccess,
160 handleSelect, 160 handleSelect,
161 handleView, 161 handleView,
162 - searchInfo,  
163 - TenantCodeEnum, 162 + organizationIdTreeRef,
164 }; 163 };
165 }, 164 },
166 }); 165 });
@@ -16,7 +16,8 @@ @@ -16,7 +16,8 @@
16 import { BasicForm, FormSchema, useForm } from '/@/components/Form/index'; 16 import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
17 import { saveTenantAdmin } from '/@/api/tenant/tenantApi'; 17 import { saveTenantAdmin } from '/@/api/tenant/tenantApi';
18 import { UserDTO } from '/@/api/tenant/tenantInfo'; 18 import { UserDTO } from '/@/api/tenant/tenantInfo';
19 - import { emailRule, phoneRule } from '/@/utils/rules'; 19 + import { ChineseRegexp, EmailRegexp, emailRule, phoneRule } from '/@/utils/rules';
  20 + import { isAccountExist } from '/@/api/system/system';
20 21
21 export default defineComponent({ 22 export default defineComponent({
22 name: 'TenantAdminFormDrawer', 23 name: 'TenantAdminFormDrawer',
@@ -38,8 +39,36 @@ @@ -38,8 +39,36 @@
38 { 39 {
39 field: 'username', 40 field: 'username',
40 label: '账号', 41 label: '账号',
41 - required: true,  
42 component: 'Input', 42 component: 'Input',
  43 + dynamicRules: ({ values }) => {
  44 + return [
  45 + {
  46 + validator(_, value) {
  47 + return new Promise((resolve, reject) => {
  48 + if (value == '') {
  49 + reject('请输入账号');
  50 + } else if (ChineseRegexp.test(value)) {
  51 + reject('账号不能含有中文');
  52 + } else if (EmailRegexp.test(value)) {
  53 + reject('账号不能为电子邮箱格式');
  54 + } else {
  55 + if (values.username != undefined && values.id == undefined) {
  56 + isAccountExist(value).then((data) => {
  57 + if (data.data != null) {
  58 + reject('账号已存在');
  59 + } else {
  60 + resolve();
  61 + }
  62 + });
  63 + } else {
  64 + resolve();
  65 + }
  66 + }
  67 + });
  68 + },
  69 + },
  70 + ];
  71 + },
43 }, 72 },
44 { 73 {
45 field: 'realName', 74 field: 'realName',
@@ -86,7 +115,6 @@ @@ -86,7 +115,6 @@
86 await resetFields(); 115 await resetFields();
87 isUpdate.value = !!data?.isUpdate; 116 isUpdate.value = !!data?.isUpdate;
88 tenantId.value = data?.tenantId; 117 tenantId.value = data?.tenantId;
89 -  
90 if (unref(isUpdate)) { 118 if (unref(isUpdate)) {
91 await updateSchema({ field: 'username', componentProps: { disabled: true } }); 119 await updateSchema({ field: 'username', componentProps: { disabled: true } });
92 await setFieldsValue({ 120 await setFieldsValue({