Commit 79bfa2d0783b6f6e6ef5de76ee708f024b1cdeff

Authored by fengtao
2 parents ccbaf072 d77a7571

Merge branch 'main' into ft_local_dev

  1 +import { DeviceProfileModel } from '../../device/model/deviceModel';
1 2 import { HistoryData } from './model';
2 3 import { defHttp } from '/@/utils/http/axios';
3 4
4 5 // 获取设备配置
5 6 export const getDeviceProfile = () => {
6   - return defHttp.get({
  7 + return defHttp.get<DeviceProfileModel[]>({
7 8 url: '/device_profile/me/list',
8 9 });
9 10 };
... ...
... ... @@ -166,9 +166,10 @@ export const getShareBoardComponentInfo = (params: { boardId: string; tenantId:
166 166 * @param params
167 167 * @returns
168 168 */
169   -export const getAllDeviceByOrg = (params: string) => {
  169 +export const getAllDeviceByOrg = (organizationId: string, deviceProfileId?: string) => {
170 170 return defHttp.get<MasterDeviceList[]>({
171   - url: `${DeviceUrl.GET_DEVICE}/${params}`,
  171 + url: `${DeviceUrl.GET_DEVICE}/${organizationId}`,
  172 + params: { deviceProfileId },
172 173 });
173 174 };
174 175
... ...
... ... @@ -78,6 +78,7 @@ export interface DataSource {
78 78 gatewayDevice: boolean;
79 79 componentInfo: ComponentInfo;
80 80 deviceName: string;
  81 + deviceProfileId: string;
81 82
82 83 // front usage
83 84 uuid?: string;
... ...
... ... @@ -25,6 +25,7 @@ export interface StructJSON {
25 25 identifier?: string;
26 26 remark?: string;
27 27 dataType?: DataType;
  28 + serviceCommand?: string;
28 29 }
29 30
30 31 export interface FunctionJson {
... ...
... ... @@ -65,7 +65,7 @@ export const releaseModel = (deviceProfileId: string) => {
65 65
66 66 export const getModelServices = (params: { deviceProfileId: string }) => {
67 67 const { deviceProfileId } = params;
68   - return defHttp.get({
  68 + return defHttp.get<ModelOfMatterParams[]>({
69 69 url: `${ModelOfMatter.GET_MODEL_SERVICE}/${deviceProfileId}`,
70 70 });
71 71 };
... ...
... ... @@ -56,7 +56,7 @@
56 56
57 57 const handleBeforeUpload = (file: File) => {
58 58 if (file.size > props.maxSize) {
59   - createMessage.warning(`文件大小超过${Math.floor(props.maxSize / 1024)}mb`);
  59 + createMessage.warning(`文件大小超过${Math.floor(props.maxSize / 1024 / 1024)}mb`);
60 60 return false;
61 61 }
62 62 handleUpload(file);
... ...
1   -import { h } from 'vue';
2 1 import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
3 2 import { findDictItemByCode } from '/@/api/system/dict';
4 3 import { FormSchema } from '/@/components/Table';
... ... @@ -22,7 +21,6 @@ const validateValueRange = (_rule, value: Record<'min' | 'max', number>, _callba
22 21 };
23 22
24 23 const validateJSON = (_rule, value: ModelOfMatterParams[], _callback) => {
25   - console.log('validate json', value);
26 24 if (value.length) {
27 25 return Promise.resolve();
28 26 }
... ... @@ -141,10 +139,15 @@ export const formSchemas: FormSchema[] = [
141 139 const { setFieldsValue } = formActionType;
142 140 return {
143 141 placeholder: '请选择单位',
144   - api: findDictItemByCode,
  142 + api: async (params) => {
  143 + const list = await findDictItemByCode(params);
  144 + list.map((item) => (item.itemText = `${item.itemText} / ${item.itemValue}`));
  145 + return list;
  146 + },
145 147 params: {
146 148 dictCode: 'attribute_unit',
147 149 },
  150 + labelInValue: true,
148 151 labelField: 'itemText',
149 152 valueField: 'itemValue',
150 153 onChange(_, record: Record<'label' | 'value', string>) {
... ... @@ -165,14 +168,6 @@ export const formSchemas: FormSchema[] = [
165 168 ifShow: ({ values }) =>
166 169 values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_INT ||
167 170 values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_DOUBLE,
168   - renderComponentContent: () => {
169   - return {
170   - option: (params: Record<'label' | 'value', string>) => {
171   - const { label, value } = params;
172   - return h('span', `${label} / ${value}`);
173   - },
174   - };
175   - },
176 171 },
177 172 {
178 173 field: FormField.BOOL_CLOSE,
... ...
... ... @@ -34,7 +34,6 @@
34 34 let { width = 300, height = 150 } = unref(getOptions);
35 35 width = isNumber(width) ? (`${width}px` as unknown as number) : width;
36 36 height = isNumber(height) ? (`${height}px` as unknown as number) : height;
37   - console.log({ getOptions });
38 37 return { width, height } as CSSProperties;
39 38 });
40 39
... ...
  1 +import { onUnmounted, ref } from 'vue';
  2 +
  3 +interface ScriptOptions {
  4 + src: string;
  5 +}
  6 +
  7 +export function useAsyncScript(opts: ScriptOptions) {
  8 + const isLoading = ref(false);
  9 + const error = ref(false);
  10 + const success = ref(false);
  11 + let script: HTMLScriptElement;
  12 +
  13 + const toPromise = () => {
  14 + return new Promise((resolve, reject) => {
  15 + script = document.createElement('script');
  16 + script.type = 'text/javascript';
  17 + script.onload = function () {
  18 + isLoading.value = false;
  19 + success.value = true;
  20 + error.value = false;
  21 + resolve('');
  22 + };
  23 +
  24 + script.onerror = function (err) {
  25 + isLoading.value = false;
  26 + success.value = false;
  27 + error.value = true;
  28 + reject(err);
  29 + };
  30 +
  31 + script.src = opts.src;
  32 + document.head.appendChild(script);
  33 + });
  34 + };
  35 +
  36 + onUnmounted(() => {
  37 + script && script.remove();
  38 + });
  39 +
  40 + return {
  41 + isLoading,
  42 + error,
  43 + success,
  44 + toPromise,
  45 + };
  46 +}
... ...
... ... @@ -62,6 +62,7 @@ export function useECharts(
62 62 }
63 63 nextTick(() => {
64 64 useTimeoutFn(() => {
  65 + console.log(chartInstance);
65 66 if (!chartInstance) {
66 67 initCharts(getDarkMode.value as 'default');
67 68
... ... @@ -70,6 +71,7 @@ export function useECharts(
70 71 clear && chartInstance?.clear();
71 72
72 73 chartInstance?.setOption(unref(getOptions));
  74 + chartInstance = null;
73 75 }, 30);
74 76 });
75 77 }
... ...
... ... @@ -120,7 +120,6 @@
120 120 const index = unref(cameraList).findIndex((item) => item.id === record.id);
121 121 if (~index) unref(cameraList)[index].isTransform = true;
122 122 }
123   - console.log(unref(cameraList));
124 123 }
125 124 };
126 125
... ...
... ... @@ -65,7 +65,6 @@
65 65 setDrawerProps({ confirmLoading: true });
66 66 let saveMessage = '添加成功';
67 67 let updateMessage = '修改成功';
68   - console.log(values);
69 68 await saveOrUpdateConfigurationCenter(values, unref(isUpdate));
70 69 closeDrawer();
71 70 emit('success');
... ...
... ... @@ -29,7 +29,7 @@
29 29 import { cloneDeep } from 'lodash';
30 30 import { usePermission } from '/@/hooks/web/usePermission';
31 31
32   - const listColumn = ref(4);
  32 + const listColumn = ref(5);
33 33
34 34 const { createMessage } = useMessage();
35 35
... ... @@ -209,7 +209,7 @@
209 209 <template #cover>
210 210 <div class="h-full w-full !flex justify-center items-center text-center">
211 211 <img
212   - class="w-36 h-36"
  212 + class="w-full h-36"
213 213 alt="example"
214 214 :src="item.thumbnail || configurationSrc"
215 215 @click="handlePreview(item)"
... ...
... ... @@ -57,7 +57,7 @@
57 57 </div>
58 58 <div v-if="deviceDetail?.deviceInfo?.address" class="mt-4">
59 59 <p>设备位置</p>
60   - <div ref="wrapRef" style="height: 550px; width: 100%"></div>
  60 + <div ref="mapWrapRef" style="height: 550px; width: 100%"></div>
61 61 </div>
62 62 </div>
63 63 </template>
... ... @@ -65,7 +65,7 @@
65 65 import { defineComponent, ref, unref, nextTick } from 'vue';
66 66 import { Image, Tooltip } from 'ant-design-vue';
67 67 import { descSchema } from '../../config/detail.config';
68   - import { useScript } from '/@/hooks/web/useScript';
  68 + import { useAsyncScript } from '/@/hooks/web/useAsyncScript';
69 69 import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
70 70 import { useMessage } from '/@/hooks/web/useMessage';
71 71 import { BAI_DU_MAP_URL } from '/@/utils/fnUtils';
... ... @@ -77,6 +77,7 @@
77 77 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
78 78
79 79 import wz from '/@/assets/images/wz.png';
  80 + import { useAsyncQueue } from '../../../localtion/useAsyncQueue';
80 81 export default defineComponent({
81 82 components: {
82 83 Image,
... ... @@ -101,13 +102,30 @@
101 102 });
102 103
103 104 // 地图
104   - const wrapRef = ref<HTMLDivElement | null>(null);
105   - const { toPromise } = useScript({ src: BAI_DU_MAP_URL });
  105 + const mapWrapRef = ref<HTMLDivElement>();
106 106
107   - async function initMap(longitude, latitude, address) {
108   - await toPromise();
  107 + const { executeFlag, setTask } = useAsyncQueue();
  108 + const { toPromise } = useAsyncScript({ src: BAI_DU_MAP_URL });
  109 +
  110 + async function initMap(longitude: number, latitude: number, address: string) {
  111 + if (!(window as any).BMap) {
  112 + setTask(() => markerMap(longitude, latitude, address));
  113 + let interval: Nullable<NodeJS.Timer> = setInterval(() => {
  114 + if ((window as any).BMap) {
  115 + executeFlag.value = true;
  116 + clearInterval(interval!);
  117 + interval = null;
  118 + }
  119 + }, 300);
  120 + await toPromise();
  121 + return;
  122 + }
  123 + markerMap(longitude, latitude, address);
  124 + }
  125 +
  126 + async function markerMap(longitude: number, latitude: number, address: string) {
109 127 await nextTick();
110   - const wrapEl = unref(wrapRef);
  128 + const wrapEl = unref(mapWrapRef);
111 129 const BMap = (window as any).BMap;
112 130 if (!wrapEl) return;
113 131 const map = new BMap.Map(wrapEl);
... ... @@ -132,6 +150,7 @@
132 150 map.enableScrollWheelZoom(true);
133 151 map.addOverlay(marker);
134 152 }
  153 +
135 154 const { createMessage } = useMessage();
136 155 const { clipboardRef } = useCopyToClipboard();
137 156 const copyTbDeviceId = () => {
... ... @@ -166,7 +185,7 @@
166 185 const remoteConnectiondGateway = () => {};
167 186
168 187 return {
169   - wrapRef,
  188 + mapWrapRef,
170 189 copyTbDeviceId,
171 190 copyDeviceToken,
172 191 initMap,
... ...
... ... @@ -6,6 +6,7 @@ import { HistoryData } from '/@/api/alarm/position/model';
6 6 import { getDeviceAttributes } from '/@/api/dataBoard';
7 7 import { DeviceAttributeRecord } from '/@/api/dataBoard/model';
8 8 import { dateUtil } from '/@/utils/dateUtil';
  9 +import { isArray } from '/@/utils/is';
9 10 import { QueryWay } from '/@/views/report/config/config.data';
10 11 import { SchemaFiled } from '/@/views/visual/board/detail/config/historyTrend.config';
11 12 import { DEFAULT_DATE_FORMAT } from '/@/views/visual/board/detail/config/util';
... ... @@ -24,7 +25,8 @@ export function useHistoryData() {
24 25 const getDeviceAttribute = async (record: DeviceOption) => {
25 26 try {
26 27 const { deviceProfileId } = record;
27   - deviceAttrs.value = (await getDeviceAttributes({ deviceProfileId })) || [];
  28 + const list = (await getDeviceAttributes({ deviceProfileId })) || [];
  29 + deviceAttrs.value = isArray(list) ? list : [];
28 30 } catch (error) {
29 31 throw error;
30 32 }
... ...
... ... @@ -22,6 +22,7 @@ export function useAsyncQueue() {
22 22 if (executeFlag.value) {
23 23 queue.forEach((item) => item());
24 24 executeFlag.value = false;
  25 + clearTask();
25 26 }
26 27 });
27 28
... ...
... ... @@ -33,7 +33,9 @@
33 33 </Button>
34 34 </Authority>
35 35 <Button type="primary" @click="handleOpenTsl"> 物模型TSL </Button>
36   - <Button v-if="isShowBtn" type="primary" @click="handleImportModel">导入物模型</Button>
  36 + <Button v-if="false && isShowBtn" type="primary" @click="handleImportModel"
  37 + >导入物模型</Button
  38 + >
37 39 </div>
38 40 <div class="flex gap-2">
39 41 <Authority :value="ModelOfMatterPermission.RELEASE">
... ...
... ... @@ -25,7 +25,7 @@
25 25 >
26 26 <TabPane :key="FunctionType.PROPERTIES" tab="属性" />
27 27 <TabPane :key="FunctionType.SERVICE" :disabled="isTCPGatewaySubDevice" tab="服务" />
28   - <TabPane :key="FunctionType.EVENTS" tab="事件" :disabled="isTCPGatewaySubDevice" />
  28 + <!-- <TabPane :key="FunctionType.EVENTS" tab="事件" :disabled=" isTCPGatewaySubDevice" /> -->
29 29 </Tabs>
30 30 <Attribute v-if="activeKey === FunctionType.PROPERTIES" ref="AttrRef" />
31 31 <Service
... ...
... ... @@ -11,7 +11,7 @@
11 11 <Tabs type="card" v-model:active-key="activeKey" @change="handleSwitchTsl">
12 12 <Tabs.TabPane :key="FunctionType.PROPERTIES" tab="属性" />
13 13 <Tabs.TabPane :key="FunctionType.SERVICE" tab="服务" />
14   - <Tabs.TabPane :key="FunctionType.EVENTS" tab="事件" />
  14 + <!-- <Tabs.TabPane :key="FunctionType.EVENTS" tab="事件" /> -->
15 15 <template #tabBarExtraContent>
16 16 <Button @click="handlePremitter">
17 17 <template #icon>
... ...
... ... @@ -27,7 +27,7 @@
27 27 const _value = (event.target as HTMLInputElement).checked;
28 28 emit('update:value', _value);
29 29 emit('change', _value);
30   - sendCommand(props.value?.slaveDeviceId || props.value?.deviceId, _value);
  30 + sendCommand(props.value!, _value);
31 31 };
32 32 </script>
33 33
... ...
... ... @@ -32,8 +32,7 @@
32 32
33 33 const { sendCommand } = useSendCommand();
34 34 const handleChange = (value: boolean) => {
35   - console.log(props.value);
36   - sendCommand(props.value.slaveDeviceId! || props.value.deviceId!, value);
  35 + sendCommand(props.value, value);
37 36 };
38 37
39 38 watchEffect(() => {
... ...
... ... @@ -22,7 +22,7 @@
22 22 const _value = (event.target as HTMLInputElement).checked;
23 23 emit('update:value', _value);
24 24 emit('change', _value);
25   - sendCommand(props.value?.slaveDeviceId || props.value?.deviceId, _value);
  25 + sendCommand(props.value!, _value);
26 26 };
27 27
28 28 const getRadio = computed(() => {
... ...
... ... @@ -13,6 +13,7 @@ export interface ControlComponentValue {
13 13 deviceId?: string;
14 14 fontColor?: string;
15 15 slaveDeviceId?: string;
  16 + deviceProfileId?: string;
16 17 }
17 18
18 19 export const ControlComponentDefaultConfig: ControlComponentValue = {
... ... @@ -31,6 +32,7 @@ export const transformControlConfig = (
31 32 ...dataSourceRecord.componentInfo,
32 33 attribute: dataSourceRecord.attribute,
33 34 attributeRename: dataSourceRecord.attributeRename,
  35 + deviceProfileId: dataSourceRecord.deviceProfileId,
34 36 deviceId: dataSourceRecord.deviceId,
35 37 slaveDeviceId: dataSourceRecord.slaveDeviceId,
36 38 } as ControlComponentValue,
... ...
  1 +import { ControlComponentValue } from './control.config';
  2 +import { getDeviceProfile } from '/@/api/alarm/position';
1 3 import { sendCommandOneway } from '/@/api/dataBoard';
  4 +import { getModelServices } from '/@/api/device/modelOfMatter';
2 5 import { useMessage } from '/@/hooks/web/useMessage';
  6 +import { isString } from '/@/utils/is';
3 7
4 8 const { createMessage } = useMessage();
5 9 export function useSendCommand() {
6   - const sendCommand = async (deviceId: string, value: any) => {
  10 + const sendCommand = async (record: ControlComponentValue, value: any) => {
  11 + const { deviceId, deviceProfileId, attribute } = record;
7 12 if (!deviceId) return;
8 13 try {
  14 + const list = await getDeviceProfile();
  15 + const deviceProfile = list.find((item) => item.id === deviceProfileId);
  16 + if (!deviceProfile) return;
  17 + let params: string | Recordable = {
  18 + [attribute!]: Number(value),
  19 + };
  20 + if (deviceProfile.transportType === 'TCP') {
  21 + const serviceList = await getModelServices({ deviceProfileId: deviceProfileId! });
  22 + const record = serviceList.find((item) => item.identifier === attribute);
  23 + const sendCommand = record?.functionJson.inputData?.at(0)?.serviceCommand || '';
  24 + params = isString(sendCommand) ? sendCommand : JSON.stringify(sendCommand);
  25 + }
9 26 await sendCommandOneway({
10 27 deviceId,
11 28 value: {
12   - params: Number(value),
  29 + params: params,
13 30 persistent: true,
14 31 additionalInfo: {
15 32 cmdType: 'API',
... ...
... ... @@ -5,9 +5,9 @@
5 5 SettingOutlined,
6 6 SwapOutlined,
7 7 } from '@ant-design/icons-vue';
8   - import { Tooltip, Button } from 'ant-design-vue';
  8 + import { Tooltip, Button, Alert } from 'ant-design-vue';
9 9 import { FormActionType, useForm } from '/@/components/Form';
10   - import { basicSchema, DataSourceField } from '../config/basicConfiguration';
  10 + import { basicSchema, DataSourceField, isMapComponent } from '../config/basicConfiguration';
11 11 import BasicForm from '/@/components/Form/src/BasicForm.vue';
12 12 import { ref, shallowReactive, unref, nextTick, watch, computed, onMounted } from 'vue';
13 13 import VisualOptionsModal from './VisualOptionsModal.vue';
... ... @@ -22,6 +22,7 @@
22 22 import { useSortable } from '/@/hooks/web/useSortable';
23 23 import { cloneDeep } from 'lodash-es';
24 24 import { frontComponentMap } from '../../components/help';
  25 + import { isControlComponent } from '../config/basicConfiguration';
25 26
26 27 type DataSourceFormEL = { [key: string]: Nullable<FormActionType> };
27 28
... ... @@ -250,6 +251,14 @@
250 251 inited = true;
251 252 }
252 253
  254 + const isControlCmp = computed(() => {
  255 + return isControlComponent(props.frontId as FrontComponent);
  256 + });
  257 +
  258 + const isMapCmp = computed(() => {
  259 + return isMapComponent(props.frontId as FrontComponent);
  260 + });
  261 +
253 262 onMounted(() => handleSort());
254 263
255 264 defineExpose({
... ... @@ -264,7 +273,25 @@
264 273 <div class="w-3/4">
265 274 <BasicForm @register="basicRegister" class="w-full" />
266 275 </div>
  276 + <Alert type="info" show-icon v-if="isControlCmp">
  277 + <template #description>
  278 + <div>
  279 + 控制组件数据源为TCP产品,则其控制命令下发为TCP产品 物模型=>服务,且不具备状态显示功能.
  280 + </div>
  281 + <div>
  282 + 控制组件数据源为非TCP产品,则其控制命令下发为产品 物模型=>属性,且具备状态显示功能.
  283 + </div>
  284 + </template>
  285 + </Alert>
  286 + <Alert type="info" show-icon v-if="isMapCmp">
  287 + <template #description>
  288 + <div>
  289 + 地图组件,需绑定两个数据源,且数据源为同一设备。第一数据源为经度,第二数据源为维度,否则地图组件不能正常显示。
  290 + </div>
  291 + </template>
  292 + </Alert>
267 293 <h3 class="w-24 flex-shrink-0 text-right pr-2 my-4">选择数据源</h3>
  294 +
268 295 <section ref="formListEl">
269 296 <div v-for="item in dataSource" :data-id="item.id" :key="item.id" class="flex bg-light-50">
270 297 <div class="w-24 text-right flex right justify-end"> 选择设备 </div>
... ...
... ... @@ -4,6 +4,8 @@ import { FormSchema } from '/@/components/Form';
4 4 import { copyTransFun } from '/@/utils/fnUtils';
5 5 import { DeviceAttributeParams, MasterDeviceList } from '/@/api/dataBoard/model';
6 6 import { FrontComponent } from '../../const/const';
  7 +import { getDeviceProfile } from '/@/api/alarm/position';
  8 +import { getModelServices } from '/@/api/device/modelOfMatter';
7 9
8 10 export enum BasicConfigField {
9 11 NAME = 'name',
... ... @@ -18,13 +20,22 @@ const getDeviceAttribute = async (params: DeviceAttributeParams) => {
18 20 return [];
19 21 };
20 22
  23 +const getDeviceService = async (deviceProfileId: string) => {
  24 + try {
  25 + const data = await getModelServices({ deviceProfileId });
  26 + if (data)
  27 + return data.map((item) => ({ ...item, label: item.functionName, value: item.identifier }));
  28 + } catch (error) {}
  29 + return [];
  30 +};
  31 +
21 32 export enum DataSourceField {
22 33 IS_GATEWAY_DEVICE = 'gatewayDevice',
  34 + TRANSPORT_TYPE = 'transportType',
23 35 ORIGINATION_ID = 'organizationId',
24 36 DEVICE_ID = 'deviceId',
25 37 SLAVE_DEVICE_ID = 'slaveDeviceId',
26 38 DEVICE_PROFILE_ID = 'deviceProfileId',
27   - SLAVE_DEVICE_PROFILE_ID = 'slaveDeviceProfileId',
28 39 ATTRIBUTE = 'attribute',
29 40 ATTRIBUTE_RENAME = 'attributeRename',
30 41 DEVICE_NAME = 'deviceName',
... ... @@ -33,16 +44,25 @@ export enum DataSourceField {
33 44 LATITUDE_ATTRIBUTE = 'latitudeAttribute',
34 45 }
35 46
36   -const isControlComponent = (frontId: FrontComponent) => {
  47 +export const isControlComponent = (frontId: FrontComponent) => {
37 48 const list = [
38 49 FrontComponent.CONTROL_COMPONENT_SLIDING_SWITCH,
39 50 FrontComponent.CONTROL_COMPONENT_SWITCH_WITH_ICON,
40 51 FrontComponent.CONTROL_COMPONENT_TOGGLE_SWITCH,
41 52 ];
42   - if (list.includes(frontId)) {
43   - return true;
44   - }
45   - return false;
  53 + return list.includes(frontId);
  54 +};
  55 +
  56 +export const isMapComponent = (frontId: FrontComponent) => {
  57 + const list = [
  58 + FrontComponent.MAP_COMPONENT_TRACK_HISTORY,
  59 + FrontComponent.MAP_COMPONENT_TRACK_REAL,
  60 + ];
  61 + return list.includes(frontId);
  62 +};
  63 +
  64 +const isTcpProfile = (transportType: string) => {
  65 + return transportType === 'TCP';
46 66 };
47 67
48 68 export const basicSchema: FormSchema[] = [
... ... @@ -81,6 +101,45 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => {
81 101 show: false,
82 102 },
83 103 {
  104 + field: DataSourceField.TRANSPORT_TYPE,
  105 + component: 'Input',
  106 + label: '设备配置类型',
  107 + show: false,
  108 + },
  109 + {
  110 + field: DataSourceField.DEVICE_PROFILE_ID,
  111 + component: 'ApiSelect',
  112 + label: '产品',
  113 + colProps: { span: 8 },
  114 + rules: [{ required: true, message: '产品为必填项' }],
  115 + componentProps: ({ formActionType, formModel }) => {
  116 + const { setFieldsValue } = formActionType;
  117 + const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
  118 + return {
  119 + api: async () => {
  120 + const list = await getDeviceProfile();
  121 + if (deviceProfileId) {
  122 + const record = list.find((item) => item.id === deviceProfileId);
  123 + setFieldsValue({ [DataSourceField.TRANSPORT_TYPE]: record?.transportType });
  124 + }
  125 + return list;
  126 + },
  127 + labelField: 'name',
  128 + valueField: 'id',
  129 + onChange: (_, option: Record<'transportType', string>) => {
  130 + console.log(option);
  131 + setFieldsValue({
  132 + [DataSourceField.DEVICE_ID]: null,
  133 + [DataSourceField.ATTRIBUTE]: null,
  134 + [DataSourceField.SLAVE_DEVICE_ID]: null,
  135 + [DataSourceField.IS_GATEWAY_DEVICE]: false,
  136 + [DataSourceField.TRANSPORT_TYPE]: option.transportType,
  137 + });
  138 + },
  139 + };
  140 + },
  141 + },
  142 + {
84 143 field: DataSourceField.ORIGINATION_ID,
85 144 component: 'ApiTreeSelect',
86 145 label: '组织',
... ... @@ -101,8 +160,6 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => {
101 160 [DataSourceField.ATTRIBUTE]: null,
102 161 [DataSourceField.SLAVE_DEVICE_ID]: null,
103 162 [DataSourceField.IS_GATEWAY_DEVICE]: false,
104   - [DataSourceField.DEVICE_PROFILE_ID]: null,
105   - [DataSourceField.SLAVE_DEVICE_PROFILE_ID]: null,
106 163 });
107 164 },
108 165 getPopupContainer: () => document.body,
... ... @@ -124,16 +181,13 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => {
124 181 componentProps({ formModel, formActionType }) {
125 182 const { setFieldsValue } = formActionType;
126 183 const organizationId = formModel[DataSourceField.ORIGINATION_ID];
127   - const deviceId = formModel[DataSourceField.DEVICE_ID];
  184 + const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
  185 +
128 186 return {
129 187 api: async () => {
130 188 if (organizationId) {
131 189 try {
132   - const data = await getAllDeviceByOrg(organizationId);
133   - if (deviceId) {
134   - const record = data.find((item) => item.id === deviceId);
135   - setFieldsValue({ [DataSourceField.DEVICE_PROFILE_ID]: record?.deviceProfileId });
136   - }
  190 + const data = await getAllDeviceByOrg(organizationId, deviceProfileId);
137 191 if (data)
138 192 return data.map((item) => ({
139 193 ...item,
... ... @@ -150,9 +204,7 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => {
150 204 setFieldsValue({
151 205 [DataSourceField.ATTRIBUTE]: null,
152 206 [DataSourceField.IS_GATEWAY_DEVICE]: record?.deviceType === 'GATEWAY',
153   - [DataSourceField.DEVICE_PROFILE_ID]: record?.deviceProfileId,
154 207 [DataSourceField.SLAVE_DEVICE_ID]: null,
155   - [DataSourceField.SLAVE_DEVICE_PROFILE_ID]: null,
156 208 [DataSourceField.DEVICE_NAME]: record?.label,
157 209 });
158 210 },
... ... @@ -162,19 +214,18 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => {
162 214 },
163 215 },
164 216 {
165   - field: DataSourceField.SLAVE_DEVICE_PROFILE_ID,
166   - component: 'Input',
167   - label: '',
168   - show: false,
169   - },
170   - {
171 217 field: DataSourceField.SLAVE_DEVICE_ID,
172 218 label: '网关子设备',
173 219 component: 'ApiSelect',
174 220 colProps: { span: 8 },
175 221 rules: [{ required: true, message: '网关子设备为必填项' }],
  222 + show: false,
176 223 ifShow({ model }) {
177   - return model[DataSourceField.IS_GATEWAY_DEVICE];
  224 + const transportType = model[DataSourceField.TRANSPORT_TYPE];
  225 + return (
  226 + !(isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)) &&
  227 + model[DataSourceField.IS_GATEWAY_DEVICE]
  228 + );
178 229 },
179 230 dynamicRules({ model }) {
180 231 return [
... ... @@ -186,16 +237,12 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => {
186 237 const organizationId = formModel[DataSourceField.ORIGINATION_ID];
187 238 const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE];
188 239 const deviceId = formModel[DataSourceField.DEVICE_ID];
189   - const slaveDeviceId = formModel[DataSourceField.SLAVE_DEVICE_ID];
  240 +
190 241 return {
191 242 api: async () => {
192 243 if (organizationId && isGatewayDevice) {
193 244 try {
194 245 const data = await getGatewaySlaveDevice({ organizationId, masterId: deviceId });
195   - if (slaveDeviceId) {
196   - const record = data.find((item) => item.id === slaveDeviceId);
197   - setFieldsValue({ [DataSourceField.DEVICE_PROFILE_ID]: record?.deviceProfileId });
198   - }
199 246 if (data)
200 247 return data.map((item) => ({
201 248 ...item,
... ... @@ -210,7 +257,6 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => {
210 257 onChange(_value, record: MasterDeviceList) {
211 258 setFieldsValue({
212 259 [DataSourceField.ATTRIBUTE]: null,
213   - [DataSourceField.SLAVE_DEVICE_PROFILE_ID]: record.deviceProfileId,
214 260 [DataSourceField.DEVICE_NAME]: record?.label,
215 261 });
216 262 },
... ... @@ -226,33 +272,30 @@ export const dataSourceSchema = (frontId?: FrontComponent): FormSchema[] => {
226 272 colProps: { span: 8 },
227 273 rules: [{ required: true, message: '属性为必填项' }],
228 274 componentProps({ formModel }) {
229   - const isGatewayDevice = formModel[DataSourceField.IS_GATEWAY_DEVICE];
230   - const deviceId = formModel[DataSourceField.DEVICE_ID];
231 275 const deviceProfileId = formModel[DataSourceField.DEVICE_PROFILE_ID];
232   - const slaveDeviceId = formModel[DataSourceField.SLAVE_DEVICE_ID];
233   - const slaveDeviceProfileId = formModel[DataSourceField.SLAVE_DEVICE_PROFILE_ID];
  276 + const transportType = formModel[DataSourceField.TRANSPORT_TYPE];
234 277
235 278 return {
236 279 api: async () => {
237   - if (deviceId) {
238   - try {
239   - if (isGatewayDevice && slaveDeviceId && slaveDeviceProfileId) {
240   - return await getDeviceAttribute({
241   - deviceProfileId: slaveDeviceProfileId,
242   - dataType: isControlComponent(frontId!) ? 'BOOL' : undefined,
243   - });
244   - }
245   - if (!isGatewayDevice && deviceProfileId) {
246   - return await getDeviceAttribute({
247   - deviceProfileId,
248   - dataType: isControlComponent(frontId!) ? 'BOOL' : undefined,
249   - });
250   - }
251   - } catch (error) {}
252   - }
  280 + try {
  281 + if (isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)) {
  282 + return await getDeviceService(deviceProfileId);
  283 + }
  284 +
  285 + if (deviceProfileId) {
  286 + return await getDeviceAttribute({
  287 + deviceProfileId,
  288 + dataType: isControlComponent(frontId!) ? 'BOOL' : undefined,
  289 + });
  290 + }
  291 + } catch (error) {}
  292 +
253 293 return [];
254 294 },
255   - placeholder: '请选择属性',
  295 + placeholder:
  296 + isControlComponent(frontId as FrontComponent) && isTcpProfile(transportType)
  297 + ? '请选择服务'
  298 + : '请选择属性',
256 299 getPopupContainer: () => document.body,
257 300 };
258 301 },
... ...