Commit aee2e0b87e73089617f3f967125e89cd7c5507d1

Authored by xp.Huang
2 parents bc6a803e f96b5c82

Merge branch 'main_dev' into 'main'

fix:设备批量导入产品类型错误

See merge request yunteng/thingskit-front!1117
Showing 89 changed files with 1116 additions and 881 deletions
@@ -25,7 +25,7 @@ module.exports = defineConfig({ @@ -25,7 +25,7 @@ module.exports = defineConfig({
25 'plugin:jest/recommended', 25 'plugin:jest/recommended',
26 ], 26 ],
27 rules: { 27 rules: {
28 - 'no-console': 'error', 28 + 'no-console': ['error', { allow: ['warn', 'error'] }],
29 'vue/script-setup-uses-vars': 'error', 29 'vue/script-setup-uses-vars': 'error',
30 '@typescript-eslint/ban-ts-ignore': 'off', 30 '@typescript-eslint/ban-ts-ignore': 'off',
31 '@typescript-eslint/explicit-function-return-type': 'off', 31 '@typescript-eslint/explicit-function-return-type': 'off',
@@ -51,6 +51,11 @@ enum DeviceManagerApi { @@ -51,6 +51,11 @@ enum DeviceManagerApi {
51 * @description 通过设备列表获取设备信息 51 * @description 通过设备列表获取设备信息
52 */ 52 */
53 QUERY_DEVICES = '/device/get/devices', 53 QUERY_DEVICES = '/device/get/devices',
  54 +
  55 + /**
  56 + * @description 批量变更产品
  57 + */
  58 + BATCH_UPDATE_PRODUCT = '/device/batch/update',
54 } 59 }
55 60
56 export const devicePage = (params: DeviceQueryParam) => { 61 export const devicePage = (params: DeviceQueryParam) => {
@@ -378,3 +383,13 @@ export const doBatchClearAlarm = (ids: string[]) => { @@ -378,3 +383,13 @@ export const doBatchClearAlarm = (ids: string[]) => {
378 { joinPrefix: false } 383 { joinPrefix: false }
379 ); 384 );
380 }; 385 };
  386 +
  387 +export const doBatchUpdateProduct = (params: { deviceIds: string[]; deviceProfileId: string }) => {
  388 + return defHttp.post(
  389 + {
  390 + url: DeviceManagerApi.BATCH_UPDATE_PRODUCT,
  391 + data: params,
  392 + },
  393 + { joinPrefix: false }
  394 + );
  395 +};
@@ -65,3 +65,19 @@ export interface ImportModelOfMatterType { @@ -65,3 +65,19 @@ export interface ImportModelOfMatterType {
65 tkDeviceProfileId?: string; 65 tkDeviceProfileId?: string;
66 categoryId?: string; 66 categoryId?: string;
67 } 67 }
  68 +
  69 +export interface ModelOfMatterItemRecordType {
  70 + id: string;
  71 + creator: string;
  72 + createTime: string;
  73 + enabled: boolean;
  74 + tenantId: string;
  75 + functionType: string;
  76 + functionName: string;
  77 + identifier: string;
  78 + extensionDesc: any;
  79 + accessMode: string;
  80 + functionJson: FunctionJson;
  81 + status: number;
  82 + deviceProfileId: string;
  83 +}
@@ -2,6 +2,7 @@ import { BasicPageParams } from '../model/baseModel'; @@ -2,6 +2,7 @@ import { BasicPageParams } from '../model/baseModel';
2 import { 2 import {
3 GetModelTslParams, 3 GetModelTslParams,
4 ImportModelOfMatterType, 4 ImportModelOfMatterType,
  5 + ModelOfMatterItemRecordType,
5 ModelOfMatterParams, 6 ModelOfMatterParams,
6 } from './model/modelOfMatterModel'; 7 } from './model/modelOfMatterModel';
7 import { defHttp } from '/@/utils/http/axios'; 8 import { defHttp } from '/@/utils/http/axios';
@@ -36,7 +37,7 @@ export const getModelList = ( @@ -36,7 +37,7 @@ export const getModelList = (
36 id?: string; 37 id?: string;
37 } 38 }
38 ) => { 39 ) => {
39 - return defHttp.get({ 40 + return defHttp.get<ModelOfMatterItemRecordType[]>({
40 url: `${ModelOfMatter.LIST}`, 41 url: `${ModelOfMatter.LIST}`,
41 params, 42 params,
42 }); 43 });
@@ -14,7 +14,6 @@ export function saveMenuApi( @@ -14,7 +14,6 @@ export function saveMenuApi(
14 update = false, 14 update = false,
15 mode: ErrorMessageMode = 'modal' 15 mode: ErrorMessageMode = 'modal'
16 ) { 16 ) {
17 - console.log(params);  
18 if (!update) { 17 if (!update) {
19 return defHttp.post<MenuOperationApiResult>( 18 return defHttp.post<MenuOperationApiResult>(
20 { 19 {
@@ -48,13 +48,21 @@ @@ -48,13 +48,21 @@
48 <template #content> 48 <template #content>
49 <section class="flex flex-wrap w-36"> 49 <section class="flex flex-wrap w-36">
50 <table class="border-collapse" @click="handleSelectConfirm"> 50 <table class="border-collapse" @click="handleSelectConfirm">
51 - <tr v-for="row in MAX_ROW" :key="row" class="border border-gray-300 border-solid"> 51 + <tr
  52 + v-for="rowNumber in MAX_ROW"
  53 + :key="rowNumber"
  54 + class="border border-gray-300 border-solid"
  55 + >
52 <td 56 <td
53 - v-for="col in MAX_COL"  
54 - :class="selectedLayout.col >= col && selectedLayout.row >= row ? 'bg-blue-500' : ''"  
55 - :key="col" 57 + v-for="colNumber in MAX_COL"
  58 + :class="
  59 + selectedLayout.col >= colNumber && selectedLayout.row >= rowNumber
  60 + ? 'bg-blue-500'
  61 + : ''
  62 + "
  63 + :key="colNumber"
56 class="w-4 h-4 border border-gray-300 border-solid cursor-pointer" 64 class="w-4 h-4 border border-gray-300 border-solid cursor-pointer"
57 - @mouseover="handleOver(row, col)" 65 + @mouseover="handleOver(rowNumber, colNumber)"
58 > 66 >
59 </td> 67 </td>
60 </tr> 68 </tr>
@@ -77,7 +77,6 @@ @@ -77,7 +77,6 @@
77 try { 77 try {
78 const data = e.target && e.target.result; 78 const data = e.target && e.target.result;
79 const workbook = XLSX.read(data, { type: 'array' }); 79 const workbook = XLSX.read(data, { type: 'array' });
80 - // console.log(workbook);  
81 /* DO SOMETHING WITH workbook HERE */ 80 /* DO SOMETHING WITH workbook HERE */
82 const excelData = getExcelData(workbook); 81 const excelData = getExcelData(workbook);
83 emit('success', excelData); 82 emit('success', excelData);
@@ -90,7 +90,7 @@ @@ -90,7 +90,7 @@
90 () => { 90 () => {
91 !unref(isFirstLoad) && fetch(); 91 !unref(isFirstLoad) && fetch();
92 }, 92 },
93 - { deep: true }, 93 + { deep: true }
94 ); 94 );
95 95
96 async function fetch() { 96 async function fetch() {
@@ -110,6 +110,7 @@ @@ -110,6 +110,7 @@
110 } 110 }
111 emitChange(); 111 emitChange();
112 } catch (error) { 112 } catch (error) {
  113 + // eslint-disable-next-line no-console
113 console.warn(error); 114 console.warn(error);
114 } finally { 115 } finally {
115 loading.value = false; 116 loading.value = false;
@@ -156,6 +156,7 @@ @@ -156,6 +156,7 @@
156 } 156 }
157 emitChange(); 157 emitChange();
158 } catch (error) { 158 } catch (error) {
  159 + // eslint-disable-next-line no-console
159 console.warn(error); 160 console.warn(error);
160 } finally { 161 } finally {
161 loading.value = false; 162 loading.value = false;
@@ -54,7 +54,7 @@ @@ -54,7 +54,7 @@
54 }, 54 },
55 // api params 55 // api params
56 params: { 56 params: {
57 - type: Object as PropType<Recordable>, 57 + type: [Object, String, Number] as any,
58 default: () => ({}), 58 default: () => ({}),
59 }, 59 },
60 // support xxx.xxx.xx 60 // support xxx.xxx.xx
  1 +<script setup lang="ts">
  2 + import { InputGroup, Button, Popconfirm } from 'ant-design-vue';
  3 + import { computed, ref, unref, watch } from 'vue';
  4 + import { componentMap } from '../componentMap';
  5 + import { ComponentType } from '../types';
  6 + import Icon from '/@/components/Icon';
  7 + import { PopConfirm } from '/@/components/Table';
  8 + import { upperFirst } from '/@/components/Transition/src/ExpandTransition';
  9 +
  10 + const props = withDefaults(
  11 + defineProps<{
  12 + value?: number | string | Recordable | Recordable[];
  13 + component?: ComponentType;
  14 + componentProps?: Recordable;
  15 + disabled?: boolean;
  16 + changeEvent?: string;
  17 + valueField?: string;
  18 + defaultLockStatus?: boolean;
  19 + popconfirm?: Omit<PopConfirm, 'confirm' | 'cancel'>;
  20 + }>(),
  21 + {
  22 + changeEvent: 'change',
  23 + valueField: 'value',
  24 + disabled: false,
  25 + component: 'Input',
  26 + defaultLockStatus: true,
  27 + componentProps: () => ({}),
  28 + }
  29 + );
  30 +
  31 + const slots = defineSlots<{
  32 + popconfirmTitle?: () => any;
  33 + }>();
  34 +
  35 + const emits = defineEmits(['change']);
  36 +
  37 + const ControlComponent = computed(() => componentMap.get(props.component));
  38 +
  39 + const getControlComponentProps = computed(() => {
  40 + const { componentProps, changeEvent, component, valueField, value } = props;
  41 + const isCheck = component && ['Switch', 'Checkbox'].includes(component);
  42 + const eventKey = `on${upperFirst(changeEvent)}`;
  43 + return {
  44 + ...componentProps,
  45 + [eventKey]: (...args: Nullable<Recordable>[]) => {
  46 + const [e] = args;
  47 + if (componentProps?.[eventKey]) {
  48 + componentProps?.[eventKey](...args);
  49 + }
  50 + const target = e ? e.target : null;
  51 + const value = target ? (isCheck ? target.checked : target.value) : e;
  52 + emits('change', value);
  53 + },
  54 + [valueField]: value,
  55 + };
  56 + });
  57 +
  58 + const popconfirmVisible = ref(false);
  59 +
  60 + const confirm = () => {
  61 + controlDisableStatus.value = false;
  62 + popconfirmVisible.value = false;
  63 + };
  64 +
  65 + const cancel = () => {
  66 + popconfirmVisible.value = false;
  67 + };
  68 +
  69 + const getPopConfirmProps = computed(() => {
  70 + const { popconfirm } = props;
  71 +
  72 + return {
  73 + ...popconfirm,
  74 + onConfirm: confirm,
  75 + onCancel: cancel,
  76 + onVisibleChange: () => {
  77 + if (!unref(controlDisableStatus)) {
  78 + popconfirmVisible.value = false;
  79 + controlDisableStatus.value = true;
  80 + return;
  81 + }
  82 + },
  83 + title: slots.popconfirmTitle ? slots.popconfirmTitle : popconfirm?.title,
  84 + };
  85 + });
  86 +
  87 + const controlDisableStatus = ref(props.defaultLockStatus);
  88 +
  89 + watch(
  90 + () => props.defaultLockStatus,
  91 + (target) => {
  92 + controlDisableStatus.value = !!target;
  93 + },
  94 + { immediate: true }
  95 + );
  96 +</script>
  97 +
  98 +<template>
  99 + <InputGroup compact class="w-full !flex">
  100 + <ControlComponent
  101 + v-bind="getControlComponentProps"
  102 + class="flex-auto"
  103 + :disabled="controlDisableStatus"
  104 + />
  105 + <Popconfirm v-model:visible="popconfirmVisible" v-bind="getPopConfirmProps">
  106 + <Button type="primary" :disabled="disabled">
  107 + <Icon
  108 + :icon="controlDisableStatus ? 'ant-design:lock-outlined' : 'ant-design:unlock-outlined'"
  109 + />
  110 + </Button>
  111 + </Popconfirm>
  112 + </InputGroup>
  113 +</template>
@@ -113,7 +113,7 @@ @@ -113,7 +113,7 @@
113 const { TabPane } = Tabs; 113 const { TabPane } = Tabs;
114 const { prefixCls } = useDesign('easy-cron-inner'); 114 const { prefixCls } = useDesign('easy-cron-inner');
115 provide('prefixCls', prefixCls); 115 provide('prefixCls', prefixCls);
116 - const emit = defineEmits([...cronEmits]); 116 + const emit = defineEmits(cronEmits);
117 const props = defineProps({ ...cronProps }); 117 const props = defineProps({ ...cronProps });
118 const activeKey = ref(props.hideSecond ? 'minute' : 'second'); 118 const activeKey = ref(props.hideSecond ? 'minute' : 'second');
119 const second = ref('*'); 119 const second = ref('*');
@@ -236,7 +236,7 @@ @@ -236,7 +236,7 @@
236 if (/^[0-7]$/.test(week)) { 236 if (/^[0-7]$/.test(week)) {
237 return convert(week); 237 return convert(week);
238 } else if (patten1.test(week)) { 238 } else if (patten1.test(week)) {
239 - return week.replace(patten1, ($0, before, separator, after) => { 239 + return week.replace(patten1, (_$0, before, separator, after) => {
240 if (separator === '/') { 240 if (separator === '/') {
241 return convert(before) + separator + after; 241 return convert(before) + separator + after;
242 } else { 242 } else {
@@ -23,8 +23,8 @@ @@ -23,8 +23,8 @@
23 23
24 export default defineComponent({ 24 export default defineComponent({
25 name: 'EasyCronModal', 25 name: 'EasyCronModal',
26 - inheritAttrs: false,  
27 components: { BasicModal, EasyCron, Button }, 26 components: { BasicModal, EasyCron, Button },
  27 + inheritAttrs: false,
28 setup() { 28 setup() {
29 const attrs = useAttrs(); 29 const attrs = useAttrs();
30 const [registerModal, { closeModal }] = useModalInner(); 30 const [registerModal, { closeModal }] = useModalInner();
@@ -45,7 +45,7 @@ export function useTabSetup(props, context, options) { @@ -45,7 +45,7 @@ export function useTabSetup(props, context, options) {
45 45
46 // 根据不同的类型计算出的value 46 // 根据不同的类型计算出的value
47 const computeValue = computed(() => { 47 const computeValue = computed(() => {
48 - let valueArray: any[] = []; 48 + const valueArray: any[] = [];
49 switch (type.value) { 49 switch (type.value) {
50 case TypeEnum.unset: 50 case TypeEnum.unset:
51 valueArray.push('?'); 51 valueArray.push('?');
@@ -79,7 +79,7 @@ export function useTabSetup(props, context, options) { @@ -79,7 +79,7 @@ export function useTabSetup(props, context, options) {
79 }); 79 });
80 // 指定值范围区间,介于最小值和最大值之间 80 // 指定值范围区间,介于最小值和最大值之间
81 const specifyRange = computed(() => { 81 const specifyRange = computed(() => {
82 - let range: number[] = []; 82 + const range: number[] = [];
83 if (maxValue.value != null) { 83 if (maxValue.value != null) {
84 for (let i = minValue.value; i <= maxValue.value; i++) { 84 for (let i = minValue.value; i <= maxValue.value; i++) {
85 range.push(i); 85 range.push(i);
@@ -143,4 +143,5 @@ export type ComponentType = @@ -143,4 +143,5 @@ export type ComponentType =
143 | 'ConditionFilter' 143 | 'ConditionFilter'
144 | 'TimeRangePicker' 144 | 'TimeRangePicker'
145 | 'TriggerDurationInput' 145 | 'TriggerDurationInput'
146 - | 'AlarmProfileSelect'; 146 + | 'AlarmProfileSelect'
  147 + | 'LockControlGroup';
@@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
44 </ModalWrapper> 44 </ModalWrapper>
45 45
46 <template #[item]="data" v-for="item in Object.keys(omit($slots, 'default'))"> 46 <template #[item]="data" v-for="item in Object.keys(omit($slots, 'default'))">
47 - <slot :name="item" v-bind="data"></slot> 47 + <slot :name="item" v-bind="data || {}"></slot>
48 </template> 48 </template>
49 </Modal> 49 </Modal>
50 </template> 50 </template>
@@ -159,7 +159,7 @@ @@ -159,7 +159,7 @@
159 } 159 }
160 emit('height-change', unref(realHeightRef)); 160 emit('height-change', unref(realHeightRef));
161 } catch (error) { 161 } catch (error) {
162 - console.log(error); 162 + console.error(error);
163 } 163 }
164 } 164 }
165 165
@@ -207,7 +207,6 @@ @@ -207,7 +207,6 @@
207 }); 207 });
208 208
209 function handleSearch(searchValue: string) { 209 function handleSearch(searchValue: string) {
210 - console.log('searchValue', searchValue);  
211 if (searchValue !== searchText.value) searchText.value = searchValue; 210 if (searchValue !== searchText.value) searchText.value = searchValue;
212 emit('update:searchValue', searchValue); 211 emit('update:searchValue', searchValue);
213 if (!searchValue) { 212 if (!searchValue) {
@@ -202,7 +202,6 @@ @@ -202,7 +202,6 @@
202 error: null, 202 error: null,
203 }; 203 };
204 } catch (e) { 204 } catch (e) {
205 - console.log(e);  
206 item.status = UploadResultStatus.ERROR; 205 item.status = UploadResultStatus.ERROR;
207 return { 206 return {
208 success: false, 207 success: false,
@@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
16 import { computed, defineComponent, unref, ref } from 'vue'; 16 import { computed, defineComponent, unref, ref } from 'vue';
17 import { Layout } from 'ant-design-vue'; 17 import { Layout } from 'ant-design-vue';
18 18
19 - import { GithubFilled } from '@ant-design/icons-vue';  
20 -  
21 import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting'; 19 import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting';
22 import { openWindow } from '/@/utils'; 20 import { openWindow } from '/@/utils';
23 21
@@ -29,7 +27,7 @@ @@ -29,7 +27,7 @@
29 27
30 export default defineComponent({ 28 export default defineComponent({
31 name: 'LayoutFooter', 29 name: 'LayoutFooter',
32 - components: { Footer: Layout.Footer, GithubFilled }, 30 + components: { Footer: Layout.Footer },
33 setup() { 31 setup() {
34 const { t } = useI18n(); 32 const { t } = useI18n();
35 const { getShowFooter } = useRootSetting(); 33 const { getShowFooter } = useRootSetting();
@@ -148,7 +148,6 @@ @@ -148,7 +148,6 @@
148 148
149 function renderMenu() { 149 function renderMenu() {
150 const { menus, ...menuProps } = unref(getCommonProps); 150 const { menus, ...menuProps } = unref(getCommonProps);
151 - // console.log(menus);  
152 if (!menus || !menus.length) return null; 151 if (!menus || !menus.length) return null;
153 return !props.isHorizontal ? ( 152 return !props.isHorizontal ? (
154 <SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} /> 153 <SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} />
@@ -100,7 +100,7 @@ export default defineComponent({ @@ -100,7 +100,7 @@ export default defineComponent({
100 <> 100 <>
101 <TypePicker 101 <TypePicker
102 menuTypeList={menuTypeList} 102 menuTypeList={menuTypeList}
103 - handler={(item: typeof menuTypeList[0]) => { 103 + handler={(item: (typeof menuTypeList)[0]) => {
104 baseHandler(HandlerEnum.CHANGE_LAYOUT, { 104 baseHandler(HandlerEnum.CHANGE_LAYOUT, {
105 mode: item.mode, 105 mode: item.mode,
106 type: item.type, 106 type: item.type,
@@ -47,7 +47,7 @@ export function initAppConfigStore() { @@ -47,7 +47,7 @@ export function initAppConfigStore() {
47 grayMode && updateGrayMode(grayMode); 47 grayMode && updateGrayMode(grayMode);
48 colorWeak && updateColorWeak(colorWeak); 48 colorWeak && updateColorWeak(colorWeak);
49 } catch (error) { 49 } catch (error) {
50 - console.log(error); 50 + console.error(error);
51 } 51 }
52 appStore.setProjectConfig(projCfg); 52 appStore.setProjectConfig(projCfg);
53 53
@@ -4,7 +4,6 @@ import { defineStore } from 'pinia'; @@ -4,7 +4,6 @@ import { defineStore } from 'pinia';
4 4
5 import { LOCK_INFO_KEY } from '/@/enums/cacheEnum'; 5 import { LOCK_INFO_KEY } from '/@/enums/cacheEnum';
6 import { Persistent } from '/@/utils/cache/persistent'; 6 import { Persistent } from '/@/utils/cache/persistent';
7 -import { useUserStore } from './user';  
8 7
9 interface LockState { 8 interface LockState {
10 lockInfo: Nullable<LockInfo>; 9 lockInfo: Nullable<LockInfo>;
@@ -111,7 +111,6 @@ export const usePermissionStore = defineStore({ @@ -111,7 +111,6 @@ export const usePermissionStore = defineStore({
111 * 否则不是超级管理员-获取对应角色的权限列表 111 * 否则不是超级管理员-获取对应角色的权限列表
112 */ 112 */
113 const codeList = await getPermCode(); 113 const codeList = await getPermCode();
114 - // console.log('codeList', codeList);  
115 this.setPermCodeList(codeList); 114 this.setPermCodeList(codeList);
116 /** 115 /**
117 * 如果是超级管理员则获取对应权限列表 116 * 如果是超级管理员则获取对应权限列表
@@ -234,7 +234,6 @@ export const useUserStore = defineStore({ @@ -234,7 +234,6 @@ export const useUserStore = defineStore({
234 // try { 234 // try {
235 // await doLogout(); 235 // await doLogout();
236 // } catch { 236 // } catch {
237 - // console.log('注销Token失败');  
238 // } 237 // }
239 // this.resetState(); 238 // this.resetState();
240 // setAuthCache(JWT_TOKEN_KEY, undefined); 239 // setAuthCache(JWT_TOKEN_KEY, undefined);
@@ -85,9 +85,7 @@ @@ -85,9 +85,7 @@
85 /^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$/; 85 /^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$/;
86 if (reg.test(formData.mobile)) { 86 if (reg.test(formData.mobile)) {
87 const sendRes = await passwordResetCode(formData.mobile); 87 const sendRes = await passwordResetCode(formData.mobile);
88 - console.log(sendRes);  
89 if (sendRes === '') { 88 if (sendRes === '') {
90 - console.log('发送成功了');  
91 return true; 89 return true;
92 } 90 }
93 return false; 91 return false;
@@ -99,6 +99,5 @@ @@ -99,6 +99,5 @@
99 async function handleRegister() { 99 async function handleRegister() {
100 const data = await validForm(); 100 const data = await validForm();
101 if (!data) return; 101 if (!data) return;
102 - console.log(data);  
103 } 102 }
104 </script> 103 </script>
@@ -27,7 +27,6 @@ @@ -27,7 +27,6 @@
27 onMounted(() => { 27 onMounted(() => {
28 // 记录当前的UserId 28 // 记录当前的UserId
29 userId.value = userStore.getUserInfo?.userId; 29 userId.value = userStore.getUserInfo?.userId;
30 - console.log('Mounted', userStore.getUserInfo);  
31 }); 30 });
32 31
33 onBeforeUnmount(() => { 32 onBeforeUnmount(() => {
@@ -11,8 +11,7 @@ @@ -11,8 +11,7 @@
11 */ 11 */
12 export function simpleDebounce(fn, delay = 100) { 12 export function simpleDebounce(fn, delay = 100) {
13 let timer: any | null = null; 13 let timer: any | null = null;
14 - return function () {  
15 - let args = arguments; 14 + return function (...args) {
16 if (timer) { 15 if (timer) {
17 clearTimeout(timer); 16 clearTimeout(timer);
18 } 17 }
@@ -61,4 +60,3 @@ export function dateFormat(date, block) { @@ -61,4 +60,3 @@ export function dateFormat(date, block) {
61 }); 60 });
62 return format; 61 return format;
63 } 62 }
64 -  
@@ -36,7 +36,6 @@ export function checkStatus( @@ -36,7 +36,6 @@ export function checkStatus(
36 } 36 }
37 break; 37 break;
38 case 403: 38 case 403:
39 - // console.log('403', errMessage);  
40 // errMessage = t('sys.api.errMsg403'); 39 // errMessage = t('sys.api.errMsg403');
41 errMessage = errMessage; 40 errMessage = errMessage;
42 break; 41 break;
@@ -8,7 +8,6 @@ export function listToTree(lists: getMenuListResultModel): getMenuListResultMode @@ -8,7 +8,6 @@ export function listToTree(lists: getMenuListResultModel): getMenuListResultMode
8 lists.forEach((goods) => { 8 lists.forEach((goods) => {
9 goods['menuName'] = t(goods.meta.title); // 为goods添加属性menuName 9 goods['menuName'] = t(goods.meta.title); // 为goods添加属性menuName
10 10
11 - // console.log(goods.children?.length);  
12 if (goods.children?.length) { 11 if (goods.children?.length) {
13 listToTree(goods.children); 12 listToTree(goods.children);
14 // goods.children.forEach((goodChildren) => { 13 // goods.children.forEach((goodChildren) => {
@@ -102,8 +102,7 @@ @@ -102,8 +102,7 @@
102 avatar: [{ uid: buildUUID(), name: 'name', url: data.record.avatar } as FileItem], 102 avatar: [{ uid: buildUUID(), name: 'name', url: data.record.avatar } as FileItem],
103 }); 103 });
104 } 104 }
105 - const { avatar, ...params } = data.record;  
106 - console.log(avatar); 105 + const { ...params } = data.record;
107 await setFieldsValue({ ...params }); 106 await setFieldsValue({ ...params });
108 } else { 107 } else {
109 editId.value = ''; 108 editId.value = '';
@@ -82,11 +82,11 @@ @@ -82,11 +82,11 @@
82 </script> 82 </script>
83 83
84 <template> 84 <template>
85 - <section class="flex">  
86 - <ApiTreeSelect v-bind="getBindProps" />  
87 - <Button v-if="getShowCreate" type="link" @click="handleOpenCreate" :disabled="disabled"  
88 - >新增组织</Button  
89 - > 85 + <section class="!flex">
  86 + <ApiTreeSelect v-bind="getBindProps" class="flex-auto" />
  87 + <Button v-if="getShowCreate" type="link" @click="handleOpenCreate" :disabled="disabled">
  88 + 新增组织
  89 + </Button>
90 <OrganizationDrawer v-if="getShowCreate" @register="registerDrawer" @success="handleReload" /> 90 <OrganizationDrawer v-if="getShowCreate" @register="registerDrawer" @success="handleReload" />
91 </section> 91 </section>
92 </template> 92 </template>
@@ -337,7 +337,6 @@ @@ -337,7 +337,6 @@
337 } 337 }
338 }, 338 },
339 onDisconnected() { 339 onDisconnected() {
340 - console.log('断开连接了');  
341 close(); 340 close();
342 }, 341 },
343 }); 342 });
@@ -354,7 +354,6 @@ @@ -354,7 +354,6 @@
354 } 354 }
355 }, 355 },
356 onDisconnected() { 356 onDisconnected() {
357 - console.log('断开连接了');  
358 close(); 357 close();
359 }, 358 },
360 }); 359 });
@@ -75,9 +75,7 @@ export const formSchema: FormSchema[] = [ @@ -75,9 +75,7 @@ export const formSchema: FormSchema[] = [
75 } 75 }
76 }, 76 },
77 // showUploadList: true, 77 // showUploadList: true,
78 - onDownload(file) {  
79 - console.log(file);  
80 - }, 78 + onDownload() {},
81 onPreview: (fileList: FileItem) => { 79 onPreview: (fileList: FileItem) => {
82 createImgPreview({ imageList: [fileList.url!] }); 80 createImgPreview({ imageList: [fileList.url!] });
83 }, 81 },
@@ -153,7 +153,7 @@ @@ -153,7 +153,7 @@
153 <template #renderItem="{ item }: BasicCardListRenderItem<BigScreenCenterItemsModel>"> 153 <template #renderItem="{ item }: BasicCardListRenderItem<BigScreenCenterItemsModel>">
154 <Card 154 <Card
155 :style="{ 155 :style="{
156 - '--viewType': item.viewType === ViewType.PUBLIC_VIEW ? '#1890ff' : '#faad14', 156 + '--viewType': item.viewType === ViewType.PUBLIC_VIEW ? '#faad14' : '#1890ff',
157 }" 157 }"
158 class="card-container" 158 class="card-container"
159 > 159 >
@@ -192,7 +192,6 @@ @@ -192,7 +192,6 @@
192 getRestData.value = resp; 192 getRestData.value = resp;
193 commonRest(resp, jsonEditorRef.value?.setJsonValue); 193 commonRest(resp, jsonEditorRef.value?.setJsonValue);
194 } catch (e) { 194 } catch (e) {
195 - console.log(e);  
196 if (Object.prototype.toString.call(e) === '[object Object]') { 195 if (Object.prototype.toString.call(e) === '[object Object]') {
197 jsonEditorRef.value?.setJsonValue(e); 196 jsonEditorRef.value?.setJsonValue(e);
198 } else { 197 } else {
@@ -61,7 +61,7 @@ export const useUtils = () => { @@ -61,7 +61,7 @@ export const useUtils = () => {
61 } 61 }
62 } 62 }
63 } catch (e) { 63 } catch (e) {
64 - console.log(`Post没有传递params${e}`); 64 + console.error(`Post没有传递params${e}`);
65 } 65 }
66 return _result.join('&'); 66 return _result.join('&');
67 }; 67 };
1 import { FormProps, FormSchema, useComponentRegister } from '/@/components/Form'; 1 import { FormProps, FormSchema, useComponentRegister } from '/@/components/Form';
2 import { findDictItemByCode } from '/@/api/system/dict'; 2 import { findDictItemByCode } from '/@/api/system/dict';
3 -import { deviceProfile, getGatewayDevice } from '/@/api/device/deviceManager'; 3 +import { getGatewayDevice, queryDeviceProfileBy } from '/@/api/device/deviceManager';
4 import { TransportTypeEnum } from '../../profiles/components/TransportDescript/const'; 4 import { TransportTypeEnum } from '../../profiles/components/TransportDescript/const';
5 import { JSONEditorValidator } from '/@/components/CodeEditor/src/JSONEditor'; 5 import { JSONEditorValidator } from '/@/components/CodeEditor/src/JSONEditor';
6 import { JSONEditor } from '/@/components/CodeEditor'; 6 import { JSONEditor } from '/@/components/CodeEditor';
7 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; 7 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
8 import { getModelServices } from '/@/api/device/modelOfMatter'; 8 import { getModelServices } from '/@/api/device/modelOfMatter';
9 import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; 9 import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
10 -import { nextTick, toRaw, unref } from 'vue'; 10 +import { h, nextTick, toRaw, unref } from 'vue';
11 import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue'; 11 import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue';
12 import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum'; 12 import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum';
13 import { TaskTypeEnum } from '/@/views/task/center/config'; 13 import { TaskTypeEnum } from '/@/views/task/center/config';
@@ -18,9 +18,13 @@ import { uploadThumbnail } from '/@/api/configuration/center/configurationCenter @@ -18,9 +18,13 @@ import { uploadThumbnail } from '/@/api/configuration/center/configurationCenter
18 18
19 import { getOrganizationList } from '/@/api/system/system'; 19 import { getOrganizationList } from '/@/api/system/system';
20 import { copyTransFun } from '/@/utils/fnUtils'; 20 import { copyTransFun } from '/@/utils/fnUtils';
  21 +import LockControlGroup from '/@/components/Form/src/components/LockControlGroup.vue';
  22 +import { OrgTreeSelect } from '/@/views/common/OrgTreeSelect';
21 23
22 useComponentRegister('JSONEditor', JSONEditor); 24 useComponentRegister('JSONEditor', JSONEditor);
23 useComponentRegister('ObjectModelValidateForm', ObjectModelValidateForm); 25 useComponentRegister('ObjectModelValidateForm', ObjectModelValidateForm);
  26 +useComponentRegister('LockControlGroup', LockControlGroup);
  27 +useComponentRegister('OrgTreeSelect', OrgTreeSelect);
24 28
25 export enum TypeEnum { 29 export enum TypeEnum {
26 IS_GATEWAY = 'GATEWAY', 30 IS_GATEWAY = 'GATEWAY',
@@ -30,6 +34,17 @@ export enum TypeEnum { @@ -30,6 +34,17 @@ export enum TypeEnum {
30 export const isGateWay = (type: string) => { 34 export const isGateWay = (type: string) => {
31 return type === TypeEnum.IS_GATEWAY; 35 return type === TypeEnum.IS_GATEWAY;
32 }; 36 };
  37 +
  38 +const updateProductHelpMessage = [
  39 + '注意:',
  40 + '修改设备产品时,如果"大屏"、"组态"、"看板"、"场景联动"、"数据流转"等有关联设备,请自行调整并保存。',
  41 +];
  42 +
  43 +const updateOrgHelpMessage = [
  44 + '注意:',
  45 + '1、修改设备组织时,如果"大屏"、"组态"、"看板"、"场景联动"、"数据流转"等有关联设备,请自行调整并保存。',
  46 + '2、网关设备在修改组织时,其关联网关子设备组织归属于网关组织及以下不用修改,否则将同步更新网关子设备组织为网关组织。',
  47 +];
33 // 第一步的表单 48 // 第一步的表单
34 export const step1Schemas: FormSchema[] = [ 49 export const step1Schemas: FormSchema[] = [
35 { 50 {
@@ -96,43 +111,60 @@ export const step1Schemas: FormSchema[] = [ @@ -96,43 +111,60 @@ export const step1Schemas: FormSchema[] = [
96 show: false, 111 show: false,
97 }, 112 },
98 { 113 {
  114 + field: 'isUpdate',
  115 + label: '编辑模式',
  116 + component: 'Switch',
  117 + show: false,
  118 + },
  119 + {
99 field: 'profileId', 120 field: 'profileId',
100 label: '所属产品', 121 label: '所属产品',
101 required: true, 122 required: true,
102 - component: 'ApiSelect', 123 + component: 'LockControlGroup',
  124 + helpMessage: updateProductHelpMessage,
  125 + renderComponentContent: () => ({
  126 + popconfirmTitle: () =>
  127 + updateProductHelpMessage.map((text) => h('div', { style: { maxWidth: '200px' } }, text)),
  128 + }),
103 componentProps: ({ formActionType, formModel }) => { 129 componentProps: ({ formActionType, formModel }) => {
104 const { setFieldsValue } = formActionType; 130 const { setFieldsValue } = formActionType;
105 return { 131 return {
106 - api: async () => {  
107 - const options = await deviceProfile();  
108 - const { profileId } = formModel;  
109 - if (profileId) {  
110 - const selectRecord = options.find((item) => item.tbProfileId === profileId);  
111 - selectRecord && setFieldsValue({ transportType: selectRecord!.transportType });  
112 - }  
113 - return options;  
114 - },  
115 - labelField: 'name',  
116 - valueField: 'tbProfileId',  
117 - onChange(  
118 - _value: string,  
119 - option: { deviceType: string; transportType: string; id: string }  
120 - ) {  
121 - const { deviceType, transportType, id } = option;  
122 - setFieldsValue({  
123 - deviceType: deviceType,  
124 - transportType,  
125 - deviceProfileId: id,  
126 - gatewayId: null,  
127 - codeType: transportType === TransportTypeEnum.TCP ? TaskTypeEnum.MODBUS_RTU : null,  
128 - code: null,  
129 - addressCode: null,  
130 - }); 132 + component: 'ApiSelect',
  133 + defaultLockStatus: !!formModel?.isUpdate,
  134 + componentProps: {
  135 + api: async () => {
  136 + const options = await queryDeviceProfileBy({
  137 + deviceType: formModel?.isUpdate ? formModel?.deviceType : null,
  138 + });
  139 + const { profileId } = formModel;
  140 + if (profileId) {
  141 + const selectRecord = options.find((item) => item.tbProfileId === profileId);
  142 + selectRecord && setFieldsValue({ transportType: selectRecord!.transportType });
  143 + }
  144 + return options;
  145 + },
  146 + labelField: 'name',
  147 + valueField: 'tbProfileId',
  148 + onChange(
  149 + _value: string,
  150 + option: { deviceType: string; transportType: string; id: string }
  151 + ) {
  152 + const { deviceType, transportType, id } = option;
  153 + setFieldsValue({
  154 + deviceType: deviceType,
  155 + transportType,
  156 + deviceProfileId: id,
  157 + gatewayId: null,
  158 + codeType: transportType === TransportTypeEnum.TCP ? TaskTypeEnum.MODBUS_RTU : null,
  159 + code: null,
  160 + addressCode: null,
  161 + });
  162 + },
  163 + showSearch: true,
  164 + placeholder: '请选择产品',
  165 + filterOption: (inputValue: string, option: Record<'label' | 'value', string>) =>
  166 + option.label.includes(inputValue),
131 }, 167 },
132 - showSearch: true,  
133 - placeholder: '请选择产品',  
134 - filterOption: (inputValue: string, option: Record<'label' | 'value', string>) =>  
135 - option.label.includes(inputValue),  
136 }; 168 };
137 }, 169 },
138 }, 170 },
@@ -311,9 +343,19 @@ export const step1Schemas: FormSchema[] = [ @@ -311,9 +343,19 @@ export const step1Schemas: FormSchema[] = [
311 { 343 {
312 field: 'organizationId', 344 field: 'organizationId',
313 label: '所属组织', 345 label: '所属组织',
314 - component: 'Select', 346 + component: 'LockControlGroup',
315 required: true, 347 required: true,
316 - slot: 'addOrg', 348 + helpMessage: updateOrgHelpMessage,
  349 + renderComponentContent: () => ({
  350 + popconfirmTitle: () =>
  351 + updateOrgHelpMessage.map((text) => h('div', { style: { maxWidth: '240px' } }, text)),
  352 + }),
  353 + componentProps: ({ formModel }) => {
  354 + return {
  355 + component: 'OrgTreeSelect',
  356 + defaultLockStatus: !!formModel?.isUpdate,
  357 + };
  358 + },
317 }, 359 },
318 { 360 {
319 field: 'label', 361 field: 'label',
@@ -7,6 +7,63 @@ import { h } from 'vue'; @@ -7,6 +7,63 @@ import { h } from 'vue';
7 import { Tag, Tooltip } from 'ant-design-vue'; 7 import { Tag, Tooltip } from 'ant-design-vue';
8 import { handeleCopy } from '../../profiles/step/topic'; 8 import { handeleCopy } from '../../profiles/step/topic';
9 9
  10 +export enum DeviceListAuthEnum {
  11 + /**
  12 + * @description 新增
  13 + */
  14 + CREATE = 'api:yt:device:post',
  15 +
  16 + /**
  17 + * @description 删除
  18 + */
  19 + DELETE = 'api:yt:device:delete',
  20 +
  21 + /**
  22 + * @description 编辑
  23 + */
  24 + UPDATE = 'api:yt:device:update',
  25 +
  26 + /**
  27 + * @description 详情
  28 + */
  29 + DETAIL = 'api:yt:device:get',
  30 +
  31 + /**
  32 + * @description 导入
  33 + */
  34 + IMPORT = 'api:yt:device:import',
  35 +
  36 + /**
  37 + * @description 公开
  38 + */
  39 + PUBLIC = 'api:yt:device:public',
  40 +
  41 + /**
  42 + * @description 上下线
  43 + */
  44 + ONLINE = 'api:yt:device:online:record',
  45 +
  46 + /**
  47 + * @description 管理设备凭证
  48 + */
  49 + EQUIPMENT = 'api:yt:device:equipment',
  50 +
  51 + /**
  52 + * @description 分配客户
  53 + */
  54 + ASSIGN = 'api:yt:device:assign',
  55 +
  56 + /**
  57 + * @description 命令下发
  58 + */
  59 + RPC = 'api:yt:device:rpc',
  60 +
  61 + /**
  62 + * @description 更新产品
  63 + */
  64 + UPDATE_PRODUCT = 'api:yt:device:update:product',
  65 +}
  66 +
10 // 表格列数据 67 // 表格列数据
11 export const columns: BasicColumn[] = [ 68 export const columns: BasicColumn[] = [
12 { 69 {
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 ...basicProps, 10 ...basicProps,
11 value: { 11 value: {
12 required: true, 12 required: true,
  13 + type: Object,
13 }, 14 },
14 }); 15 });
15 16
  1 +import { getDeviceProfile } from '/@/api/alarm/position';
  2 +import { FormSchema } from '/@/components/Form';
  3 +
  4 +enum FormFieldsEnum {
  5 + DEVICE_TYPE = 'deviceType',
  6 + SOURCE_DEVICE_PROFILE_ID = 'sourceDeviceProfileName',
  7 + TARGET_DEVICE_PROFILE_ID = 'deviceProfileId',
  8 +}
  9 +
  10 +export type FormGetFiledValueResultType = Record<FormFieldsEnum, string>;
  11 +
  12 +export const formSchemas: FormSchema[] = [
  13 + {
  14 + field: FormFieldsEnum.SOURCE_DEVICE_PROFILE_ID,
  15 + component: 'Input',
  16 + label: '源产品',
  17 + dynamicDisabled: true,
  18 + required: true,
  19 + },
  20 + {
  21 + field: FormFieldsEnum.DEVICE_TYPE,
  22 + label: '设备类型',
  23 + component: 'Input',
  24 + show: false,
  25 + },
  26 + {
  27 + field: FormFieldsEnum.TARGET_DEVICE_PROFILE_ID,
  28 + component: 'ApiSelect',
  29 + label: '目标产品',
  30 + required: true,
  31 + componentProps: ({ formModel }) => {
  32 + return {
  33 + api: getDeviceProfile,
  34 + params: formModel[FormFieldsEnum.DEVICE_TYPE],
  35 + labelField: 'name',
  36 + valueField: 'tbProfileId',
  37 + placeholder: '请选择目标产品',
  38 + getPopupContainer: () => document.body,
  39 + };
  40 + },
  41 + },
  42 +];
  1 +export { default as BatchUpdateProductModal } from './index.vue';
  2 +
  3 +export type BatchUpdateProductModalParamsType = ModalParamsType<
  4 + Record<'sourceDeviceProfileName' | 'deviceType', string> & Record<'deviceIds', string[]>
  5 +>;
  1 +<script setup lang="ts">
  2 + import { ref, unref } from 'vue';
  3 + import { BatchUpdateProductModalParamsType } from '.';
  4 + import { FormGetFiledValueResultType, formSchemas } from './config';
  5 + import { doBatchUpdateProduct } from '/@/api/device/deviceManager';
  6 + import { BasicForm, useForm } from '/@/components/Form';
  7 + import Icon from '/@/components/Icon';
  8 + import { BasicModal, useModalInner } from '/@/components/Modal';
  9 + import { useMessage } from '/@/hooks/web/useMessage';
  10 +
  11 + const emits = defineEmits(['register', 'success']);
  12 +
  13 + const deviceIds = ref<string[]>([]);
  14 + const [registerForm, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({
  15 + layout: 'vertical',
  16 + showActionButtonGroup: false,
  17 + schemas: formSchemas,
  18 + });
  19 +
  20 + const [registerModal, { setModalProps, closeModal }] = useModalInner(
  21 + async ({ record }: BatchUpdateProductModalParamsType) => {
  22 + resetFields();
  23 + deviceIds.value = record.deviceIds;
  24 + setFieldsValue(record);
  25 + }
  26 + );
  27 +
  28 + const { createMessage } = useMessage();
  29 + const handleOk = async () => {
  30 + try {
  31 + await validate();
  32 + setModalProps({ loading: true, confirmLoading: true });
  33 +
  34 + const result = getFieldsValue() as FormGetFiledValueResultType;
  35 +
  36 + await doBatchUpdateProduct({
  37 + deviceIds: unref(deviceIds),
  38 + deviceProfileId: result.deviceProfileId,
  39 + });
  40 +
  41 + createMessage.success('操作成功');
  42 +
  43 + closeModal();
  44 + emits('success');
  45 + } finally {
  46 + setModalProps({ loading: false, confirmLoading: false });
  47 + }
  48 + };
  49 +</script>
  50 +
  51 +<template>
  52 + <BasicModal @register="registerModal" @ok="handleOk">
  53 + <template #title>
  54 + <div>批量更新产品</div>
  55 + <div class="mt-4 font-normal text-sm">
  56 + <Icon icon="ant-design:info-circle-outlined" />
  57 + <span>
  58 + 注意:修改设备产品时只能修改为同类型产品,如果"大屏"、"组态"、"看板"、"场景联动"、"数据流转"等有关联设备,请自行调整并保存。
  59 + </span>
  60 + </div>
  61 + </template>
  62 + <!-- <template #title>
  63 + <span></span>
  64 + </template> -->
  65 + <BasicForm @register="registerForm" />
  66 + </BasicModal>
  67 +</template>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 @next="handleStep1Next" 20 @next="handleStep1Next"
21 ref="DeviceStep1Ref" 21 ref="DeviceStep1Ref"
22 v-show="current === 0" 22 v-show="current === 0"
23 - :isUpdate="!isUpdate" 23 + :isUpdate="isUpdate"
24 /> 24 />
25 <DeviceStep2 25 <DeviceStep2
26 ref="DeviceStep2Ref" 26 ref="DeviceStep2Ref"
@@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
33 </BasicModal> 33 </BasicModal>
34 </template> 34 </template>
35 <script lang="ts"> 35 <script lang="ts">
36 - import { defineComponent, ref, computed, unref } from 'vue'; 36 + import { defineComponent, ref, computed, unref, nextTick } from 'vue';
37 import { BasicModal, useModalInner } from '/@/components/Modal'; 37 import { BasicModal, useModalInner } from '/@/components/Modal';
38 import { createOrEditDevice } from '/@/api/device/deviceManager'; 38 import { createOrEditDevice } from '/@/api/device/deviceManager';
39 import DeviceStep1 from '../step/DeviceStep1.vue'; 39 import DeviceStep1 from '../step/DeviceStep1.vue';
@@ -60,16 +60,17 @@ @@ -60,16 +60,17 @@
60 const DeviceStep2Ref = ref<InstanceType<typeof DeviceStep2>>(); 60 const DeviceStep2Ref = ref<InstanceType<typeof DeviceStep2>>();
61 const { createMessage } = useMessage(); 61 const { createMessage } = useMessage();
62 const current = ref(0); 62 const current = ref(0);
63 - const isUpdate = ref<Boolean>(false); 63 + const isUpdate = ref(false);
64 const deviceInfo = ref({}); 64 const deviceInfo = ref({});
65 let currentDeviceData = {} as Recordable; 65 let currentDeviceData = {} as Recordable;
66 const getTitle = computed(() => (!unref(isUpdate) ? '新增设备' : '编辑设备')); 66 const getTitle = computed(() => (!unref(isUpdate) ? '新增设备' : '编辑设备'));
67 // 所有参数 67 // 所有参数
68 let stepState = ref(); 68 let stepState = ref();
69 // 编辑回显 69 // 编辑回显
70 - const [register, { closeModal, setModalProps }] = useModalInner((data) => { 70 + const [register, { closeModal, setModalProps }] = useModalInner(async (data) => {
71 setModalProps({ confirmLoading: false, loading: true }); 71 setModalProps({ confirmLoading: false, loading: true });
72 isUpdate.value = data?.isUpdate; 72 isUpdate.value = data?.isUpdate;
  73 + await nextTick();
73 if (unref(isUpdate)) { 74 if (unref(isUpdate)) {
74 const { record } = data; 75 const { record } = data;
75 currentDeviceData = record; 76 currentDeviceData = record;
@@ -2,26 +2,6 @@ @@ -2,26 +2,6 @@
2 <div class="step1"> 2 <div class="step1">
3 <div class="step1-form"> 3 <div class="step1-form">
4 <BasicForm @register="register"> 4 <BasicForm @register="register">
5 - <template #addOrg="{ model, field }">  
6 - <div style="display: flex; align-items: center">  
7 - <div style="width: 245px">  
8 - <a-tree-select  
9 - @change="handleTreeOrg"  
10 - v-model:value="model[field]"  
11 - show-search  
12 - style="width: 100%"  
13 - :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"  
14 - placeholder="请选择组织"  
15 - allow-clear  
16 - tree-default-expand-all  
17 - :tree-data="model?.['organizationList'] || treeData"  
18 - />  
19 - </div>  
20 - <div>  
21 - <a-button type="link" @click="handleOpenOrgDrawer">新增组织</a-button>  
22 - </div>  
23 - </div>  
24 - </template>  
25 <template #snCode="{ model, field }"> 5 <template #snCode="{ model, field }">
26 <div class="flex"> 6 <div class="flex">
27 <Input :maxlength="36" v-model:value="model[field]" placeholder="请输入设备名称" /> 7 <Input :maxlength="36" v-model:value="model[field]" placeholder="请输入设备名称" />
@@ -36,7 +16,7 @@ @@ -36,7 +16,7 @@
36 </Input> 16 </Input>
37 </template> 17 </template>
38 </BasicForm> 18 </BasicForm>
39 - <div class="flex justify-center" v-if="isUpdate"> 19 + <div class="flex justify-center" v-if="!isUpdate">
40 <a-button type="primary" @click="nextStep">下一步</a-button> 20 <a-button type="primary" @click="nextStep">下一步</a-button>
41 </div> 21 </div>
42 </div> 22 </div>
@@ -91,11 +71,10 @@ @@ -91,11 +71,10 @@
91 </Spin> 71 </Spin>
92 </div> 72 </div>
93 </Modal> 73 </Modal>
94 - <DeptDrawer @register="registerModal" @success="handleSuccess" />  
95 </div> 74 </div>
96 </template> 75 </template>
97 <script lang="ts"> 76 <script lang="ts">
98 - import { defineComponent, ref, nextTick, unref, reactive, toRefs, onMounted } from 'vue'; 77 + import { defineComponent, ref, nextTick, unref, reactive } from 'vue';
99 import { BasicForm, useForm } from '/@/components/Form'; 78 import { BasicForm, useForm } from '/@/components/Form';
100 import { step1Schemas } from '../../config/data'; 79 import { step1Schemas } from '../../config/data';
101 import { useScript } from '/@/hooks/web/useScript'; 80 import { useScript } from '/@/hooks/web/useScript';
@@ -109,8 +88,6 @@ @@ -109,8 +88,6 @@
109 import { validatorLongitude, validatorLatitude } from '/@/utils/rules'; 88 import { validatorLongitude, validatorLatitude } from '/@/utils/rules';
110 import { getOrganizationList } from '/@/api/system/system'; 89 import { getOrganizationList } from '/@/api/system/system';
111 import { copyTransFun } from '/@/utils/fnUtils'; 90 import { copyTransFun } from '/@/utils/fnUtils';
112 - import { useDrawer } from '/@/components/Drawer';  
113 - import DeptDrawer from '/@/views/system/organization/OrganizationDrawer.vue';  
114 import { TaskTypeEnum } from '/@/views/task/center/config'; 91 import { TaskTypeEnum } from '/@/views/task/center/config';
115 import { toRaw } from 'vue'; 92 import { toRaw } from 'vue';
116 import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; 93 import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
@@ -129,7 +106,6 @@ @@ -129,7 +106,6 @@
129 FormItem: Form.Item, 106 FormItem: Form.Item,
130 Row, 107 Row,
131 Col, 108 Col,
132 - DeptDrawer,  
133 Spin, 109 Spin,
134 }, 110 },
135 props: { 111 props: {
@@ -152,16 +128,7 @@ @@ -152,16 +128,7 @@
152 copyTransFun(data as any as any[]); 128 copyTransFun(data as any as any[]);
153 orgData.treeData = data; 129 orgData.treeData = data;
154 }; 130 };
155 - onMounted(async () => {  
156 - await getOrganizationListFunc();  
157 - });  
158 - const { treeData } = toRefs(orgData);  
159 - const [registerModal, { openDrawer }] = useDrawer();  
160 - const handleOpenOrgDrawer = () => {  
161 - openDrawer(true, {  
162 - isUpdate: false,  
163 - });  
164 - }; 131 +
165 const handleSuccess = async () => { 132 const handleSuccess = async () => {
166 await getOrganizationListFunc(); 133 await getOrganizationListFunc();
167 }; 134 };
@@ -178,27 +145,18 @@ @@ -178,27 +145,18 @@
178 const devicePic = ref(''); 145 const devicePic = ref('');
179 const loading = ref(false); 146 const loading = ref(false);
180 147
181 - const [  
182 - register,  
183 - {  
184 - validate,  
185 - resetFields,  
186 - setFieldsValue,  
187 - getFieldsValue,  
188 - updateSchema,  
189 - clearValidate,  
190 - validateFields,  
191 - },  
192 - ] = useForm({  
193 - labelWidth: 140,  
194 - schemas: step1Schemas,  
195 - actionColOptions: {  
196 - span: 14,  
197 - },  
198 - labelAlign: 'right',  
199 - showResetButton: false,  
200 - showSubmitButton: false,  
201 - }); 148 + const [register, { validate, resetFields, setFieldsValue, getFieldsValue, updateSchema }] =
  149 + useForm({
  150 + labelWidth: 140,
  151 + schemas: step1Schemas,
  152 + actionColOptions: {
  153 + span: 14,
  154 + },
  155 + labelAlign: 'right',
  156 + showResetButton: false,
  157 + showSubmitButton: false,
  158 + });
  159 +
202 async function nextStep() { 160 async function nextStep() {
203 try { 161 try {
204 let values = await validate(); 162 let values = await validate();
@@ -245,7 +203,7 @@ @@ -245,7 +203,7 @@
245 const selectPosition = async () => { 203 const selectPosition = async () => {
246 visible.value = true; 204 visible.value = true;
247 if ( 205 if (
248 - !unref(isUpdate1) && 206 + unref(isUpdate1) &&
249 unref(devicePositionState).longitude && 207 unref(devicePositionState).longitude &&
250 unref(devicePositionState).latitude 208 unref(devicePositionState).latitude
251 ) { 209 ) {
@@ -440,8 +398,10 @@ @@ -440,8 +398,10 @@
440 positionState.address = deviceInfo.address; 398 positionState.address = deviceInfo.address;
441 devicePositionState.value = { ...toRaw(positionState) }; 399 devicePositionState.value = { ...toRaw(positionState) };
442 devicePic.value = deviceInfo.avatar; 400 devicePic.value = deviceInfo.avatar;
  401 +
443 if (deviceInfo.avatar) { 402 if (deviceInfo.avatar) {
444 setFieldsValue({ 403 setFieldsValue({
  404 + isUpdate: unref(isUpdate1),
445 icon: [{ uid: buildUUID(), name: 'name', url: deviceInfo.avatar } as FileItem], 405 icon: [{ uid: buildUUID(), name: 'name', url: deviceInfo.avatar } as FileItem],
446 }); 406 });
447 } 407 }
@@ -449,6 +409,7 @@ @@ -449,6 +409,7 @@
449 ...data, 409 ...data,
450 code: data?.code, 410 code: data?.code,
451 addressCode: parseInt(data?.code || '', 16), 411 addressCode: parseInt(data?.code || '', 16),
  412 + isUpdate: unref(isUpdate1),
452 }); 413 });
453 } 414 }
454 // 父组件调用获取字段值的方法 415 // 父组件调用获取字段值的方法
@@ -499,13 +460,6 @@ @@ -499,13 +460,6 @@
499 }); 460 });
500 } 461 }
501 462
502 - const handleTreeOrg = (option: string) => {  
503 - if (option) clearValidate('organizationId');  
504 - else {  
505 - validateFields(['organizationId']);  
506 - }  
507 - };  
508 -  
509 return { 463 return {
510 resetFields, 464 resetFields,
511 positionState, 465 positionState,
@@ -534,11 +488,7 @@ @@ -534,11 +488,7 @@
534 loading, 488 loading,
535 rules, 489 rules,
536 redirectPosition, 490 redirectPosition,
537 - treeData,  
538 - registerModal,  
539 - handleOpenOrgDrawer,  
540 handleSuccess, 491 handleSuccess,
541 - handleTreeOrg,  
542 devicePositionState, 492 devicePositionState,
543 spinning, 493 spinning,
544 }; 494 };
@@ -100,11 +100,9 @@ @@ -100,11 +100,9 @@
100 const { send, close } = useWebSocket(state.server, { 100 const { send, close } = useWebSocket(state.server, {
101 onConnected() { 101 onConnected() {
102 send(state.sendValue); 102 send(state.sendValue);
103 - console.log('建立连接了');  
104 }, 103 },
105 onMessage(_, e) { 104 onMessage(_, e) {
106 const { data } = JSON.parse(e.data); 105 const { data } = JSON.parse(e.data);
107 - console.log('来新消息了', '---data---', data);  
108 const newArray: socketDataType[] = []; 106 const newArray: socketDataType[] = [];
109 for (const key in data) { 107 for (const key in data) {
110 const [time, value] = data[key].flat(1); 108 const [time, value] = data[key].flat(1);
@@ -134,7 +132,6 @@ @@ -134,7 +132,6 @@
134 }); 132 });
135 }, 133 },
136 onDisconnected() { 134 onDisconnected() {
137 - console.log('断开连接了');  
138 close(); 135 close();
139 }, 136 },
140 onError() { 137 onError() {
@@ -32,13 +32,12 @@ @@ -32,13 +32,12 @@
32 import { BasicTable, useTable, TableAction } from '/@/components/Table'; 32 import { BasicTable, useTable, TableAction } from '/@/components/Table';
33 import { Switch } from 'ant-design-vue'; 33 import { Switch } from 'ant-design-vue';
34 import { DeviceRecord } from '/@/api/device/model/deviceModel'; 34 import { DeviceRecord } from '/@/api/device/model/deviceModel';
35 - import { watch } from 'vue';  
36 import VideoModal from './videoModal.vue'; 35 import VideoModal from './videoModal.vue';
37 import { useModal } from '/@/components/Modal'; 36 import { useModal } from '/@/components/Modal';
38 import { onMounted } from 'vue'; 37 import { onMounted } from 'vue';
39 import { useMessage } from '/@/hooks/web/useMessage'; 38 import { useMessage } from '/@/hooks/web/useMessage';
40 39
41 - const props = defineProps({ 40 + defineProps({
42 fromId: { 41 fromId: {
43 type: String, 42 type: String,
44 default: '', 43 default: '',
@@ -49,13 +48,6 @@ @@ -49,13 +48,6 @@
49 }, 48 },
50 }); 49 });
51 50
52 - watch(  
53 - () => props,  
54 - () => {  
55 - console.log(props, 'props');  
56 - }  
57 - );  
58 -  
59 const [registerModal, { openModal }] = useModal(); 51 const [registerModal, { openModal }] = useModal();
60 52
61 const [registerTable, { setTableData, setProps, setSelectedRowKeys, reload }] = useTable({ 53 const [registerTable, { setTableData, setProps, setSelectedRowKeys, reload }] = useTable({
@@ -68,14 +60,10 @@ @@ -68,14 +60,10 @@
68 labelWidth: 120, 60 labelWidth: 120,
69 schemas: searchFormSchema, 61 schemas: searchFormSchema,
70 }, 62 },
71 - beforeFetch: (params) => {  
72 - console.log(params);  
73 - },  
74 useSearchForm: true, 63 useSearchForm: true,
75 }); 64 });
76 65
77 - const handleTurnVideo = async (checked: Boolean, record: Recordable) => {  
78 - console.log(checked, record, 'record'); 66 + const handleTurnVideo = async (checked: Boolean, _record: Recordable) => {
79 setProps({ 67 setProps({
80 loading: true, 68 loading: true,
81 }); 69 });
@@ -281,7 +269,6 @@ @@ -281,7 +269,6 @@
281 }); 269 });
282 270
283 const handlePlay = (record: Recordable) => { 271 const handlePlay = (record: Recordable) => {
284 - console.log(record);  
285 openModal(true, { 272 openModal(true, {
286 record, 273 record,
287 }); 274 });
@@ -4,41 +4,57 @@ @@ -4,41 +4,57 @@
4 <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> 4 <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" />
5 <BasicTable style="flex: auto" @register="registerTable" class="w-5/6 xl:w-4/5"> 5 <BasicTable style="flex: auto" @register="registerTable" class="w-5/6 xl:w-4/5">
6 <template #toolbar> 6 <template #toolbar>
7 - <Authority value="api:yt:device:post"> 7 + <Authority :value="DeviceListAuthEnum.CREATE">
8 <a-button type="primary" @click="handleCreate" v-if="authBtn(role)"> 8 <a-button type="primary" @click="handleCreate" v-if="authBtn(role)">
9 新增设备 9 新增设备
10 </a-button> 10 </a-button>
11 </Authority> 11 </Authority>
12 - <Authority value="api:yt:device:delete">  
13 - <Popconfirm  
14 - title="您确定要批量删除数据"  
15 - ok-text="确定"  
16 - cancel-text="取消"  
17 - @confirm="handleDelete()"  
18 - >  
19 - <a-button color="error" v-if="authBtn(role)" :disabled="!isExistOption">  
20 - 批量删除  
21 - </a-button>  
22 - </Popconfirm>  
23 - </Authority>  
24 - <Authority value="api:yt:device:import"> 12 +
  13 + <Authority :value="DeviceListAuthEnum.IMPORT">
25 <Button type="primary" @click="handleBatchImport">导入</Button> 14 <Button type="primary" @click="handleBatchImport">导入</Button>
26 </Authority> 15 </Authority>
27 - <Authority value="api:yt:device:assign">  
28 - <a-button 16 +
  17 + <Authority
  18 + :value="[
  19 + DeviceListAuthEnum.DELETE,
  20 + DeviceListAuthEnum.ASSIGN,
  21 + DeviceListAuthEnum.UPDATE_PRODUCT,
  22 + ]"
  23 + >
  24 + <AuthDropDown
29 v-if="authBtn(role)" 25 v-if="authBtn(role)"
30 - type="primary"  
31 - @click="handleBatchAssign"  
32 :disabled="!isExistOption" 26 :disabled="!isExistOption"
  27 + :dropMenuList="[
  28 + {
  29 + text: '删除设备',
  30 + auth: DeviceListAuthEnum.DELETE,
  31 + icon: 'ant-design:delete-outlined',
  32 + event: '',
  33 + popconfirm: {
  34 + title: '您确定要批量删除数据',
  35 + onConfirm: () => handleDelete(),
  36 + },
  37 + },
  38 + {
  39 + text: '分配客户',
  40 + auth: DeviceListAuthEnum.ASSIGN,
  41 + icon: 'mdi:account-arrow-left',
  42 + event: '',
  43 + onClick: handleBatchAssign.bind(null),
  44 + },
  45 + {
  46 + text: '更新产品',
  47 + auth: DeviceListAuthEnum.UPDATE_PRODUCT,
  48 + icon: 'clarity:note-edit-line',
  49 + event: '',
  50 + disabled: batchUpdateProductFlag,
  51 + onClick: handelOpenBatchUpdateProductModal,
  52 + },
  53 + ]"
33 > 54 >
34 - 批量分配  
35 - </a-button> 55 + <Button type="primary" :disabled="!isExistOption">批量操作</Button>
  56 + </AuthDropDown>
36 </Authority> 57 </Authority>
37 - <!-- <Authority>  
38 - <a-button type="primary" @click="handelCollect()" :disabled="!isExistOption">  
39 - 批量收藏  
40 - </a-button>  
41 - </Authority> -->  
42 </template> 58 </template>
43 <template #img="{ record }"> 59 <template #img="{ record }">
44 <TableImg 60 <TableImg
@@ -121,12 +137,12 @@ @@ -121,12 +137,12 @@
121 { 137 {
122 label: '详情', 138 label: '详情',
123 icon: 'ant-design:eye-outlined', 139 icon: 'ant-design:eye-outlined',
124 - auth: 'api:yt:device:get', 140 + auth: DeviceListAuthEnum.DETAIL,
125 onClick: handleDetail.bind(null, record), 141 onClick: handleDetail.bind(null, record),
126 }, 142 },
127 { 143 {
128 label: '编辑', 144 label: '编辑',
129 - auth: 'api:yt:device:update', 145 + auth: DeviceListAuthEnum.UPDATE,
130 icon: 'clarity:note-edit-line', 146 icon: 'clarity:note-edit-line',
131 ifShow: authBtn(role), 147 ifShow: authBtn(role),
132 onClick: handleEdit.bind(null, record), 148 onClick: handleEdit.bind(null, record),
@@ -138,7 +154,7 @@ @@ -138,7 +154,7 @@
138 label: '取消分配', 154 label: '取消分配',
139 icon: 'mdi:account-arrow-left', 155 icon: 'mdi:account-arrow-left',
140 ifShow: authBtn(role) && !record?.customerAdditionalInfo?.isPublic, 156 ifShow: authBtn(role) && !record?.customerAdditionalInfo?.isPublic,
141 - auth: 'api:yt:device:assign', 157 + auth: DeviceListAuthEnum.ASSIGN,
142 popConfirm: { 158 popConfirm: {
143 title: '是否取消分配客户', 159 title: '是否取消分配客户',
144 confirm: handleCancelDispatchCustomer.bind(null, record), 160 confirm: handleCancelDispatchCustomer.bind(null, record),
@@ -148,12 +164,12 @@ @@ -148,12 +164,12 @@
148 label: '分配客户', 164 label: '分配客户',
149 icon: 'mdi:account-arrow-right', 165 icon: 'mdi:account-arrow-right',
150 ifShow: authBtn(role), 166 ifShow: authBtn(role),
151 - auth: 'api:yt:device:assign', 167 + auth: DeviceListAuthEnum.ASSIGN,
152 onClick: handleDispatchCustomer.bind(null, record), 168 onClick: handleDispatchCustomer.bind(null, record),
153 }, 169 },
154 { 170 {
155 label: record?.customerAdditionalInfo?.isPublic ? '私有' : '公开', 171 label: record?.customerAdditionalInfo?.isPublic ? '私有' : '公开',
156 - auth: 'api:yt:device:public', 172 + auth: DeviceListAuthEnum.PUBLIC,
157 icon: record?.customerAdditionalInfo?.isPublic 173 icon: record?.customerAdditionalInfo?.isPublic
158 ? 'ant-design:lock-outlined' 174 ? 'ant-design:lock-outlined'
159 : 'ant-design:unlock-outlined', 175 : 'ant-design:unlock-outlined',
@@ -161,7 +177,7 @@ @@ -161,7 +177,7 @@
161 }, 177 },
162 { 178 {
163 label: '上下线记录', 179 label: '上下线记录',
164 - auth: 'api:yt:device:online:record', 180 + auth: DeviceListAuthEnum.ONLINE,
165 icon: 'ant-design:rise-outlined', 181 icon: 'ant-design:rise-outlined',
166 onClick: handleUpAndDownRecord.bind(null, record), 182 onClick: handleUpAndDownRecord.bind(null, record),
167 }, 183 },
@@ -173,7 +189,6 @@ @@ -173,7 +189,6 @@
173 } 189 }
174 : { 190 : {
175 label: '取消收藏', 191 label: '取消收藏',
176 - auth: 'api:yt:device:online:record',  
177 icon: 'ant-design:heart-outlined', 192 icon: 'ant-design:heart-outlined',
178 popConfirm: { 193 popConfirm: {
179 title: '是否取消收藏', 194 title: '是否取消收藏',
@@ -182,7 +197,7 @@ @@ -182,7 +197,7 @@
182 }, 197 },
183 { 198 {
184 label: '删除', 199 label: '删除',
185 - auth: 'api:yt:device:delete', 200 + auth: DeviceListAuthEnum.DELETE,
186 icon: 'ant-design:delete-outlined', 201 icon: 'ant-design:delete-outlined',
187 ifShow: authBtn(role) && record.customerId === undefined, 202 ifShow: authBtn(role) && record.customerId === undefined,
188 color: 'error', 203 color: 'error',
@@ -208,11 +223,16 @@ @@ -208,11 +223,16 @@
208 <CustomerModal @register="registerCustomerModal" @reload="handleReload" /> 223 <CustomerModal @register="registerCustomerModal" @reload="handleReload" />
209 224
210 <BatchImportModal @register="registerImportModal" @import-finally="handleImportFinally" /> 225 <BatchImportModal @register="registerImportModal" @import-finally="handleImportFinally" />
  226 +
  227 + <BatchUpdateProductModal
  228 + @register="registerBatchUpdateProductModal"
  229 + @success="handleBatchUpdateProductSuccess"
  230 + />
211 </PageWrapper> 231 </PageWrapper>
212 </div> 232 </div>
213 </template> 233 </template>
214 -<script lang="ts">  
215 - import { defineComponent, reactive, unref, onMounted } from 'vue'; 234 +<script lang="ts" setup>
  235 + import { reactive, onMounted, ref } from 'vue';
216 import { 236 import {
217 DeviceModel, 237 DeviceModel,
218 DeviceRecord, 238 DeviceRecord,
@@ -220,8 +240,8 @@ @@ -220,8 +240,8 @@
220 DeviceTypeEnum, 240 DeviceTypeEnum,
221 } from '/@/api/device/model/deviceModel'; 241 } from '/@/api/device/model/deviceModel';
222 import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table'; 242 import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table';
223 - import { columns, searchFormSchema } from './config/device.data';  
224 - import { Tag, Popover, Popconfirm, Button, Tooltip } from 'ant-design-vue'; 243 + import { columns, DeviceListAuthEnum, searchFormSchema } from './config/device.data';
  244 + import { Tag, Popover, Button, Tooltip } from 'ant-design-vue';
225 import { HeartTwoTone } from '@ant-design/icons-vue'; 245 import { HeartTwoTone } from '@ant-design/icons-vue';
226 import { 246 import {
227 deleteDevice, 247 deleteDevice,
@@ -246,326 +266,295 @@ @@ -246,326 +266,295 @@
246 import { USER_INFO_KEY } from '/@/enums/cacheEnum'; 266 import { USER_INFO_KEY } from '/@/enums/cacheEnum';
247 import { getAuthCache } from '/@/utils/auth'; 267 import { getAuthCache } from '/@/utils/auth';
248 import { authBtn } from '/@/enums/roleEnum'; 268 import { authBtn } from '/@/enums/roleEnum';
249 - import { useClipboard } from '@vueuse/core';  
250 import { QuestionCircleOutlined } from '@ant-design/icons-vue'; 269 import { QuestionCircleOutlined } from '@ant-design/icons-vue';
251 import { Authority } from '/@/components/Authority'; 270 import { Authority } from '/@/components/Authority';
252 import { useRoute, useRouter } from 'vue-router'; 271 import { useRoute, useRouter } from 'vue-router';
253 import { useBatchOperation } from '/@/utils/useBatchOperation'; 272 import { useBatchOperation } from '/@/utils/useBatchOperation';
254 import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm'; 273 import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm';
255 import { useAuthDeviceDetail } from './hook/useAuthDeviceDetail'; 274 import { useAuthDeviceDetail } from './hook/useAuthDeviceDetail';
  275 + import {
  276 + BatchUpdateProductModal,
  277 + BatchUpdateProductModalParamsType,
  278 + } from './cpns/modal/BatchUpdateProductModal';
  279 + import { DataActionModeEnum } from '/@/enums/toolEnum';
  280 + import { AuthDropDown } from '/@/components/Widget';
256 281
257 - export default defineComponent({  
258 - name: 'DeviceManagement',  
259 - components: {  
260 - BasicTable,  
261 - PageWrapper,  
262 - TableAction,  
263 - OrganizationIdTree,  
264 - Tag,  
265 - DeviceModal,  
266 - DeviceDetailDrawer,  
267 - CustomerModal,  
268 - TableImg,  
269 - QuestionCircleOutlined,  
270 - Popover,  
271 - Authority,  
272 - Popconfirm,  
273 - BatchImportModal,  
274 - Button,  
275 - // HeartOutlined,  
276 - HeartTwoTone,  
277 - Tooltip,  
278 - },  
279 - setup(_) {  
280 - const { isCustomer } = useAuthDeviceDetail();  
281 - const { createMessage } = useMessage();  
282 - const go = useGo();  
283 - const ROUTER = useRouter();  
284 - const ROUTE = useRoute();  
285 - const searchInfo = reactive<Recordable>({});  
286 - const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);  
287 - const [registerModal, { openModal }] = useModal();  
288 - const [registerCustomerModal, { openModal: openCustomerModal }] = useModal();  
289 - const [registerDetailDrawer, { openDrawer }] = useDrawer();  
290 - const [registerTbDetailDrawer, { openDrawer: openTbDeviceDrawer }] = useDrawer();  
291 - const [registerGatewayDetailDrawer, { openDrawer: openGatewayDetailDrawer }] = useDrawer();  
292 - const [registerImportModal, { openModal: openImportModal }] = useModal(); 282 + const { isCustomer } = useAuthDeviceDetail();
  283 + const { createMessage } = useMessage();
  284 + const go = useGo();
  285 + const ROUTER = useRouter();
  286 + const ROUTE = useRoute();
  287 + const searchInfo = reactive<Recordable>({});
  288 + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
  289 + const [registerModal, { openModal }] = useModal();
  290 + const [registerCustomerModal, { openModal: openCustomerModal }] = useModal();
  291 + const [registerDetailDrawer, { openDrawer }] = useDrawer();
  292 + const [registerTbDetailDrawer, { openDrawer: openTbDeviceDrawer }] = useDrawer();
  293 + const [registerGatewayDetailDrawer, { openDrawer: openGatewayDetailDrawer }] = useDrawer();
  294 + const [registerImportModal, { openModal: openImportModal }] = useModal();
  295 + const [registerBatchUpdateProductModal, { openModal: openBatchUpdateProductModal }] = useModal();
293 296
294 - const [  
295 - registerTable,  
296 - {  
297 - reload,  
298 - setLoading,  
299 - setSelectedRowKeys,  
300 - getForm,  
301 - getSelectRowKeys,  
302 - getSelectRows,  
303 - getRowSelection,  
304 - },  
305 - ] = useTable({  
306 - title: '设备列表',  
307 - api: devicePage,  
308 - columns,  
309 - beforeFetch: (params) => {  
310 - const { deviceProfileId } = params;  
311 - if (!deviceProfileId) return;  
312 - const obj = {  
313 - ...params,  
314 - ...{  
315 - deviceProfileIds: deviceProfileId ? [deviceProfileId] : null,  
316 - },  
317 - };  
318 - delete obj.deviceProfileId;  
319 - return obj;  
320 - },  
321 - formConfig: {  
322 - labelWidth: 100,  
323 - schemas: searchFormSchema,  
324 - resetFunc: resetFn,  
325 - },  
326 - useSearchForm: true,  
327 - showTableSetting: true,  
328 - bordered: true,  
329 - showIndexColumn: false,  
330 - rowKey: 'id',  
331 - searchInfo: searchInfo,  
332 - clickToRowSelect: false,  
333 - actionColumn: {  
334 - width: 200,  
335 - title: '操作',  
336 - slots: { customRender: 'action' },  
337 - fixed: 'right',  
338 - },  
339 - rowSelection: {  
340 - type: 'checkbox',  
341 - getCheckboxProps: (record: DeviceModel) => {  
342 - return { disabled: !!record.customerId };  
343 - }, 297 + const batchUpdateProductFlag = ref(true);
  298 +
  299 + const [
  300 + registerTable,
  301 + {
  302 + reload,
  303 + setLoading,
  304 + setSelectedRowKeys,
  305 + getForm,
  306 + getSelectRowKeys,
  307 + getSelectRows,
  308 + getRowSelection,
  309 + clearSelectedRowKeys,
  310 + },
  311 + ] = useTable({
  312 + title: '设备列表',
  313 + api: devicePage,
  314 + columns,
  315 + beforeFetch: (params) => {
  316 + const { deviceProfileId } = params;
  317 + if (!deviceProfileId) return;
  318 + const obj = {
  319 + ...params,
  320 + ...{
  321 + deviceProfileIds: deviceProfileId ? [deviceProfileId] : null,
344 }, 322 },
345 - }); 323 + };
  324 + delete obj.deviceProfileId;
  325 + return obj;
  326 + },
  327 + formConfig: {
  328 + labelWidth: 100,
  329 + schemas: searchFormSchema,
  330 + resetFunc: resetFn,
  331 + },
  332 + useSearchForm: true,
  333 + showTableSetting: true,
  334 + bordered: true,
  335 + showIndexColumn: false,
  336 + rowKey: 'id',
  337 + searchInfo: searchInfo,
  338 + clickToRowSelect: false,
  339 + actionColumn: {
  340 + width: 200,
  341 + title: '操作',
  342 + slots: { customRender: 'action' },
  343 + fixed: 'right',
  344 + },
  345 + rowSelection: {
  346 + type: 'checkbox',
  347 + getCheckboxProps: (record: DeviceModel) => {
  348 + return { disabled: !!record.customerId };
  349 + },
  350 + onSelect(_record, _selected, selectedRows) {
  351 + const [firstItem] = selectedRows as DeviceRecord[];
  352 + const { deviceType } = firstItem || {};
  353 + batchUpdateProductFlag.value =
  354 + !selectedRows.length ||
  355 + !selectedRows.every((item) => (item as DeviceRecord).deviceType === deviceType);
  356 + },
  357 + onSelectAll(_selected, selectedRows) {
  358 + const [firstItem] = selectedRows as DeviceRecord[];
  359 + const { deviceType } = firstItem || {};
  360 + batchUpdateProductFlag.value =
  361 + !selectedRows.length ||
  362 + !selectedRows.every((item) => (item as DeviceRecord).deviceType === deviceType);
  363 + },
  364 + },
  365 + });
346 366
347 - const { isExistOption } = useBatchOperation(getRowSelection, setSelectedRowKeys); 367 + const { isExistOption } = useBatchOperation(getRowSelection, setSelectedRowKeys);
348 368
349 - const userInfo: any = getAuthCache(USER_INFO_KEY);  
350 - const role: string = userInfo.roles[0]; 369 + const userInfo: any = getAuthCache(USER_INFO_KEY);
  370 + const role: string = userInfo.roles[0];
351 371
352 - function handleCreate() {  
353 - openModal(true, {  
354 - isUpdate: false,  
355 - });  
356 - }  
357 - // 分配客户  
358 - function handleDispatchCustomer(record: Recordable) {  
359 - openCustomerModal(true, record);  
360 - }  
361 - function handleReload() {  
362 - setSelectedRowKeys([]);  
363 - handleSuccess();  
364 - }  
365 - // 取消分配客户  
366 - async function handleCancelDispatchCustomer(record: Recordable) {  
367 - try {  
368 - // 该设备是否正在被场景联动使用中?  
369 - await cancelDispatchCustomer(record);  
370 - handleReload();  
371 - } catch {}  
372 - } 372 + function handleCreate() {
  373 + openModal(true, {
  374 + isUpdate: false,
  375 + });
  376 + }
  377 + // 分配客户
  378 + function handleDispatchCustomer(record: Recordable) {
  379 + openCustomerModal(true, record);
  380 + }
  381 + function handleReload() {
  382 + setSelectedRowKeys([]);
  383 + handleSuccess();
  384 + }
  385 + // 取消分配客户
  386 + async function handleCancelDispatchCustomer(record: Recordable) {
  387 + try {
  388 + // 该设备是否正在被场景联动使用中?
  389 + await cancelDispatchCustomer(record);
  390 + handleReload();
  391 + } catch {}
  392 + }
373 393
374 - function handleDetail(record: Recordable) {  
375 - const { id, tbDeviceId, deviceProfile, deviceType } = record;  
376 - const { transportType } = deviceProfile || {};  
377 - openDrawer(true, {  
378 - id,  
379 - tbDeviceId,  
380 - transportType,  
381 - deviceType,  
382 - });  
383 - } 394 + function handleDetail(record: Recordable) {
  395 + const { id, tbDeviceId, deviceProfile, deviceType } = record;
  396 + const { transportType } = deviceProfile || {};
  397 + openDrawer(true, {
  398 + id,
  399 + tbDeviceId,
  400 + transportType,
  401 + deviceType,
  402 + });
  403 + }
384 404
385 - async function handleEdit(record: Recordable) {  
386 - if (record.deviceType === 'SENSOR') {  
387 - const res = await getGATEWAY(record.tbDeviceId);  
388 - Reflect.set(record, 'gatewayId', res.tbDeviceId);  
389 - }  
390 - openModal(true, {  
391 - isUpdate: true,  
392 - record,  
393 - });  
394 - }  
395 - function handleSuccess() {  
396 - reload();  
397 - }  
398 - function handleSelect(organization) {  
399 - searchInfo.organizationId = organization;  
400 - handleSuccess();  
401 - }  
402 - function goDeviceProfile(e) {  
403 - go(PageEnum.DEVICE_PROFILE + '?name=' + encodeURIComponent(String(e)));  
404 - }  
405 - const { copied, copy } = useClipboard({ legacy: true });  
406 - const copySN = async (snCode: string) => {  
407 - await copy(snCode);  
408 - if (unref(copied)) {  
409 - createMessage.success('复制成功~');  
410 - }  
411 - }; 405 + async function handleEdit(record: Recordable) {
  406 + if (record.deviceType === 'SENSOR') {
  407 + const res = await getGATEWAY(record.tbDeviceId);
  408 + Reflect.set(record, 'gatewayId', res.tbDeviceId);
  409 + }
  410 + openModal(true, {
  411 + isUpdate: true,
  412 + record,
  413 + });
  414 + }
  415 + function handleSuccess() {
  416 + reload();
  417 + }
  418 + function handleSelect(organization) {
  419 + searchInfo.organizationId = organization;
  420 + handleSuccess();
  421 + }
  422 + function goDeviceProfile(e) {
  423 + go(PageEnum.DEVICE_PROFILE + '?name=' + encodeURIComponent(String(e)));
  424 + }
412 425
413 - const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => {  
414 - openTbDeviceDrawer(true, data);  
415 - }; 426 + const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => {
  427 + openTbDeviceDrawer(true, data);
  428 + };
416 429
417 - const handleOpenGatewayDetail = (data: { id: string; tbDeviceId: string }) => {  
418 - openGatewayDetailDrawer(true, data);  
419 - }; 430 + const handleOpenGatewayDetail = (data: { id: string; tbDeviceId: string }) => {
  431 + openGatewayDetailDrawer(true, data);
  432 + };
420 433
421 - const handleUpAndDownRecord = (record: Record<'name' | 'alias', string>) => {  
422 - ROUTER.push({  
423 - path: '/operation/onlinerecord',  
424 - query: { deviceName: record.alias || record.name },  
425 - });  
426 - }; 434 + const handleUpAndDownRecord = (record: Record<'name' | 'alias', string>) => {
  435 + ROUTER.push({
  436 + path: '/operation/onlinerecord',
  437 + query: { deviceName: record.alias || record.name },
  438 + });
  439 + };
427 440
428 - const handleCheckHasDiffenterOrg = (options: DeviceModel[]) => {  
429 - let orgId: string | undefined;  
430 - let flag = false;  
431 - for (const item of options) {  
432 - const _orgId = item.organizationId;  
433 - if (!orgId) orgId = _orgId;  
434 - if (orgId !== _orgId) {  
435 - flag = true;  
436 - break;  
437 - }  
438 - }  
439 - return flag;  
440 - }; 441 + const handleCheckHasDiffenterOrg = (options: DeviceModel[]) => {
  442 + let orgId: string | undefined;
  443 + let flag = false;
  444 + for (const item of options) {
  445 + const _orgId = item.organizationId;
  446 + if (!orgId) orgId = _orgId;
  447 + if (orgId !== _orgId) {
  448 + flag = true;
  449 + break;
  450 + }
  451 + }
  452 + return flag;
  453 + };
441 454
442 - const handleBatchAssign = () => {  
443 - const options = getSelectRows();  
444 - if (handleCheckHasDiffenterOrg(options as DeviceModel[])) {  
445 - createMessage.error('当前选中项中存在不同所属组织的设备!');  
446 - return;  
447 - }  
448 - openCustomerModal(true, options);  
449 - }; 455 + const handleBatchAssign = () => {
  456 + const options = getSelectRows();
  457 + if (handleCheckHasDiffenterOrg(options as DeviceModel[])) {
  458 + createMessage.error('当前选中项中存在不同所属组织的设备!');
  459 + return;
  460 + }
  461 + openCustomerModal(true, options);
  462 + };
450 463
451 - const handleDelete = async (record?: DeviceRecord) => {  
452 - let ids: string[] = [];  
453 - if (record) {  
454 - ids.push(record.id);  
455 - } else {  
456 - ids = getSelectRowKeys();  
457 - }  
458 - try {  
459 - setLoading(true);  
460 - await deleteDevice(ids);  
461 - createMessage.success('删除成功');  
462 - handleReload();  
463 - } catch (error) {  
464 - throw error;  
465 - } finally {  
466 - setLoading(false);  
467 - }  
468 - }; 464 + const handleDelete = async (record?: DeviceRecord) => {
  465 + let ids: string[] = [];
  466 + if (record) {
  467 + ids.push(record.id);
  468 + } else {
  469 + ids = getSelectRowKeys();
  470 + }
  471 + try {
  472 + setLoading(true);
  473 + await deleteDevice(ids);
  474 + createMessage.success('删除成功');
  475 + handleReload();
  476 + } catch (error) {
  477 + throw error;
  478 + } finally {
  479 + setLoading(false);
  480 + }
  481 + };
469 482
470 - const handleBatchImport = () => {  
471 - openImportModal(true);  
472 - }; 483 + const handleBatchImport = () => {
  484 + openImportModal(true);
  485 + };
473 486
474 - const handleImportFinally = () => {  
475 - reload();  
476 - }; 487 + const handleImportFinally = () => {
  488 + reload();
  489 + };
477 490
478 - const { createSyncConfirm } = useSyncConfirm();  
479 - const handlePublicDevice = async (record: DeviceRecord) => {  
480 - try {  
481 - const publicFlag = record?.customerAdditionalInfo?.isPublic;  
482 - const type = publicFlag ? '私有' : '公开';  
483 - const flag = await createSyncConfirm({  
484 - iconType: 'warning',  
485 - title: `您确定要将设备 '${record.name}' 设为${type}吗?`,  
486 - content: `确认后,设备及其所有数据将被设为${type}并${  
487 - publicFlag ? '不' : ''  
488 - }可被其他人访问。`,  
489 - });  
490 - if (!flag) return;  
491 - if (publicFlag) {  
492 - await privateDevice(record.tbDeviceId);  
493 - } else {  
494 - await publicDevice(record.tbDeviceId);  
495 - }  
496 - reload();  
497 - } catch (error) {}  
498 - }; 491 + const { createSyncConfirm } = useSyncConfirm();
  492 + const handlePublicDevice = async (record: DeviceRecord) => {
  493 + try {
  494 + const publicFlag = record?.customerAdditionalInfo?.isPublic;
  495 + const type = publicFlag ? '私有' : '公开';
  496 + const flag = await createSyncConfirm({
  497 + iconType: 'warning',
  498 + title: `您确定要将设备 '${record.name}' 设为${type}吗?`,
  499 + content: `确认后,设备及其所有数据将被设为${type}并${
  500 + publicFlag ? '不' : ''
  501 + }可被其他人访问。`,
  502 + });
  503 + if (!flag) return;
  504 + if (publicFlag) {
  505 + await privateDevice(record.tbDeviceId);
  506 + } else {
  507 + await publicDevice(record.tbDeviceId);
  508 + }
  509 + reload();
  510 + } catch (error) {}
  511 + };
499 512
500 - // 收藏 && 批量收藏  
501 - const handelCollect = async (record?: Recordable) => {  
502 - let ids: string[] = [];  
503 - if (record) {  
504 - ids.push(record.id);  
505 - } else {  
506 - ids = await getSelectRowKeys();  
507 - }  
508 - try {  
509 - setLoading(true);  
510 - await deviceCollect(ids);  
511 - createMessage.success('操作成功');  
512 - handleReload();  
513 - } catch (error) {  
514 - throw error;  
515 - } finally {  
516 - setLoading(false);  
517 - }  
518 - }; 513 + // 收藏 && 批量收藏
  514 + const handelCollect = async (record?: Recordable) => {
  515 + let ids: string[] = [];
  516 + if (record) {
  517 + ids.push(record.id);
  518 + } else {
  519 + ids = await getSelectRowKeys();
  520 + }
  521 + try {
  522 + setLoading(true);
  523 + await deviceCollect(ids);
  524 + createMessage.success('操作成功');
  525 + handleReload();
  526 + } catch (error) {
  527 + throw error;
  528 + } finally {
  529 + setLoading(false);
  530 + }
  531 + };
519 532
520 - onMounted(() => {  
521 - const queryParams = ROUTE.query as Record<'deviceProfileId', undefined | string>;  
522 - const { setFieldsValue } = getForm();  
523 - setFieldsValue({ deviceProfileId: queryParams.deviceProfileId });  
524 - });  
525 - return {  
526 - registerTable,  
527 - handleCreate,  
528 - handleDetail,  
529 - handleEdit,  
530 - handleSuccess,  
531 - goDeviceProfile,  
532 - handleSelect,  
533 - registerModal,  
534 - registerDetailDrawer,  
535 - DeviceTypeEnum,  
536 - DeviceState,  
537 - searchInfo,  
538 - organizationIdTreeRef,  
539 - handleDispatchCustomer,  
540 - handleCancelDispatchCustomer,  
541 - registerCustomerModal,  
542 - authBtn,  
543 - role,  
544 - copySN,  
545 - isExistOption,  
546 - handleDelete,  
547 - handelCollect,  
548 - // hasBatchDelete,  
549 - // handleDeleteOrBatchDelete,  
550 - handleReload,  
551 - registerTbDetailDrawer,  
552 - handleOpenTbDeviceDetail,  
553 - handleOpenGatewayDetail,  
554 - registerGatewayDetailDrawer,  
555 - handleUpAndDownRecord,  
556 - handleBatchAssign,  
557 - registerImportModal,  
558 - handleBatchImport,  
559 - handleImportFinally,  
560 - handlePublicDevice,  
561 - isCustomer,  
562 - };  
563 - }, 533 + onMounted(() => {
  534 + const queryParams = ROUTE.query as Record<'deviceProfileId', undefined | string>;
  535 + const { setFieldsValue } = getForm();
  536 + setFieldsValue({ deviceProfileId: queryParams.deviceProfileId });
564 }); 537 });
  538 +
  539 + const handelOpenBatchUpdateProductModal = () => {
  540 + const rows: DeviceRecord[] = getSelectRows();
  541 + const [firstItem] = rows;
  542 +
  543 + openBatchUpdateProductModal(true, {
  544 + mode: DataActionModeEnum.UPDATE,
  545 + record: {
  546 + sourceDeviceProfileName: firstItem.deviceProfile.name,
  547 + deviceType: firstItem.deviceType,
  548 + deviceIds: rows.map((item) => item.tbDeviceId),
  549 + },
  550 + } as BatchUpdateProductModalParamsType);
  551 + };
  552 +
  553 + const handleBatchUpdateProductSuccess = () => {
  554 + reload();
  555 + clearSelectedRowKeys();
  556 + batchUpdateProductFlag.value = true;
  557 + };
565 </script> 558 </script>
566 559
567 -<style scoped lang="css">  
568 - /* /deep/.ant-message-notice-content {  
569 - max-width: 600px !important;  
570 - } */  
571 -</style> 560 +<style scoped lang="css"></style>
@@ -346,7 +346,6 @@ export const schemas: FormSchema[] = [ @@ -346,7 +346,6 @@ export const schemas: FormSchema[] = [
346 return { 346 return {
347 onChange(value) { 347 onChange(value) {
348 const { updateSchema } = formActionType; 348 const { updateSchema } = formActionType;
349 - console.log(value);  
350 formModel.interval = ''; 349 formModel.interval = '';
351 updateSchema({ 350 updateSchema({
352 field: 'interval', 351 field: 'interval',
@@ -235,7 +235,6 @@ @@ -235,7 +235,6 @@
235 235
236 function loadDataSuccess(excelDataList: ExcelData[]) { 236 function loadDataSuccess(excelDataList: ExcelData[]) {
237 tableListRef.value = []; 237 tableListRef.value = [];
238 - console.log(excelDataList);  
239 for (const excelData of excelDataList) { 238 for (const excelData of excelDataList) {
240 const { 239 const {
241 header, 240 header,
@@ -294,9 +293,7 @@ @@ -294,9 +293,7 @@
294 }); 293 });
295 }; 294 };
296 //导入 295 //导入
297 - function handleImport() {  
298 - console.log('record');  
299 - } 296 + function handleImport() {}
300 function handleSuccess() { 297 function handleSuccess() {
301 reload(); 298 reload();
302 } 299 }
@@ -204,8 +204,7 @@ @@ -204,8 +204,7 @@
204 }); 204 });
205 flag && createMessage.info(flag?.message); 205 flag && createMessage.info(flag?.message);
206 } catch (msg) { 206 } catch (msg) {
207 - // eslint-disable-next-line no-console  
208 - console.log(msg, 'msg'); 207 + console.error(msg, 'msg');
209 } finally { 208 } finally {
210 closeLoading(); 209 closeLoading();
211 closeModal(); 210 closeModal();
@@ -96,7 +96,6 @@ @@ -96,7 +96,6 @@
96 render: (_, data: Bootstrap) => (data.notifIfDisabled ? '启用' : '禁用'), 96 render: (_, data: Bootstrap) => (data.notifIfDisabled ? '启用' : '禁用'),
97 }, 97 },
98 ]; 98 ];
99 - console.log(unref(getOtherSetting));  
100 const [registerOtherSettings] = useDescription({ 99 const [registerOtherSettings] = useDescription({
101 layout: 'vertical', 100 layout: 'vertical',
102 column: 2, 101 column: 2,
@@ -68,21 +68,18 @@ @@ -68,21 +68,18 @@
68 <Button v-if="isShowBtn" class="!bg-gray-200" type="text" @click="handleReturn"> 68 <Button v-if="isShowBtn" class="!bg-gray-200" type="text" @click="handleReturn">
69 返回 69 返回
70 </Button> 70 </Button>
71 - <Authority :value="[ModelOfMatterPermission.DELETE, ModelCategoryPermission.DELETE]"> 71 + <Authority
  72 + v-if="isShowBtn"
  73 + :value="[ModelOfMatterPermission.DELETE, ModelCategoryPermission.DELETE]"
  74 + >
72 <Popconfirm 75 <Popconfirm
73 title="您确定要批量删除数据" 76 title="您确定要批量删除数据"
74 ok-text="确定" 77 ok-text="确定"
75 cancel-text="取消" 78 cancel-text="取消"
76 - @confirm="handleDeleteOrBatchDelete(null)" 79 + @confirm="handleDeleteOrBatchDelete()"
  80 + :disabled="getHasBatchDelete"
77 > 81 >
78 - <Button  
79 - style="display: none"  
80 - type="primary"  
81 - color="error"  
82 - :disabled="hasBatchDelete"  
83 - >  
84 - 批量删除  
85 - </Button> 82 + <Button type="primary" danger :disabled="getHasBatchDelete"> 批量删除 </Button>
86 </Popconfirm> 83 </Popconfirm>
87 </Authority> 84 </Authority>
88 </div> 85 </div>
@@ -120,11 +117,7 @@ @@ -120,11 +117,7 @@
120 /> 117 />
121 </template> 118 </template>
122 </BasicTable> 119 </BasicTable>
123 - <PhysicalModelModal  
124 - :record="$props.record"  
125 - @register="registerModal"  
126 - @success="handleSuccess"  
127 - /> 120 + <PhysicalModelModal :record="$props.record" @register="registerModal" @success="reload" />
128 <PhysicalModelTsl :record="$props.record" @register="registerModalTsl" /> 121 <PhysicalModelTsl :record="$props.record" @register="registerModalTsl" />
129 <SelectImport 122 <SelectImport
130 :record="$props.record" 123 :record="$props.record"
@@ -142,7 +135,6 @@ @@ -142,7 +135,6 @@
142 ModelCategoryPermission, 135 ModelCategoryPermission,
143 physicalColumn, 136 physicalColumn,
144 } from '../device.profile.data'; 137 } from '../device.profile.data';
145 - import { useBatchDelete } from '/@/hooks/web/useBatchDelete';  
146 import { Authority } from '/@/components/Authority'; 138 import { Authority } from '/@/components/Authority';
147 import PhysicalModelModal from './cpns/physical/PhysicalModelModal.vue'; 139 import PhysicalModelModal from './cpns/physical/PhysicalModelModal.vue';
148 import PhysicalModelTsl from './cpns/physical/PhysicalModelTsl.vue'; 140 import PhysicalModelTsl from './cpns/physical/PhysicalModelTsl.vue';
@@ -156,8 +148,11 @@ @@ -156,8 +148,11 @@
156 releaseModel, 148 releaseModel,
157 } from '/@/api/device/modelOfMatter'; 149 } from '/@/api/device/modelOfMatter';
158 import { OpenModelOfMatterModelParams, OpenModelMode } from './cpns/physical/types'; 150 import { OpenModelOfMatterModelParams, OpenModelMode } from './cpns/physical/types';
159 - import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';  
160 - import { ref, unref } from 'vue'; 151 + import {
  152 + ModelOfMatterItemRecordType,
  153 + ModelOfMatterParams,
  154 + } from '/@/api/device/model/modelOfMatterModel';
  155 + import { computed, ref, unref } from 'vue';
161 import { isObject } from '/@/utils/is'; 156 import { isObject } from '/@/utils/is';
162 import { useRole } from '/@/hooks/business/useRole'; 157 import { useRole } from '/@/hooks/business/useRole';
163 import { ExportModelCategory } from '/@/api/device/modelOfMatter'; 158 import { ExportModelCategory } from '/@/api/device/modelOfMatter';
@@ -177,50 +172,45 @@ @@ -177,50 +172,45 @@
177 const [registerModalTsl, { openModal: openModalTsl }] = useModal(); 172 const [registerModalTsl, { openModal: openModalTsl }] = useModal();
178 const [registerModalSelect, { openModal: openModalSelect }] = useModal(); 173 const [registerModalSelect, { openModal: openModalSelect }] = useModal();
179 174
180 - const [registerTable, { reload, setProps }] = useTable({  
181 - api: async (params: Record<'page' | 'pageSize', number>) => {  
182 - return await getModelList({  
183 - ...params,  
184 - id: props.record.id,  
185 - selectType: props.record.ifShowClass ? 'category' : undefined,  
186 - });  
187 - },  
188 - columns: props.record.ifShowClass  
189 - ? physicalColumn.filter((item) => item.dataIndex !== 'status')  
190 - : physicalColumn,  
191 - showIndexColumn: false,  
192 - clickToRowSelect: false,  
193 - showTableSetting: true,  
194 - bordered: true,  
195 - useSearchForm: true,  
196 - formConfig: {  
197 - schemas: modelOfMatterForm,  
198 - labelWidth: 120,  
199 - },  
200 - actionColumn: {  
201 - width: 200,  
202 - title: '操作',  
203 - dataIndex: 'action',  
204 - slots: { customRender: 'action' },  
205 - fixed: 'right',  
206 - },  
207 - });  
208 -  
209 - // 刷新  
210 - const handleSuccess = () => {  
211 - reload();  
212 - };  
213 - const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete(  
214 - props.record.ifShowClass && (unref(isPlatformAdmin) || unref(isSysadmin))  
215 - ? deleteModelCategory  
216 - : deleteModel,  
217 - handleSuccess,  
218 - setProps  
219 - ); 175 + const [registerTable, { reload, getSelectRowKeys, getRowSelection, clearSelectedRowKeys }] =
  176 + useTable({
  177 + api: async (params: Record<'page' | 'pageSize', number>) => {
  178 + return await getModelList({
  179 + ...params,
  180 + id: props.record.id,
  181 + selectType: props.record.ifShowClass ? 'category' : undefined,
  182 + });
  183 + },
  184 + columns: props.record.ifShowClass
  185 + ? physicalColumn.filter((item) => item.dataIndex !== 'status')
  186 + : physicalColumn,
  187 + showIndexColumn: false,
  188 + clickToRowSelect: false,
  189 + showTableSetting: true,
  190 + bordered: true,
  191 + useSearchForm: true,
  192 + rowKey: 'id',
  193 + formConfig: {
  194 + schemas: modelOfMatterForm,
  195 + labelWidth: 120,
  196 + },
  197 + actionColumn: {
  198 + width: 200,
  199 + title: '操作',
  200 + dataIndex: 'action',
  201 + slots: { customRender: 'action' },
  202 + fixed: 'right',
  203 + },
  204 + rowSelection: {
  205 + getCheckboxProps: (record: ModelOfMatterItemRecordType) => {
  206 + return {
  207 + disabled: record.status === 1,
  208 + };
  209 + },
  210 + },
  211 + });
220 212
221 - selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {  
222 - return { disabled: record.status === 1 };  
223 - }; 213 + const getHasBatchDelete = computed(() => !getRowSelection().selectedRowKeys?.length);
224 214
225 const handleViewDetail = (record: ModelOfMatterParams) => { 215 const handleViewDetail = (record: ModelOfMatterParams) => {
226 if (record) { 216 if (record) {
@@ -245,6 +235,19 @@ @@ -245,6 +235,19 @@
245 } 235 }
246 }; 236 };
247 237
  238 + const handleDeleteOrBatchDelete = async (record?: ModelOfMatterItemRecordType) => {
  239 + const deleteFn =
  240 + props.record.ifShowClass && (unref(isPlatformAdmin) || unref(isSysadmin))
  241 + ? deleteModelCategory
  242 + : deleteModel;
  243 +
  244 + const ids = record ? [record.id] : getSelectRowKeys();
  245 + await deleteFn(ids);
  246 + createMessage.success('删除成功');
  247 + clearSelectedRowKeys();
  248 + reload();
  249 + };
  250 +
248 const handleOpenTsl = () => { 251 const handleOpenTsl = () => {
249 openModalTsl(true, { 252 openModalTsl(true, {
250 isUpdate: true, 253 isUpdate: true,
@@ -30,9 +30,7 @@ @@ -30,9 +30,7 @@
30 import { SelectTypes } from 'ant-design-vue/es/select'; 30 import { SelectTypes } from 'ant-design-vue/es/select';
31 31
32 const emit = defineEmits(['register', 'emitSelect']); 32 const emit = defineEmits(['register', 'emitSelect']);
33 - const [register] = useModalInner((data) => {  
34 - console.log(data);  
35 - }); 33 + const [register] = useModalInner(() => {});
36 const heightNum = ref(80); 34 const heightNum = ref(80);
37 const visible = ref(false); 35 const visible = ref(false);
38 const selectValue = ref('LwM2M'); 36 const selectValue = ref('LwM2M');
@@ -130,14 +130,13 @@ @@ -130,14 +130,13 @@
130 telemetry: [], 130 telemetry: [],
131 }); 131 });
132 132
133 - const [registerModel, { resetFields: resetObjectListValue, getFieldsValue: getObjectListValue }] =  
134 - useForm({  
135 - labelWidth: 100,  
136 - schemas: modelSchemas,  
137 - actionColOptions: {  
138 - span: 14,  
139 - },  
140 - }); 133 + const [registerModel, { resetFields: resetObjectListValue }] = useForm({
  134 + labelWidth: 100,
  135 + schemas: modelSchemas,
  136 + actionColOptions: {
  137 + span: 14,
  138 + },
  139 + });
141 const [ 140 const [
142 registerSettings, 141 registerSettings,
143 { 142 {
@@ -152,14 +151,13 @@ @@ -152,14 +151,13 @@
152 span: 14, 151 span: 14,
153 }, 152 },
154 }); 153 });
155 - const [registerDevice, { resetFields: resetDeviceValue, getFieldsValue: getDeviceValue }] =  
156 - useForm({  
157 - labelWidth: 100,  
158 - schemas: deviceSchemas,  
159 - actionColOptions: {  
160 - span: 14,  
161 - },  
162 - }); 154 + const [registerDevice, { resetFields: resetDeviceValue }] = useForm({
  155 + labelWidth: 100,
  156 + schemas: deviceSchemas,
  157 + actionColOptions: {
  158 + span: 14,
  159 + },
  160 + });
163 const [registerModal, { openModal }] = useModal(); 161 const [registerModal, { openModal }] = useModal();
164 162
165 const handleAdd = () => { 163 const handleAdd = () => {
@@ -205,10 +203,6 @@ @@ -205,10 +203,6 @@
205 }; 203 };
206 204
207 const getFormData = async () => { 205 const getFormData = async () => {
208 - const objectListVal = getObjectListValue();  
209 - const deviceVal = getDeviceValue();  
210 - console.log('第一个tab', objectListVal);  
211 - console.log('第四个tab', deviceVal);  
212 getBootStrapFormValue(); 206 getBootStrapFormValue();
213 const settingsVal = await settingsValidate(); 207 const settingsVal = await settingsValidate();
214 if (!settingsVal) return; 208 if (!settingsVal) return;
@@ -69,7 +69,7 @@ @@ -69,7 +69,7 @@
69 if (unref(copied)) createMessage.success('复制成功!'); 69 if (unref(copied)) createMessage.success('复制成功!');
70 else createMessage.error('复制失败!'); 70 else createMessage.error('复制失败!');
71 } catch (e) { 71 } catch (e) {
72 - console.log(e); 72 + console.error(e);
73 } 73 }
74 }; 74 };
75 75
@@ -172,8 +172,7 @@ export const formSchema: FormSchema[] = [ @@ -172,8 +172,7 @@ export const formSchema: FormSchema[] = [
172 const record = await findMessageConfig(params); 172 const record = await findMessageConfig(params);
173 return record.filter((item) => item.status === 1); 173 return record.filter((item) => item.status === 1);
174 } catch (error) { 174 } catch (error) {
175 - // eslint-disable-next-line no-console  
176 - console.log(error); 175 + console.error(error);
177 return []; 176 return [];
178 } 177 }
179 }, 178 },
@@ -41,7 +41,7 @@ @@ -41,7 +41,7 @@
41 checksumAlgorithm: value.checksumAlgorithm, 41 checksumAlgorithm: value.checksumAlgorithm,
42 }); 42 });
43 } catch (error) { 43 } catch (error) {
44 - console.log(error); 44 + console.error(error);
45 if ((error as { status: number }).status) { 45 if ((error as { status: number }).status) {
46 await deleteOtaPackage(id); 46 await deleteOtaPackage(id);
47 } 47 }
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 border-color: #6b7280; 6 border-color: #6b7280;
7 } 7 }
8 8
9 -.vue-flow__handle:hover{ 9 +.vue-flow__handle:hover {
10 background-color: #000; 10 background-color: #000;
11 } 11 }
12 12
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 } 15 }
16 16
17 .vue-flow__handle-left { 17 .vue-flow__handle-left {
18 - left: -12px; 18 + left: -12px;
19 } 19 }
20 20
21 .vue-flow__background.vue-flow__container { 21 .vue-flow__background.vue-flow__container {
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 stroke-width: 4; 32 stroke-width: 4;
33 stroke: gray; 33 stroke: gray;
34 transition: stroke-width 0.3s; 34 transition: stroke-width 0.3s;
35 -} 35 +}
36 36
37 .connection-focus { 37 .connection-focus {
38 stroke-width: 6; 38 stroke-width: 6;
@@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
44 } 44 }
45 45
46 /* 连接线移入放大效果 */ 46 /* 连接线移入放大效果 */
47 -.vue-flow__edge:hover > .vue-flow__edge-path { 47 +.vue-flow__edge:hover > .vue-flow__edge-path {
48 stroke-width: 6 !important; 48 stroke-width: 6 !important;
49 } 49 }
50 50
@@ -54,18 +54,19 @@ @@ -54,18 +54,19 @@
54 } 54 }
55 55
56 .vue-flow__edge:hover .vue-flow__edge-textbg { 56 .vue-flow__edge:hover .vue-flow__edge-textbg {
57 - transform: scale(1.1) 57 + transform: scale(1.1);
58 } 58 }
59 59
60 -.vue-flow__edge:hover .vue-flow__edge-text{  
61 - transform: scale(1.1) 60 +.vue-flow__edge:hover .vue-flow__edge-text {
  61 + transform: scale(1.1);
62 } 62 }
63 63
64 /* selection 选择框 */ 64 /* selection 选择框 */
65 -.vue-flow__nodesselection-rect, .vue-flow__selection{ 65 +.vue-flow__nodesselection-rect,
  66 +.vue-flow__selection {
66 border-width: 3px; 67 border-width: 3px;
67 } 68 }
68 69
69 -.vue-flow__nodesselection-rect { 70 +.vue-flow__nodesselection-rect {
70 pointer-events: none; 71 pointer-events: none;
71 } 72 }
@@ -236,7 +236,7 @@ @@ -236,7 +236,7 @@
236 // 设置输出值 236 // 设置输出值
237 outputEditor.value.set(result); 237 outputEditor.value.set(result);
238 } catch (e) { 238 } catch (e) {
239 - console.log(e); 239 + console.error(e);
240 const { createMessage } = useMessage(); 240 const { createMessage } = useMessage();
241 createMessage.error(e.toString()); 241 createMessage.error(e.toString());
242 } 242 }
@@ -85,9 +85,7 @@ @@ -85,9 +85,7 @@
85 /^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$/; 85 /^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$/;
86 if (reg.test(formData.mobile)) { 86 if (reg.test(formData.mobile)) {
87 const sendRes = await passwordResetCode(formData.mobile); 87 const sendRes = await passwordResetCode(formData.mobile);
88 - console.log(sendRes);  
89 if (sendRes === '') { 88 if (sendRes === '') {
90 - console.log('发送成功了');  
91 return true; 89 return true;
92 } 90 }
93 return false; 91 return false;
@@ -99,6 +99,5 @@ @@ -99,6 +99,5 @@
99 async function handleRegister() { 99 async function handleRegister() {
100 const data = await validForm(); 100 const data = await validForm();
101 if (!data) return; 101 if (!data) return;
102 - console.log(data);  
103 } 102 }
104 </script> 103 </script>
@@ -27,7 +27,6 @@ @@ -27,7 +27,6 @@
27 onMounted(() => { 27 onMounted(() => {
28 // 记录当前的UserId 28 // 记录当前的UserId
29 userId.value = userStore.getUserInfo?.userId; 29 userId.value = userStore.getUserInfo?.userId;
30 - console.log('Mounted', userStore.getUserInfo);  
31 }); 30 });
32 31
33 onBeforeUnmount(() => { 32 onBeforeUnmount(() => {
@@ -69,8 +69,8 @@ export function useFormRules(formData?: Recordable) { @@ -69,8 +69,8 @@ export function useFormRules(formData?: Recordable) {
69 const mobileFormRule = unref(getMobileFormRule); 69 const mobileFormRule = unref(getMobileFormRule);
70 70
71 const mobileRule = { 71 const mobileRule = {
72 - sms: smsFormRule,  
73 - mobile: mobileFormRule, 72 + code: smsFormRule,
  73 + phoneNumber: mobileFormRule,
74 }; 74 };
75 switch (unref(currentState)) { 75 switch (unref(currentState)) {
76 // register form rules 76 // register form rules
@@ -14,7 +14,6 @@ @@ -14,7 +14,6 @@
14 Reflect.deleteProperty(params, 'path'); 14 Reflect.deleteProperty(params, 'path');
15 15
16 const _path = Array.isArray(path) ? path.join('/') : path; 16 const _path = Array.isArray(path) ? path.join('/') : path;
17 - console.log(unref(currentRoute));  
18 if (_redirect_type === 'name') { 17 if (_redirect_type === 'name') {
19 replace({ 18 replace({
20 name: _path, 19 name: _path,
@@ -138,7 +138,6 @@ @@ -138,7 +138,6 @@
138 } 138 }
139 if (newFieldValue.codeTown == undefined) { 139 if (newFieldValue.codeTown == undefined) {
140 validateArray.push('prov'); 140 validateArray.push('prov');
141 - console.log(validateArray);  
142 } else { 141 } else {
143 const findExistIndex1 = validateArray.findIndex((o) => o == 'prov'); 142 const findExistIndex1 = validateArray.findIndex((o) => o == 'prov');
144 if (findExistIndex1 !== -1) { 143 if (findExistIndex1 !== -1) {
@@ -5,7 +5,8 @@ @@ -5,7 +5,8 @@
5 <Tabs.TabPane 5 <Tabs.TabPane
6 v-if=" 6 v-if="
7 isWhereAdmin == 'TENANT_ADMIN' || 7 isWhereAdmin == 'TENANT_ADMIN' ||
8 - (isWhereAdmin == 'SYS_ADMIN' || isWhereAdmin == 'CUSTOMER_USER') 8 + isWhereAdmin == 'SYS_ADMIN' ||
  9 + isWhereAdmin == 'CUSTOMER_USER'
9 " 10 "
10 key="企业信息" 11 key="企业信息"
11 tab="企业信息" 12 tab="企业信息"
@@ -264,7 +264,6 @@ @@ -264,7 +264,6 @@
264 setProps({ 264 setProps({
265 loading: true, 265 loading: true,
266 }); 266 });
267 - console.log(sendTime.value);  
268 let startTime = null; 267 let startTime = null;
269 let endTime = null; 268 let endTime = null;
270 if (sendTime.value.length > 0) { 269 if (sendTime.value.length > 0) {
@@ -49,6 +49,7 @@ @@ -49,6 +49,7 @@
49 font-size: 16px; 49 font-size: 16px;
50 font-weight: 500; 50 font-weight: 500;
51 } 51 }
  52 +
52 :deep(.vben-collapse-container__header) { 53 :deep(.vben-collapse-container__header) {
53 border-bottom: none; 54 border-bottom: none;
54 } 55 }
@@ -134,7 +134,7 @@ @@ -134,7 +134,7 @@
134 copyTransFun(data as any); 134 copyTransFun(data as any);
135 return data; 135 return data;
136 } catch (error) { 136 } catch (error) {
137 - console.log(error); 137 + console.error(error);
138 return []; 138 return [];
139 } 139 }
140 }, 140 },
@@ -77,7 +77,7 @@ @@ -77,7 +77,7 @@
77 copyTransFun(data as any); 77 copyTransFun(data as any);
78 return data; 78 return data;
79 } catch (error) { 79 } catch (error) {
80 - console.log(error); 80 + console.error(error);
81 return []; 81 return [];
82 } 82 }
83 }, 83 },
@@ -10,7 +10,8 @@ @@ -10,7 +10,8 @@
10 10
11 const alert = { 11 const alert = {
12 [PackagesCategoryEnum.MAP]: [ 12 [PackagesCategoryEnum.MAP]: [
13 - '地图组件,需绑定两个数据源,且数据源为同一设备。第一数据源为经度,第二数据源为纬度,否则地图组件不能正常显示。', 13 + '1、绑定数据源为结构体时,可以自行选择结构体里的属性作为经纬度',
  14 + '2、绑定数据源为非结构体时,第一数据源为经度,第二数据源为纬度,且数据源为同一设备,并同时上报。否则地图组件不能正常显示。',
14 ], 15 ],
15 }; 16 };
16 17
@@ -34,14 +34,6 @@ @@ -34,14 +34,6 @@
34 const { unit, fontColor, showDeviceName } = item.componentInfo || {}; 34 const { unit, fontColor, showDeviceName } = item.componentInfo || {};
35 const { deviceName, deviceRename, attribute, attributeRename, deviceId, attributeName } = 35 const { deviceName, deviceRename, attribute, attributeRename, deviceId, attributeName } =
36 item; 36 item;
37 - // return {  
38 - // unit: unit ?? persetUnit,  
39 - // fontColor: fontColor ?? persetFontColor,  
40 - // showDeviceName: showDeviceName ?? persetShowDeviceName,  
41 - // attribute,  
42 - // deviceName,  
43 - // deviceRename,  
44 - // };  
45 return { 37 return {
46 unit: unit ?? presetUnit, 38 unit: unit ?? presetUnit,
47 fontColor: fontColor ?? presetFontColor, 39 fontColor: fontColor ?? presetFontColor,
@@ -58,7 +50,6 @@ @@ -58,7 +50,6 @@
58 }); 50 });
59 51
60 const getOffset = (length: number, index: number) => { 52 const getOffset = (length: number, index: number) => {
61 - // try {  
62 const offsetList = ref<any>([]); 53 const offsetList = ref<any>([]);
63 switch (length) { 54 switch (length) {
64 case 1: 55 case 1:
@@ -147,7 +138,6 @@ @@ -147,7 +138,6 @@
147 break; 138 break;
148 } 139 }
149 return unref(offsetList); 140 return unref(offsetList);
150 - // } catch {}  
151 }; 141 };
152 142
153 const series = ref( 143 const series = ref(
@@ -263,7 +253,6 @@ @@ -263,7 +253,6 @@
263 series.value.forEach((item) => { 253 series.value.forEach((item) => {
264 if (item.id === deviceId && item.attribute === attribute && value) { 254 if (item.id === deviceId && item.attribute === attribute && value) {
265 item.value = getNumberValue(value); 255 item.value = getNumberValue(value);
266 - // time.value = timespan;  
267 } 256 }
268 }); 257 });
269 }); 258 });
@@ -62,7 +62,6 @@ @@ -62,7 +62,6 @@
62 const options = (): EChartsOption => { 62 const options = (): EChartsOption => {
63 const { unit, fontColor, pointerColor, maxNumber, valueSize } = unref(getDesign); 63 const { unit, fontColor, pointerColor, maxNumber, valueSize } = unref(getDesign);
64 64
65 - // getStageColor(gradientInfo);  
66 return { 65 return {
67 series: [ 66 series: [
68 { 67 {
@@ -103,14 +102,6 @@ @@ -103,14 +102,6 @@
103 color: pointerColor, 102 color: pointerColor,
104 }, 103 },
105 }, 104 },
106 - // anchor: {  
107 - // show: true,  
108 - // showAbove: true,  
109 - // size: 10,  
110 - // itemStyle: {  
111 - // borderWidth: 4,  
112 - // },  
113 - // },  
114 title: { 105 title: {
115 show: false, 106 show: false,
116 }, 107 },
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 import { BasicModal, useModalInner } from '/@/components/Modal'; 3 import { BasicModal, useModalInner } from '/@/components/Modal';
4 import { formSchema, getHistorySearchParams, SchemaFiled } from './history.config'; 4 import { formSchema, getHistorySearchParams, SchemaFiled } from './history.config';
5 import { HistoryModalOkEmitParams } from './type'; 5 import { HistoryModalOkEmitParams } from './type';
6 - import { ref } from 'vue'; 6 + import { ref, unref } from 'vue';
7 import { getAllDeviceByOrg } from '/@/api/dataBoard'; 7 import { getAllDeviceByOrg } from '/@/api/dataBoard';
8 import { getDeviceHistoryInfo } from '/@/api/alarm/position'; 8 import { getDeviceHistoryInfo } from '/@/api/alarm/position';
9 import { DataSource } from '/@/views/visual/palette/types'; 9 import { DataSource } from '/@/views/visual/palette/types';
@@ -19,58 +19,154 @@ @@ -19,58 +19,154 @@
19 ], 19 ],
20 }); 20 });
21 21
22 - const [registerModal, { closeModal }] = useModalInner(async (dataSource: DataSource[]) => {  
23 - try {  
24 - dataSource = cloneDeep(dataSource);  
25 - if (dataSource.length < 2) return;  
26 - dataSource = dataSource.splice(0, 2);  
27 - const deviceRecord = dataSource?.at(0) || ({} as DataSource);  
28 - if (!deviceRecord.organizationId) return;  
29 - const deviceList = await getAllDeviceByOrg(  
30 - deviceRecord.organizationId,  
31 - deviceRecord.deviceProfileId  
32 - );  
33 - const options = deviceList  
34 - .filter((item) => item.tbDeviceId === deviceRecord.deviceId)  
35 - .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId }));  
36 -  
37 - const attKey = dataSource.map((item) => ({  
38 - ...item,  
39 - label: item.attribute,  
40 - value: item.attribute,  
41 - }));  
42 - updateSchema([  
43 - {  
44 - field: SchemaFiled.DEVICE_ID,  
45 - componentProps: {  
46 - options,  
47 - }, 22 + const loading = ref(false);
  23 + const getDesign = ref();
  24 +
  25 + const getTwoMap = async (dataSource) => {
  26 + if (dataSource.length < 2) return;
  27 + dataSource = dataSource.splice(0, 2);
  28 + const deviceRecord = dataSource?.at(0) || ({} as DataSource);
  29 +
  30 + if (!deviceRecord.organizationId) return;
  31 + const deviceList = await getAllDeviceByOrg(
  32 + deviceRecord.organizationId,
  33 + deviceRecord.deviceProfileId
  34 + );
  35 + const options = deviceList
  36 + .filter((item) => item.tbDeviceId === deviceRecord.deviceId)
  37 + .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId }));
  38 +
  39 + const attKey = dataSource.map((item) => ({
  40 + ...item,
  41 + label: item.attribute,
  42 + value: item.attribute,
  43 + }));
  44 +
  45 + updateSchemaMap(options, attKey, deviceRecord);
  46 + };
  47 +
  48 + const getOneMap = async (dataSource) => {
  49 + const deviceRecord = dataSource?.[0];
  50 + if (!deviceRecord.organizationId) return;
  51 + const deviceList = await getAllDeviceByOrg(
  52 + deviceRecord.organizationId,
  53 + deviceRecord.deviceProfileId
  54 + );
  55 + const options = deviceList
  56 + .filter((item) => item.tbDeviceId === deviceRecord.deviceId)
  57 + .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId }));
  58 +
  59 + const attKey = dataSource?.map((item) => ({
  60 + ...item,
  61 + label: item.attributeName,
  62 + value: item.attribute,
  63 + }));
  64 + updateSchemaMap(options, attKey, deviceRecord);
  65 + };
  66 +
  67 + const updateSchemaMap = (options, attKey, deviceRecord) => {
  68 + updateSchema([
  69 + {
  70 + field: SchemaFiled.DEVICE_ID,
  71 + componentProps: {
  72 + options,
48 }, 73 },
49 - {  
50 - field: SchemaFiled.KEYS,  
51 - component: 'Select',  
52 - defaultValue: attKey.map((item) => item.value),  
53 - componentProps: {  
54 - options: attKey,  
55 - mode: 'multiple',  
56 - disabled: true,  
57 - }, 74 + },
  75 + {
  76 + field: SchemaFiled.KEYS,
  77 + component: 'Select',
  78 + defaultValue: attKey.map((item) => item.value),
  79 + componentProps: {
  80 + options: attKey,
  81 + mode: 'multiple',
  82 + disabled: true,
58 }, 83 },
59 - ]); 84 + },
  85 + ]);
60 86
61 - setFieldsValue({  
62 - [SchemaFiled.DEVICE_ID]: deviceRecord.deviceId,  
63 - [SchemaFiled.KEYS]: attKey.map((item) => item.value),  
64 - }); 87 + setFieldsValue({
  88 + [SchemaFiled.DEVICE_ID]: deviceRecord.deviceId,
  89 + [SchemaFiled.KEYS]: attKey.map((item) => item.value),
  90 + });
  91 + };
  92 +
  93 + const [registerModal, { closeModal }] = useModalInner(async (dataSource: DataSource[]) => {
  94 + try {
  95 + getDesign.value = dataSource;
  96 + dataSource = cloneDeep(dataSource);
  97 + //判断选择是不是结构体
  98 + if (dataSource.length == 1 && dataSource?.[0]?.lal) {
  99 + getOneMap(dataSource);
  100 + return;
  101 + }
  102 + getTwoMap(dataSource);
65 } catch (error) { 103 } catch (error) {
66 throw error; 104 throw error;
67 } 105 }
68 }); 106 });
69 107
  108 + const getMultipleDataSource = async (res) => {
  109 + let timespanList = Object.keys(res).reduce((prev, next) => {
  110 + const ts = res[next].map((item) => item.ts);
  111 + return [...prev, ...ts];
  112 + }, [] as number[]);
  113 + timespanList = [...new Set(timespanList)];
  114 +
  115 + const track: Record<'lng' | 'lat', number>[] = [];
  116 + const keys = Object.keys(res);
  117 +
  118 + for (const ts of timespanList) {
  119 + const list: { ts: number; value: number }[] = [];
  120 + for (const key of keys) {
  121 + const record = res[key].find((item) => ts === item.ts);
  122 + if (!validEffective(record?.value)) {
  123 + continue;
  124 + }
  125 + list.push(record as any);
  126 + }
  127 +
  128 + if (list.length === 2 && list.every(Boolean)) {
  129 + const lng = list.at(0)?.value;
  130 + const lat = list.at(1)?.value;
  131 + if (lng && lat) track.push({ lng, lat });
  132 + }
  133 + }
  134 + return track;
  135 + };
  136 +
  137 + // 单数据源选择结构体
  138 + const getSingleDataSource = async (res) => {
  139 + const [keys] = Object.keys(res);
  140 + const track: Record<'lng' | 'lat', number>[] = [];
  141 + const dataSource = res[keys]?.map((item) => {
  142 + return {
  143 + value: item.value ? JSON.parse(item.value) : {},
  144 + };
  145 + });
  146 + const list: { value: number }[] = [];
  147 + dataSource?.forEach((item) => {
  148 + if (
  149 + //判断结构体得值是不是数字
  150 + Object.values(item.value).every((item1) => {
  151 + return validEffective(item1 as any);
  152 + })
  153 + ) {
  154 + list.push(item.value);
  155 + }
  156 + });
  157 + const { latitude, longitude } = unref(getDesign)?.[0]; //获取选择的经纬度选项
  158 +
  159 + list.forEach((item) => {
  160 + const lng = item[longitude];
  161 + const lat = item[latitude];
  162 + if (lng && lat) track.push({ lng, lat });
  163 + });
  164 + return track;
  165 + };
  166 +
70 const validEffective = (value = '') => { 167 const validEffective = (value = '') => {
71 return !!(value && !isNaN(value as unknown as number)); 168 return !!(value && !isNaN(value as unknown as number));
72 }; 169 };
73 - const loading = ref(false);  
74 const handleOk = async () => { 170 const handleOk = async () => {
75 try { 171 try {
76 await validate(); 172 await validate();
@@ -84,33 +180,9 @@ @@ -84,33 +180,9 @@
84 ...value, 180 ...value,
85 [SchemaFiled.KEYS]: value[SchemaFiled.KEYS].join(','), 181 [SchemaFiled.KEYS]: value[SchemaFiled.KEYS].join(','),
86 }); 182 });
  183 + const ifSingle = unref(getDesign)?.length === 1 && unref(getDesign)?.[0]?.lal;
87 184
88 - let timespanList = Object.keys(res).reduce((prev, next) => {  
89 - const ts = res[next].map((item) => item.ts);  
90 - return [...prev, ...ts];  
91 - }, [] as number[]);  
92 - timespanList = [...new Set(timespanList)];  
93 -  
94 - const track: Record<'lng' | 'lat', number>[] = [];  
95 - const keys = Object.keys(res);  
96 -  
97 - for (const ts of timespanList) {  
98 - const list: { ts: number; value: number }[] = [];  
99 - for (const key of keys) {  
100 - const record = res[key].find((item) => ts === item.ts);  
101 - if (!validEffective(record?.value)) {  
102 - continue;  
103 - }  
104 - list.push(record as any);  
105 - }  
106 -  
107 - if (list.length === 2 && list.every(Boolean)) {  
108 - const lng = list.at(0)?.value;  
109 - const lat = list.at(1)?.value;  
110 - if (lng && lat) track.push({ lng, lat });  
111 - }  
112 - }  
113 - 185 + const track = ifSingle ? await getSingleDataSource(res) : await getMultipleDataSource(res);
114 emit('ok', { track, value } as HistoryModalOkEmitParams); 186 emit('ok', { track, value } as HistoryModalOkEmitParams);
115 closeModal(); 187 closeModal();
116 } catch (error) { 188 } catch (error) {
@@ -24,6 +24,14 @@ @@ -24,6 +24,14 @@
24 return props.config.option.dataSource?.at(0)?.deviceId; 24 return props.config.option.dataSource?.at(0)?.deviceId;
25 }); 25 });
26 26
  27 + const getDesign = computed(() => {
  28 + const { option } = props.config;
  29 + const { dataSource } = option || {};
  30 + return {
  31 + dataSource: dataSource,
  32 + };
  33 + });
  34 +
27 /** 35 /**
28 * @description 经度key 36 * @description 经度key
29 */ 37 */
@@ -42,7 +50,7 @@ @@ -42,7 +50,7 @@
42 return !!(value && !isNaN(value as unknown as number)); 50 return !!(value && !isNaN(value as unknown as number));
43 }; 51 };
44 52
45 - const updateFn: MultipleDataFetchUpdateFn = (message, deviceId) => { 53 + const getTwoMap = (message, deviceId) => {
46 if (unref(getDeviceId) !== deviceId) return; 54 if (unref(getDeviceId) !== deviceId) return;
47 55
48 const { data = {} } = message; 56 const { data = {} } = message;
@@ -51,7 +59,7 @@ @@ -51,7 +59,7 @@
51 59
52 const lngData = bindMessage[unref(getLngKey)] || []; 60 const lngData = bindMessage[unref(getLngKey)] || [];
53 const [lngLatest] = lngData; 61 const [lngLatest] = lngData;
54 - const [, lng] = lngLatest; 62 + const [, lng] = lngLatest || [];
55 63
56 const latData = bindMessage[unref(getLatKey)] || []; 64 const latData = bindMessage[unref(getLatKey)] || [];
57 const [latLatest] = latData; 65 const [latLatest] = latData;
@@ -62,6 +70,34 @@ @@ -62,6 +70,34 @@
62 } 70 }
63 }; 71 };
64 72
  73 + const getOneMap = (message, deviceId) => {
  74 + if (unref(getDeviceId) !== deviceId) return;
  75 +
  76 + const { longitude, latitude, attribute } = unref(getDesign)?.dataSource?.[0] || {};
  77 + const { data } = message || {};
  78 + const bindMessage = data[deviceId];
  79 + const [, values] = attribute && bindMessage?.[attribute][0];
  80 +
  81 + const mapValues = values ? JSON.parse(values) : {};
  82 + const lng = longitude && mapValues[longitude];
  83 + const lat = latitude && mapValues[latitude];
  84 +
  85 + if (validEffective(lng) && validEffective(lat)) {
  86 + drawLine({ lng: Number(lng), lat: Number(lat) });
  87 + }
  88 + };
  89 +
  90 + const updateFn: MultipleDataFetchUpdateFn = (message, deviceId) => {
  91 + const { lal } = unref(getDesign)?.dataSource?.[0] || {};
  92 + // 属性选择结构体类型时
  93 + if (lal && unref(getDesign)?.dataSource?.length == 1) {
  94 + getOneMap(message, deviceId);
  95 + return;
  96 + }
  97 + // 选择两个属性时
  98 + getTwoMap(message, deviceId);
  99 + };
  100 +
65 useMultipleDataFetch(props, updateFn); 101 useMultipleDataFetch(props, updateFn);
66 102
67 const { drawLine } = useMapTrackPlayBack(mapInstance); 103 const { drawLine } = useMapTrackPlayBack(mapInstance);
@@ -100,11 +136,3 @@ @@ -100,11 +136,3 @@
100 <div v-show="!loading" ref="wrapRef" :id="wrapId" class="w-full h-full no-drag"> </div> 136 <div v-show="!loading" ref="wrapRef" :id="wrapId" class="w-full h-full no-drag"> </div>
101 </main> 137 </main>
102 </template> 138 </template>
103 -  
104 -<style lang="less" scoped>  
105 - // .map-spin-wrapper {  
106 - // :deep(.ant-spin-container) {  
107 - // @apply justify-center items-center p-2 w-full h-full;  
108 - // }  
109 - // }  
110 -</style>  
@@ -247,7 +247,6 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -247,7 +247,6 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
247 }); 247 });
248 }, 248 },
249 placeholder: '请选择设备', 249 placeholder: '请选择设备',
250 - getPopupContainer: () => document.body,  
251 ...createPickerSearch(), 250 ...createPickerSearch(),
252 }; 251 };
253 }, 252 },
@@ -382,11 +381,18 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -382,11 +381,18 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
382 return []; 381 return [];
383 }, 382 },
384 placeholder: '请选择属性', 383 placeholder: '请选择属性',
385 - getPopupContainer: () => document.body,  
386 onChange(value: string, option: Record<'label' | 'value' | any, string>) { 384 onChange(value: string, option: Record<'label' | 'value' | any, string>) {
  385 + const { detail }: any = option || {};
387 setFieldsValue({ 386 setFieldsValue({
388 [DataSourceField.ATTRIBUTE_NAME]: value ? option.label : null, 387 [DataSourceField.ATTRIBUTE_NAME]: value ? option.label : null,
389 [DataSourceField.EXTENSION_DESC]: value ? JSON.stringify(option.extensionDesc) : '', 388 [DataSourceField.EXTENSION_DESC]: value ? JSON.stringify(option.extensionDesc) : '',
  389 + // 地图组件结构体
  390 + lal:
  391 + category === 'MAP' && value && detail?.dataType.type === 'STRUCT'
  392 + ? JSON.stringify(detail?.dataType.specs)
  393 + : null,
  394 + latitude: null,
  395 + longitude: null,
390 }); 396 });
391 }, 397 },
392 ...createPickerSearch(), 398 ...createPickerSearch(),
@@ -394,6 +400,46 @@ export const commonDataSourceSchemas = (): FormSchema[] => { @@ -394,6 +400,46 @@ export const commonDataSourceSchemas = (): FormSchema[] => {
394 }, 400 },
395 }, 401 },
396 { 402 {
  403 + field: 'lal',
  404 + label: '经纬度存储的值',
  405 + component: 'Input',
  406 + show: false,
  407 + },
  408 + {
  409 + field: 'longitude',
  410 + label: '经度',
  411 + colProps: { span: 8 },
  412 + component: 'Select',
  413 + required: true,
  414 + ifShow: ({ model }) => category === 'MAP' && model.lal,
  415 + componentProps({ formModel }) {
  416 + const { lal } = formModel || {};
  417 + return {
  418 + placeholder: '请选择经度',
  419 + options: lal
  420 + ? JSON.parse(lal)?.map((item) => ({ label: item.functionName, value: item.identifier }))
  421 + : [],
  422 + };
  423 + },
  424 + },
  425 + {
  426 + field: 'latitude',
  427 + label: '纬度',
  428 + colProps: { span: 8 },
  429 + required: true,
  430 + component: 'Select',
  431 + ifShow: ({ model }) => category === 'MAP' && model.lal,
  432 + componentProps({ formModel }) {
  433 + const { lal } = formModel || {};
  434 + return {
  435 + placeholder: '请选择纬度',
  436 + options: lal
  437 + ? JSON.parse(lal)?.map((item) => ({ label: item.functionName, value: item.identifier }))
  438 + : [],
  439 + };
  440 + },
  441 + },
  442 + {
397 field: DataSourceField.EXTENSION_DESC, 443 field: DataSourceField.EXTENSION_DESC,
398 component: 'Input', 444 component: 'Input',
399 show: false, 445 show: false,
1 -import { ReceiveTsSubCmdsGroupMessageType } from '../index.type'; 1 +import { ReceiveTsSubCmdsGroupMessageType } from './socket/useSocket.type';
2 2
3 export const useReceiveMessage = () => { 3 export const useReceiveMessage = () => {
4 const forEachGroupMessage = ( 4 const forEachGroupMessage = (
1 -import cloneDeep from 'lodash-es/cloneDeep';  
2 -import { ComponentConfig } from '.';  
3 -import {  
4 - ConfigType,  
5 - CreateComponentType,  
6 - PublicComponentOptions,  
7 - PublicPresetOptions,  
8 -} from '/@/views/visual/packages/index.type';  
9 -import { PublicConfigClass, componentInitConfig } from '/@/views/visual/packages/publicConfig';  
10 -import { ComponentConfigFieldEnum } from '/@/views/visual/packages/enum';  
11 -  
12 -export const option: PublicPresetOptions = {  
13 - [ComponentConfigFieldEnum.FONT_COLOR]: '#',  
14 - [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false,  
15 -};  
16 -  
17 -export default class Config extends PublicConfigClass implements CreateComponentType {  
18 - public key: string = ComponentConfig.key;  
19 -  
20 - public attr = { ...componentInitConfig };  
21 -  
22 - public componentConfig: ConfigType = cloneDeep(ComponentConfig);  
23 -  
24 - public persetOption = cloneDeep(option);  
25 -  
26 - public option: PublicComponentOptions;  
27 -  
28 - constructor(option: PublicComponentOptions) {  
29 - super();  
30 - this.option = { ...option };  
31 - }  
32 -}  
1 -<script lang="ts" setup>  
2 - import { ComponentConfigFieldEnum } from '/@/views/visual/packages/enum';  
3 - import { useForm, BasicForm } from '/@/components/Form';  
4 - import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type';  
5 -  
6 - const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({  
7 - schemas: [  
8 - {  
9 - field: ComponentConfigFieldEnum.FONT_COLOR,  
10 - label: '数值字体颜色',  
11 - component: 'ColorPicker',  
12 - changeEvent: 'update:value',  
13 - componentProps: {  
14 - defaultValue: '#FD7347',  
15 - },  
16 - },  
17 - {  
18 - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME,  
19 - label: '显示设备名称',  
20 - component: 'Checkbox',  
21 - },  
22 - ],  
23 - showActionButtonGroup: false,  
24 - labelWidth: 120,  
25 - baseColProps: {  
26 - span: 12,  
27 - },  
28 - });  
29 -  
30 - const getFormValues = () => {  
31 - return getFieldsValue();  
32 - };  
33 -  
34 - const setFormValues = (data: Recordable) => {  
35 - return setFieldsValue(data);  
36 - };  
37 -  
38 - defineExpose({  
39 - getFormValues,  
40 - setFormValues,  
41 - resetFormValues: resetFields,  
42 - } as PublicFormInstaceType);  
43 -</script>  
44 -  
45 -<template>  
46 - <BasicForm @register="register" />  
47 -</template>  
1 -<script lang="ts" setup>  
2 - import { CreateComponentType } from '/@/views/visual/packages/index.type';  
3 - import { BasicForm, useForm } from '/@/components/Form';  
4 - import {  
5 - PublicComponentValueType,  
6 - PublicFormInstaceType,  
7 - } from '/@/views/visual/dataSourceBindPanel/index.type';  
8 - import { commonDataSourceSchemas } from '../config/common.config';  
9 -  
10 - defineProps<{  
11 - values: PublicComponentValueType;  
12 - componentConfig: CreateComponentType;  
13 - }>();  
14 -  
15 - const [register, { getFieldsValue, setFieldsValue, validate, resetFields }] = useForm({  
16 - labelWidth: 0,  
17 - showActionButtonGroup: false,  
18 - layout: 'horizontal',  
19 - labelCol: { span: 0 },  
20 - schemas: commonDataSourceSchemas(),  
21 - });  
22 -  
23 - const getFormValues = () => {  
24 - return getFieldsValue();  
25 - };  
26 -  
27 - const setFormValues = (record: Recordable) => {  
28 - return setFieldsValue(record);  
29 - };  
30 -  
31 - defineExpose({  
32 - getFormValues,  
33 - setFormValues,  
34 - validate,  
35 - resetFormValues: resetFields,  
36 - } as PublicFormInstaceType);  
37 -</script>  
38 -  
39 -<template>  
40 - <BasicForm @register="register" />  
41 -</template>  
1 -import { useComponentKeys } from '/@/views/visual/packages/hook/useComponentKeys';  
2 -import { ConfigType, PackagesCategoryEnum } from '/@/views/visual/packages/index.type';  
3 -  
4 -const componentKeys = useComponentKeys('componentKeys');  
5 -  
6 -export const ComponentConfig: ConfigType = {  
7 - ...componentKeys,  
8 - title: '组件名',  
9 - package: PackagesCategoryEnum.TEXT,  
10 -};  
1 -<script lang="ts" setup>  
2 - import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type';  
3 - import { option } from './config';  
4 - import { useDataFetch } from '../hook/socket/useSocket';  
5 - import { DataFetchUpdateFn } from '../hook/socket/useSocket.type';  
6 -  
7 - const props = defineProps<{  
8 - config: ComponentPropsConfigType<typeof option>;  
9 - }>();  
10 -  
11 - const updateFn: DataFetchUpdateFn = (_message) => {};  
12 -  
13 - useDataFetch(props, updateFn);  
14 -</script>  
15 -  
16 -<template>  
17 - <main class="w-full h-full flex flex-col justify-center items-center"> </main>  
18 -</template>  
@@ -150,7 +150,6 @@ @@ -150,7 +150,6 @@
150 getIsSharePage, 150 getIsSharePage,
151 (value) => { 151 (value) => {
152 if (value) { 152 if (value) {
153 - console.log(unref(getDarkMode));  
154 const root = document.querySelector('#app'); 153 const root = document.querySelector('#app');
155 (root as HTMLDivElement).style.backgroundColor = 154 (root as HTMLDivElement).style.backgroundColor =
156 unref(getDarkMode) === ThemeEnum.LIGHT ? '#F5F5F5' : '#1b1b1b'; 155 unref(getDarkMode) === ThemeEnum.LIGHT ? '#F5F5F5' : '#1b1b1b';
@@ -29,6 +29,9 @@ export interface DataSource { @@ -29,6 +29,9 @@ export interface DataSource {
29 customCommand: CustomCommand; 29 customCommand: CustomCommand;
30 videoConfig?: VideoConfigType; 30 videoConfig?: VideoConfigType;
31 [key: string]: any; 31 [key: string]: any;
  32 + lal?: string;
  33 + latitude?: string | number;
  34 + longitude?: string | number;
32 } 35 }
33 36
34 export interface ExtraDataSource extends DataSource, PublicComponentOptions { 37 export interface ExtraDataSource extends DataSource, PublicComponentOptions {
@@ -32,7 +32,6 @@ app.ws.use( @@ -32,7 +32,6 @@ app.ws.use(
32 }); 32 });
33 ctx.websocket.send(data); 33 ctx.websocket.send(data);
34 } 34 }
35 - console.log(message);  
36 }); 35 });
37 }) 36 })
38 ); 37 );
@@ -59,5 +58,6 @@ app.use(router.allowedMethods()); @@ -59,5 +58,6 @@ app.use(router.allowedMethods());
59 app.use(koaStatic(path.join(__dirname))); 58 app.use(koaStatic(path.join(__dirname)));
60 59
61 app.listen(PORT, () => { 60 app.listen(PORT, () => {
  61 + // eslint-disable-next-line no-console
62 console.log(`Application started successfully: http://localhost:${PORT}`); 62 console.log(`Application started successfully: http://localhost:${PORT}`);
63 }); 63 });