Commit 21b223f679f9c6cfb9ffe9dcfc3c40b1cec96c23

Authored by fengtao
2 parents 7e974951 d994b48d

Merge branch 'main' into ft_local_dev

... ... @@ -14,9 +14,9 @@ VITE_PUBLIC_PATH = /
14 14 # VITE_PROXY = [["/api","http://101.133.234.90:8080/api"]]
15 15 # 线上测试环境
16 16 # VITE_PROXY = [["/api","http://localhost:8080/api"],["/thingskit-drawio","http://localhost:3000/"]]
17   -VITE_PROXY = [["/api","http://222.180.200.114:48080/api"],["/thingskit-drawio","http://localhost:3000/"]]
  17 +# VITE_PROXY = [["/api","http://222.180.200.114:48080/api"],["/thingskit-drawio","http://localhost:3000/"]]
18 18 # VITE_PROXY = [["/api","http://121.37.251.8:8080/api"],["/thingskit-drawio","http://localhost:3000/"]]
19   -# VITE_PROXY = [["/api","http://192.168.10.136:8080/api"],["/thingskit-drawio","http://192.168.10.136:8080/api"]]
  19 +VITE_PROXY = [["/api","http://192.168.10.103:8080/api"],["/thingskit-drawio","http://192.168.10.136:8080/api"]]
20 20
21 21 # 实时数据的ws地址
22 22 # VITE_WEB_SOCKET = ws://localhost:8080/api/ws/plugins/telemetry?token=
... ...
1 1 import { BasicPageParams } from '../model/baseModel';
2 2 import { GetModelTslParams, ModelOfMatterParams } from './model/modelOfMatterModel';
3 3 import { defHttp } from '/@/utils/http/axios';
  4 +import { FunctionType } from '/@/views/device/profiles/step/cpns/physical/cpns/config';
4 5
5 6 enum ModelOfMatter {
6 7 CREATE = '/things_model',
... ... @@ -8,9 +9,16 @@ enum ModelOfMatter {
8 9 DELETE = '/things_model',
9 10 TSL = '/things_model',
10 11 LIST = '/things_model/page',
  12 + RELEASE = '/things_model',
11 13 }
12 14
13   -export const getModelList = (params: BasicPageParams) => {
  15 +export const getModelList = (
  16 + params: BasicPageParams & {
  17 + deviceProfileId: string;
  18 + functionTyp?: FunctionType;
  19 + nameOrIdentifier?: string;
  20 + }
  21 +) => {
14 22 return defHttp.get({
15 23 url: `${ModelOfMatter.LIST}`,
16 24 params,
... ... @@ -46,3 +54,9 @@ export const deleteModel = (params: string[]) => {
46 54 },
47 55 });
48 56 };
  57 +
  58 +export const releaseModel = (deviceProfileId: string) => {
  59 + return defHttp.put({
  60 + url: `${ModelOfMatter.RELEASE}/${deviceProfileId}`,
  61 + });
  62 +};
... ...
  1 +import { cloneDeep } from 'lodash-es';
1 2 import { DateTypeEnum } from './config';
2 3 import { StructFormValue } from './type';
3 4 import { DataType, ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel';
  5 +import { isArray } from '/@/utils/is';
4 6
5 7 export function transfromToStructJSON(value: StructFormValue): StructJSON {
6 8 const {
... ... @@ -16,9 +18,9 @@ export function transfromToStructJSON(value: StructFormValue): StructJSON {
16 18 identifier,
17 19 remark,
18 20 specs,
19   - assessMode,
  21 + accessMode,
20 22 } = value;
21   - const basic = { functionName, identifier, remark, assessMode };
  23 + const basic = { functionName, identifier, remark, accessMode };
22 24 let dataType = {} as unknown as DataType;
23 25
24 26 switch (type) {
... ... @@ -62,3 +64,27 @@ export function transfromToStructJSON(value: StructFormValue): StructJSON {
62 64 }
63 65 return { ...basic, dataType };
64 66 }
  67 +
  68 +export const excludeIdInStructJSON = (struct: DataType) => {
  69 + const _value = cloneDeep(struct);
  70 + const { specs } = _value;
  71 + const list = [specs];
  72 +
  73 + while (list.length) {
  74 + for (const item of list) {
  75 + if (isArray(item)) {
  76 + (item as StructJSON[]).forEach((temp) => {
  77 + if (temp.dataType?.specs) {
  78 + list.push(temp.dataType.specs);
  79 + }
  80 + Reflect.deleteProperty(temp, 'id');
  81 + });
  82 + } else {
  83 + Reflect.deleteProperty(item as Recordable, 'id');
  84 + }
  85 + list.shift();
  86 + }
  87 + }
  88 +
  89 + return _value;
  90 +};
... ...
... ... @@ -286,7 +286,7 @@
286 286 }
287 287
288 288 .split-screen-mode:deep(.ant-spin-container) {
289   - height: 100%;
  289 + height: 100% !important;
290 290 }
291 291
292 292 .video-container {
... ... @@ -321,4 +321,8 @@
321 321 width: 100%;
322 322 height: 100%;
323 323 }
  324 +
  325 + .split-mode-lis:deep(.ant-spin-container:fullscreen) {
  326 + height: 100% !important;
  327 + }
324 328 </style>
... ...
... ... @@ -27,6 +27,7 @@
27 27 import { getBoundingClientRect } from '/@/utils/domUtils';
28 28 import configurationSrc from '/@/assets/icons/configuration.svg';
29 29 import { cloneDeep } from 'lodash';
  30 + import { usePermission } from '/@/hooks/web/usePermission';
30 31
31 32 const listColumn = ref(4);
32 33
... ... @@ -112,8 +113,9 @@
112 113 const { VITE_GLOB_CONFIGURATION } = import.meta.env;
113 114 const isDev = isDevMode();
114 115
  116 + const { hasPermission } = usePermission();
115 117 const handlePreview = (record: ConfigurationCenterItemsModal) => {
116   - console.log(record);
  118 + if (!hasPermission('api:yt:configuration:center:get_configuration_info:get')) return;
117 119 window.open(
118 120 `${VITE_GLOB_CONFIGURATION}/${isDev ? '?dev=1&' : '?'}configurationId=${
119 121 record!.id
... ... @@ -206,7 +208,12 @@
206 208 <Card hoverable>
207 209 <template #cover>
208 210 <div class="h-full w-full !flex justify-center items-center text-center">
209   - <img class="w-36 h-36" alt="example" :src="item.thumbnail || configurationSrc" />
  211 + <img
  212 + class="w-36 h-36"
  213 + alt="example"
  214 + :src="item.thumbnail || configurationSrc"
  215 + @click="handlePreview(item)"
  216 + />
210 217 </div>
211 218 </template>
212 219 <template class="ant-card-actions" #actions>
... ... @@ -215,18 +222,18 @@
215 222 <EyeOutlined key="setting" @click="handlePreview(item)" />
216 223 </Tooltip>
217 224 </Authority>
218   - <Authority value="api:yt:configuration:center:update">
219   - <Tooltip title="编辑">
220   - <EditOutlined key="edit" @click="handleCreateOrUpdate(item)" />
  225 + <Authority value="api:yt:configuration:center:get_configuration_info:get">
  226 + <Tooltip title="设计">
  227 + <EditOutlined key="edit" @click="handleDesign(item)" />
221 228 </Tooltip>
222 229 </Authority>
223 230 <Dropdown
224 231 :dropMenuList="[
225 232 {
226 233 text: '设计',
227   - auth: 'api:yt:configuration:center:get_configuration_info:get',
  234 + auth: 'api:yt:configuration:center:update',
228 235 icon: 'clarity:note-edit-line',
229   - onClick: handleDesign.bind(null, item),
  236 + onClick: handleCreateOrUpdate.bind(null, item),
230 237 },
231 238 {
232 239 text: '删除',
... ...
1 1 <template>
2   - <BasicDrawer v-bind="$attrs" title="产品详情" @register="register" width="60%">
3   - <Tabs :animated="true" v-model:activeKey="activeKey" @change="handlePanelChange">
4   - <TabPane key="product" tab="产品">
  2 + <BasicDrawer v-bind="$attrs" title="产品详情" @register="register" width="60%" destroy-on-close>
  3 + <Tabs v-model:activeKey="activeKey" @change="handlePanelChange">
  4 + <Tabs.TabPane key="product" tab="产品">
5 5 <div class="relative">
6 6 <DeviceConfigurationStep :ifShowBtn="false" ref="DevConStRef" />
7 7 <div class="absolute w-full h-full top-0 cursor-not-allowed"></div>
8 8 </div>
9   - </TabPane>
10   - <TabPane key="transport" tab="传输配置">
  9 + </Tabs.TabPane>
  10 + <Tabs.TabPane key="transport" tab="传输配置">
11 11 <div class="relative">
12 12 <TransportConfigurationStep :ifShowBtn="false" ref="TransConStRef" />
13 13 <div class="absolute w-full h-full top-0 cursor-not-allowed"></div>
14 14 </div>
15   - </TabPane>
16   - <TabPane key="modelOfMatter" tab="物模型管理">
  15 + </Tabs.TabPane>
  16 + <Tabs.TabPane key="modelOfMatter" tab="物模型管理">
17 17 <PhysicalModelManagementStep :record="record" />
18   - </TabPane>
  18 + </Tabs.TabPane>
19 19 </Tabs>
20 20 </BasicDrawer>
21 21 </template>
22 22 <script lang="ts" setup>
23 23 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
24   - import { Tabs, TabPane } from 'ant-design-vue';
  24 + import { Tabs } from 'ant-design-vue';
25 25 import DeviceConfigurationStep from './step/DeviceConfigurationStep.vue';
26 26 import TransportConfigurationStep from './step/TransportConfigurationStep.vue';
27 27 import PhysicalModelManagementStep from './step/PhysicalModelManagementStep.vue';
... ... @@ -50,6 +50,7 @@
50 50
51 51 const [register, {}] = useDrawerInner(async (data: { record: DeviceRecord }) => {
52 52 activeKey.value = 'product';
  53 + record.value = data.record;
53 54 record.value = await deviceConfigGetDetail(data.record.id);
54 55 setDeviceConfFormData(unref(record));
55 56 });
... ...
... ... @@ -6,6 +6,8 @@ import { numberRule } from '/@/utils/rules';
6 6
7 7 import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi';
8 8 import { FormField, FunctionType } from './step/cpns/physical/cpns/config';
  9 +import { h } from 'vue';
  10 +import { Tag } from 'ant-design-vue';
9 11
10 12 export const steps = [
11 13 {
... ... @@ -21,7 +23,7 @@ export const steps = [
21 23 export const formatFunctionType: Record<FunctionType, string> = {
22 24 [FunctionType.PROPERTIES]: '属性',
23 25 [FunctionType.EVENTS]: '事件',
24   - [FunctionType.SERVICE]: '事件',
  26 + [FunctionType.SERVICE]: '服务',
25 27 };
26 28
27 29 export const physicalColumn: BasicColumn[] = [
... ... @@ -52,12 +54,49 @@ export const physicalColumn: BasicColumn[] = [
52 54 },
53 55 },
54 56 {
  57 + title: '状态',
  58 + dataIndex: 'status',
  59 + width: 100,
  60 + customRender: (value: Record<'text', number>) => {
  61 + const { text } = value;
  62 + return h(
  63 + Tag,
  64 + {
  65 + color: text ? 'green' : 'red',
  66 + },
  67 + () => (text ? '已发布' : '待发布')
  68 + );
  69 + },
  70 + },
  71 + {
55 72 title: '创建时间',
56 73 dataIndex: 'createTime',
57 74 width: 150,
58 75 },
59 76 ];
60 77
  78 +export const modelOfMatterForm: FormSchema[] = [
  79 + {
  80 + field: 'functionType',
  81 + label: '功能类型',
  82 + component: 'Select',
  83 + colProps: { span: 8 },
  84 + componentProps: {
  85 + options: [
  86 + { label: formatFunctionType[FunctionType.PROPERTIES], value: FunctionType.PROPERTIES },
  87 + { label: formatFunctionType[FunctionType.EVENTS], value: FunctionType.EVENTS },
  88 + { label: formatFunctionType[FunctionType.SERVICE], value: FunctionType.SERVICE },
  89 + ],
  90 + },
  91 + },
  92 + {
  93 + field: 'nameOrIdentifier',
  94 + label: '功能名称/标识符',
  95 + component: 'Input',
  96 + colProps: { span: 8 },
  97 + },
  98 +];
  99 +
61 100 export const step1Schemas: FormSchema[] = [
62 101 {
63 102 field: 'image',
... ...
... ... @@ -2,6 +2,7 @@
2 2 <div class="p-style">
3 3 <BasicTable
4 4 :rowSelection="{ type: 'checkbox' }"
  5 + class="bg-gray-100 dark:bg-dark-900"
5 6 :clickToRowSelect="false"
6 7 @register="registerTable"
7 8 >
... ... @@ -31,6 +32,9 @@
31 32 新增物模型
32 33 </Button>
33 34 <Button type="primary" @click="handleOpenTsl"> 物模型TSL </Button>
  35 + <Button v-if="isShowBtn" type="primary" @click="handleImportModel"
  36 + >导入物模型</Button
  37 + >
34 38 </Authority>
35 39 </div>
36 40 <div class="flex gap-2">
... ... @@ -41,7 +45,9 @@
41 45 cancel-text="取消"
42 46 @confirm="handleEmit"
43 47 >
44   - <Button v-if="isShowBtn" type="primary"> 发布上线 </Button>
  48 + <Button v-if="isShowBtn" type="primary" :loading="releaseLoading">
  49 + 发布上线
  50 + </Button>
45 51 </Popconfirm>
46 52 <Button v-if="isShowBtn" class="!bg-gray-200" type="text" @click="handleReturn">
47 53 返回
... ... @@ -108,7 +114,7 @@
108 114 <script lang="ts" setup>
109 115 import { BasicTable, useTable, TableAction } from '/@/components/Table';
110 116 import { useModal } from '/@/components/Modal';
111   - import { physicalColumn } from '../device.profile.data';
  117 + import { modelOfMatterForm, physicalColumn } from '../device.profile.data';
112 118 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
113 119 import { Authority } from '/@/components/Authority';
114 120 import PhysicalModelModal from './cpns/physical/PhysicalModelModal.vue';
... ... @@ -116,13 +122,13 @@
116 122 import { Popconfirm, Button, Alert } from 'ant-design-vue';
117 123 import { useMessage } from '/@/hooks/web/useMessage';
118 124 import { DeviceRecord } from '/@/api/device/model/deviceModel';
119   - import { deleteModel, getModelList } from '/@/api/device/modelOfMatter';
  125 + import { deleteModel, getModelList, releaseModel } from '/@/api/device/modelOfMatter';
120 126 import { OpenModelOfMatterModelParams, OpenModelMode } from './cpns/physical/types';
121 127 import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
122 128 import { ref } from 'vue';
123 129 defineEmits(['register']);
124 130
125   - defineProps<{
  131 + const props = defineProps<{
126 132 record: DeviceRecord;
127 133 }>();
128 134
... ... @@ -132,13 +138,19 @@
132 138 const [registerModalTsl, { openModal: openModalTsl }] = useModal();
133 139
134 140 const [registerTable, { reload, setProps }] = useTable({
135   - api: getModelList,
  141 + api: async (params: Record<'page' | 'pageSize', number>) => {
  142 + return await getModelList({ ...params, deviceProfileId: props.record.id });
  143 + },
136 144 columns: physicalColumn,
137 145 showIndexColumn: false,
138 146 clickToRowSelect: false,
139   - useSearchForm: false,
140 147 showTableSetting: true,
141 148 bordered: true,
  149 + useSearchForm: true,
  150 + formConfig: {
  151 + schemas: modelOfMatterForm,
  152 + labelWidth: 120,
  153 + },
142 154 actionColumn: {
143 155 width: 200,
144 156 title: '操作',
... ... @@ -200,11 +212,23 @@
200 212 const handleEditPhysicalModel = () => (isShowBtn.value = true);
201 213
202 214 const handleReturn = () => (isShowBtn.value = false);
203   - const handleEmit = () => {
204   - isShowBtn.value = false;
205   - createMessage.success('发布成功');
  215 +
  216 + const releaseLoading = ref(false);
  217 + const handleEmit = async () => {
  218 + try {
  219 + releaseLoading.value = true;
  220 + await releaseModel(props.record.id);
  221 + handleReturn();
  222 + createMessage.success('发布成功');
  223 + reload();
  224 + } catch (error) {
  225 + } finally {
  226 + releaseLoading.value = false;
  227 + }
206 228 };
207 229
  230 + const handleImportModel = async () => {};
  231 +
208 232 defineExpose({});
209 233 </script>
210 234 <style lang="less" scoped>
... ...
... ... @@ -9,7 +9,7 @@
9 9 @ok="handleSubmit"
10 10 @cancel="handleCancel"
11 11 >
12   - <div>
  12 + <div class="relative">
13 13 <div v-if="openModalMode === OpenModelMode.CREATE">
14 14 <Typography>
15 15 <TypographyParagraph>
... ... @@ -24,26 +24,26 @@
24 24 :size="size"
25 25 >
26 26 <TabPane :key="FunctionType.PROPERTIES" tab="属性" />
27   - <TabPane :key="FunctionType.SERVICE" tab="服务" />
28   - <TabPane
29   - :key="FunctionType.EVENTS"
30   - tab="事件"
31   - :disabled="$props.record.transportType === 'TCP'"
32   - />
  27 + <TabPane :key="FunctionType.SERVICE" :disabled="isTCPGatewaySubDevice" tab="服务" />
  28 + <TabPane :key="FunctionType.EVENTS" tab="事件" :disabled="isTCPGatewaySubDevice" />
33 29 </Tabs>
34   - <Attribute v-show="activeKey === FunctionType.PROPERTIES" ref="AttrRef" />
  30 + <Attribute v-if="activeKey === FunctionType.PROPERTIES" ref="AttrRef" />
35 31 <Service
36   - v-show="activeKey === FunctionType.SERVICE"
  32 + v-if="activeKey === FunctionType.SERVICE"
37 33 :record="$props.record"
38 34 ref="ServiceRef"
39 35 />
40   - <Events v-show="activeKey === FunctionType.EVENTS" ref="EventsRef" />
  36 + <Events v-if="activeKey === FunctionType.EVENTS" ref="EventsRef" />
  37 + <div
  38 + v-if="openModalMode === OpenModelMode.VIEW"
  39 + class="absolute w-full h-full top-0 cursor-not-allowed z-50"
  40 + ></div>
41 41 </div>
42 42 </BasicModal>
43 43 </div>
44 44 </template>
45 45 <script lang="ts" setup>
46   - import { ref, unref } from 'vue';
  46 + import { ref, unref, nextTick, computed } from 'vue';
47 47 import { BasicModal, useModalInner } from '/@/components/Modal';
48 48 import { Tabs, TabPane, Typography, TypographyParagraph } from 'ant-design-vue';
49 49 import Attribute from './cpns/Attribute.vue';
... ... @@ -51,7 +51,7 @@
51 51 import Events from './cpns/Events.vue';
52 52 import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
53 53 import { createModel, updateModel } from '/@/api/device/modelOfMatter';
54   - import { DeviceRecord } from '/@/api/device/model/deviceModel';
  54 + import { DeviceRecord, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
55 55 import { useMessage } from '/@/hooks/web/useMessage';
56 56 import { OpenModelMode, OpenModelOfMatterModelParams } from './types/index';
57 57 import { FunctionType } from './cpns/config';
... ... @@ -62,6 +62,12 @@
62 62 record: DeviceRecord;
63 63 }>();
64 64
  65 + const isTCPGatewaySubDevice = computed(() => {
  66 + const { record } = props;
  67 + const { deviceType, transportType } = record;
  68 + return deviceType === DeviceTypeEnum.SENSOR && transportType === 'TCP';
  69 + });
  70 +
65 71 const blockContent = `属性一般是设备的运行状态,如当前温度等;服务是设备可被调用的方法,支持定义参数,如执行某项任务;事件则是设备上报的
66 72 通知,如告警,需要被及时处理。`;
67 73 const activeKey = ref<FunctionType>(FunctionType.PROPERTIES);
... ... @@ -101,16 +107,13 @@
101 107 if (record) {
102 108 functionType.value = data.record.functionType;
103 109 activeKey.value = data.record.functionType;
  110 + await nextTick();
104 111 setFormData(record.functionType, record as unknown as ModelOfMatterParams);
105 112 }
106 113 if (unref(openModalMode) === OpenModelMode.VIEW) {
107 114 setModalProps({ showOkBtn: false, showCancelBtn: false, title: '查看物模型' });
108   - // setFormData(functionType.value, record);
109 115 } else {
110 116 const title = unref(openModalMode) === OpenModelMode.UPDATE ? '编辑物模型' : '新增物模型';
111   - if (OpenModelMode.UPDATE) {
112   - // setFormData(functionType.value, record);
113   - }
114 117 setModalProps({ title, showOkBtn: true, showCancelBtn: true });
115 118 }
116 119 }
... ... @@ -150,6 +153,7 @@
150 153 closeModal();
151 154 emit('success');
152 155 } catch (error) {
  156 + throw Error(error);
153 157 } finally {
154 158 setModalProps({ loading: false, okButtonProps: { loading: false } });
155 159 }
... ...
... ... @@ -6,6 +6,7 @@
6 6 width="55rem"
7 7 @register="register"
8 8 @ok="handleSubmit"
  9 + okText="导出物模型"
9 10 @cancel="handleCancel"
10 11 >
11 12 <TslContent :record="$props.record" ref="TslConRef" />
... ... @@ -19,7 +20,7 @@
19 20
20 21 defineEmits(['register']);
21 22
22   - defineProps<{
  23 + const props = defineProps<{
23 24 record: DeviceRecord;
24 25 }>();
25 26
... ... @@ -42,7 +43,17 @@
42 43 const handleSubmit = () => {
43 44 const value = TslConRef.value?.getFormData();
44 45 if (!value) return;
45   - console.log('搜集值', value);
  46 +
  47 + const blob = new Blob([JSON.stringify(value, null, 2)], { type: 'text/json' });
  48 + const objectURL = URL.createObjectURL(blob);
  49 + const element = document.createElement('a');
  50 + element.href = objectURL;
  51 + element.download = `${props.record.name}-model.json`;
  52 + element.style.display = 'none';
  53 + document.body.appendChild(element);
  54 + element.click();
  55 + element.remove();
  56 + URL.revokeObjectURL(objectURL);
46 57 };
47 58 </script>
48 59
... ...
... ... @@ -6,7 +6,10 @@
6 6 import { DataType, ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
7 7 import { formSchemas } from '/@/components/Form/src/externalCompns/components/StructForm/config';
8 8 import { StructFormValue } from '/@/components/Form/src/externalCompns/components/StructForm/type';
9   - import { transfromToStructJSON } from '/@/components/Form/src/externalCompns/components/StructForm/util';
  9 + import {
  10 + transfromToStructJSON,
  11 + excludeIdInStructJSON,
  12 + } from '/@/components/Form/src/externalCompns/components/StructForm/util';
10 13 import { FunctionType } from './config';
11 14 import { isArray } from 'lodash';
12 15
... ... @@ -26,6 +29,8 @@
26 29 if (!_values) return {};
27 30 const { functionName, remark, identifier, accessMode } = _values;
28 31 const structJSON = transfromToStructJSON(_values);
  32 + const dataType = excludeIdInStructJSON(structJSON.dataType!);
  33 +
29 34 const value = {
30 35 functionName,
31 36 functionType: FunctionType.PROPERTIES,
... ... @@ -33,7 +38,7 @@
33 38 identifier,
34 39 accessMode,
35 40 functionJson: {
36   - dataType: structJSON.dataType,
  41 + dataType: dataType,
37 42 },
38 43 } as ModelOfMatterParams;
39 44 return value;
... ...
... ... @@ -4,8 +4,9 @@
4 4 <script lang="ts" setup>
5 5 import { BasicForm, useForm } from '/@/components/Form';
6 6 import { eventSchemas, FunctionType } from './config';
7   - import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  7 + import { ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel';
8 8 import { StructFormValue } from '/@/components/Form/src/externalCompns/components/StructForm/type';
  9 + import { excludeIdInStructJSON } from '/@/components/Form/src/externalCompns/components/StructForm/util';
9 10
10 11 const [register, { validate, resetFields, setFieldsValue }] = useForm({
11 12 labelWidth: 100,
... ... @@ -34,8 +35,13 @@
34 35
35 36 async function getFormData() {
36 37 const _values = (await validate()) as StructFormValue;
37   - const { functionName, remark, identifier, outputData, eventType } = _values;
  38 + const { functionName, remark, identifier, outputData: _outputData, eventType } = _values;
38 39 if (!_values) return {} as unknown as ModelOfMatterParams;
  40 +
  41 + const outputData = (_outputData as unknown as StructJSON[]).map((item) =>
  42 + excludeIdInStructJSON(item.dataType!)
  43 + );
  44 +
39 45 const value = {
40 46 functionName,
41 47 identifier,
... ...
... ... @@ -6,8 +6,9 @@
6 6 import { serviceSchemas } from './config';
7 7 import { FunctionType } from './config';
8 8 import { StructFormValue } from '/@/components/Form/src/externalCompns/components/StructForm/type';
9   - import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  9 + import { ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel';
10 10 import { DeviceRecord } from '/@/api/device/model/deviceModel';
  11 + import { excludeIdInStructJSON } from '/@/components/Form/src/externalCompns/components/StructForm/util';
11 12
12 13 const props = defineProps<{
13 14 record: DeviceRecord;
... ... @@ -27,7 +28,10 @@
27 28 //回显数据
28 29 const setFormData = (record: ModelOfMatterParams) => {
29 30 const { functionJson = {}, functionName, identifier, remark, callType } = record;
30   - const { inputData, outputData, serviceCommand } = functionJson;
  31 + const { inputData = [], outputData } = functionJson;
  32 + const { serviceCommand } =
  33 + (inputData.at(0) as unknown as { serviceCommand: string }) ||
  34 + ({} as { serviceCommand: string });
31 35 const value = {
32 36 functionName,
33 37 identifier,
... ... @@ -43,9 +47,24 @@
43 47 //获取数据
44 48 async function getFormData() {
45 49 const _values = (await validate()) as StructFormValue;
46   - const { functionName, remark, identifier, inputData, outputData, serviceCommand, callType } =
47   - _values;
  50 + const {
  51 + functionName,
  52 + remark,
  53 + identifier,
  54 + inputData: _inputData = [],
  55 + outputData: _outputData = [],
  56 + serviceCommand,
  57 + callType,
  58 + } = _values;
48 59 if (!_values) return {};
  60 +
  61 + const outputData = (_outputData as unknown as StructJSON[]).map((item) =>
  62 + excludeIdInStructJSON(item.dataType!)
  63 + );
  64 + const inputData = (_inputData as unknown as StructJSON[]).map((item) =>
  65 + excludeIdInStructJSON(item.dataType!)
  66 + );
  67 +
49 68 const value = {
50 69 functionName,
51 70 identifier,
... ... @@ -55,7 +74,7 @@
55 74 functionJson: {
56 75 inputData,
57 76 outputData,
58   - serviceCommand,
  77 + ...(serviceCommand ? { inputData: [{ serviceCommand }] } : {}),
59 78 },
60 79 } as ModelOfMatterParams;
61 80
... ...
... ... @@ -30,7 +30,7 @@
30 30 </div>
31 31 <div>
32 32 <Spin :spinning="loading">
33   - <div id="jsoneditor" ref="jsoneditorRef"></div>
  33 + <div id="jsoneditor" ref="jsoneditorEl"></div>
34 34 </Spin>
35 35 </div>
36 36 </div>
... ... @@ -60,9 +60,12 @@
60 60
61 61 const jsonValue = ref();
62 62
63   - const jsonInstance = ref();
  63 + const jsonInstance = ref<{
  64 + set: (value?: Recordable) => void;
  65 + get: () => Recordable;
  66 + }>();
64 67
65   - const jsoneditorRef = ref<Recordable>();
  68 + const jsoneditorEl = ref<HTMLDivElement>();
66 69
67 70 const activeKey = ref(FunctionType.PROPERTIES);
68 71
... ... @@ -73,7 +76,7 @@
73 76 mainMenuBar: false,
74 77 statusBar: false,
75 78 };
76   - let editor = new jsoneditor(jsoneditorRef.value, options);
  79 + let editor = new jsoneditor(jsoneditorEl.value, options);
77 80 editor.set(jsonValue.value);
78 81 jsonInstance.value = editor;
79 82 });
... ... @@ -83,7 +86,7 @@
83 86
84 87 const handleCopy = () => {
85 88 try {
86   - const valueRef = unref(jsonInstance).get();
  89 + const valueRef = unref(jsonInstance)?.get();
87 90 const value = JSON.stringify(unref(valueRef));
88 91 if (!value) {
89 92 createMessage.warning('请输入要拷贝的内容!');
... ... @@ -99,31 +102,36 @@
99 102 };
100 103
101 104 const getFormData = () => {
102   - const value = unref(jsonInstance).get();
  105 + const value = unref(jsonInstance)?.get();
103 106 if (!value) return;
104 107 return value;
105 108 };
106 109
107 110 const resetFormData = () => {
108   - unref(jsonInstance).set();
  111 + unref(jsonInstance)?.set();
109 112 };
110 113
111 114 const handlePremitter = () => {
112   - const value = unref(jsonInstance).get();
113   - return unref(jsonInstance).set(value);
  115 + const value = unref(jsonInstance)?.get();
  116 + return unref(jsonInstance)?.set(value);
114 117 };
115 118
116 119 const handleSwitchTsl = async (functionType: FunctionType) => {
117 120 try {
118 121 loading.value = true;
119 122 const record = await getModelTsl({ deviceProfileId: props.record.id, functionType });
120   - console.log(record);
  123 + jsonInstance.value?.set(record);
121 124 } catch (error) {
122 125 } finally {
123 126 loading.value = false;
124 127 }
125 128 };
126 129
  130 + onMounted(() => {
  131 + activeKey.value = FunctionType.PROPERTIES;
  132 + handleSwitchTsl(FunctionType.PROPERTIES);
  133 + });
  134 +
127 135 defineExpose({
128 136 getFormData,
129 137 resetFormData,
... ...
1   -<template>
2   - <div>
3   - <BasicForm @register="registerForm">
4   - <template #structSlot>
5   - <CommomParam
6   - ref="CommomParamInParamRef"
7   - :isExcludeStruct="true"
8   - :isInputParam="true"
9   - :inputParamData="inputParamData"
10   - @emitAddInParam="handleAddInParam"
11   - @emitEditInParam="handleEditInParam"
12   - @emitDeletelnParam="handleDelInParam"
13   - />
14   - </template>
15   - </BasicForm>
16   - <AddParamsModal @register="registerModal" @data="getData" />
17   - </div>
18   -</template>
19   -<script lang="ts" setup>
20   - import { unref } from 'vue';
21   - import { BasicForm, useForm } from '/@/components/Form';
22   - import { addParamsSchemas } from '../config';
23   - import { useModal } from '/@/components/Modal';
24   - import useCommon from '../../hook/useCommon';
25   - import AddParamsModal from './AddParamsModal.vue';
26   - import CommomParam from './CommomParam.vue';
27   - import useDefineVar from '../../hook/useDefineVar';
28   -
29   - defineEmits(['register']);
30   -
31   - const { inputParamData, CommomParamInParamRef } = useDefineVar();
32   -
33   - const { useChangeTypeGetTypeForm, useGetInOrOutData, useUpdateFormExcludeStruct } = useCommon();
34   -
35   - const [registerModal, { openModal }] = useModal();
36   -
37   - const [registerForm, { validate, resetFields, updateSchema }] = useForm({
38   - labelWidth: 100,
39   - schemas: addParamsSchemas,
40   - actionColOptions: {
41   - span: 14,
42   - },
43   - showResetButton: false,
44   - submitOnReset: false,
45   - showActionButtonGroup: false,
46   - });
47   -
48   - const getData = (d, f) => useGetInOrOutData(d, f, unref(inputParamData), []);
49   -
50   - const handleAddInParam = (b, o) => openModal(b, o);
51   -
52   - const handleEditInParam = (b, o) => openModal(b, o);
53   -
54   - const handleDelInParam = (i) => unref(inputParamData).splice(i, 1);
55   -
56   - const updateFormExcludeStruct = (flag) => useUpdateFormExcludeStruct(flag, updateSchema);
57   -
58   - const getOutputStructList = () => CommomParamInParamRef.value?.getInputStructList();
59   -
60   - const getBoolOrStruct = (T, S, B) => {
61   - if (T === 'STRUCT') {
62   - return S;
63   - } else if (T === 'INT' || T === 'DOUBLE' || T === 'TEXT') {
64   - return null;
65   - } else {
66   - return B;
67   - }
68   - };
69   -
70   - const getIntOrText = (T, D) => {
71   - if (T === 'STRUCT') {
72   - return null;
73   - } else if (T === 'INT' || T === 'DOUBLE' || T === 'TEXT') {
74   - return D;
75   - }
76   - };
77   -
78   - const getFormData = async () => {
79   - const values = await validate();
80   - if (!values) return;
81   - const outputParams = getOutputStructList();
82   - outputParams?.forEach((f) => {
83   - f.dataType = 'STRUCT';
84   - f.childSpecsDTO = getIntOrText(f.childDataType, f.dataSpecs);
85   - f.childEnumSpecsDTO = getBoolOrStruct(f.childDataType, null, f.dataSpecsList);
86   - });
87   - const dataSpecs = useChangeTypeGetTypeForm(values.dataType, values);
88   - const dataSpecsList = useChangeTypeGetTypeForm(values.dataType, values);
89   - const { boolClose, boolOpen, step, unit, valueRange, length, ...value } = values;
90   - const none = [valueRange, step, unit, boolOpen, boolClose, length]; //没用,防止eslint报未使用变量
91   - console.log(none);
92   - return {
93   - ...{ childName: value.name },
94   - ...{ childDataType: value.dataType },
95   - ...value,
96   - ...{
97   - dataSpecs: getIntOrText(values.dataType, dataSpecs),
98   - },
99   - ...{
100   - dataSpecsList: getBoolOrStruct(values.dataType, outputParams, dataSpecsList),
101   - },
102   - };
103   - };
104   -
105   - const setFormData = (v) => {
106   - try {
107   - setFieldsValue(v);
108   - setFieldsValue({
109   - ...v.dataSpecs,
110   - valueRange: v.dataSpecs,
111   - });
112   - setFieldsValue({
113   - boolClose: v.dataType == 'BOOL' ? v.dataSpecsList[0].name : '',
114   - boolOpen: v.dataType == 'BOOL' ? v.dataSpecsList[1].name : '',
115   - });
116   - const { dataSpecsList, dataType, childDataType } = v;
117   - if (childDataType == 'BOOL') {
118   - setFieldsValue({
119   - dataType: childDataType,
120   - boolClose: dataSpecsList[0].name,
121   - boolOpen: dataSpecsList[1].name,
122   - });
123   - }
124   - if (dataType == 'BOOL' || dataType == 'STRUCT') {
125   - inputParamData.value = [...new Array(dataSpecsList.length).keys()];
126   - inputParamData.value = dataSpecsList;
127   - }
128   - } catch (e) {
129   - console.log('AddParamForm error info', e);
130   - }
131   - };
132   -
133   - const resetFormData = () => {
134   - resetFields();
135   - inputParamData.value = [];
136   - };
137   -
138   - defineExpose({
139   - setFormData,
140   - getFormData,
141   - resetFormData,
142   - updateFormExcludeStruct,
143   - });
144   -</script>
145   -
146   -<style lang="less" scope>
147   - .add-style {
148   - color: #0170cc;
149   - cursor: pointer;
150   - }
151   -</style>
1   -<template>
2   - <div>
3   - <BasicModal
4   - :title="getTitle"
5   - :maskClosable="false"
6   - v-bind="$attrs"
7   - width="45rem"
8   - @register="register"
9   - @ok="handleSubmit"
10   - @cancel="handleCancel"
11   - >
12   - <AddParamForm ref="AddParamFormRef" />
13   - </BasicModal>
14   - </div>
15   -</template>
16   -<script lang="ts" setup>
17   - import { ref, computed, reactive } from 'vue';
18   - import { BasicModal, useModalInner } from '/@/components/Modal';
19   - import AddParamForm from './AddParamForm.vue';
20   - import useParitalValid from '../../hook/useParitalValid';
21   -
22   - const emits = defineEmits(['register', 'data']);
23   -
24   - const {} = useParitalValid();
25   -
26   - const setEditData: any = reactive({
27   - getEditData: {},
28   - });
29   -
30   - const AddParamFormRef = ref<InstanceType<typeof AddParamForm>>();
31   -
32   - const isUpdate = ref(false);
33   -
34   - const isFlag = ref('');
35   -
36   - const excludeStruct = ref(false);
37   -
38   - const getTitle = computed(() => (!isUpdate.value ? '编辑参数' : '新增参数'));
39   -
40   - const [register, { setModalProps }] = useModalInner(async (data) => {
41   - setModalProps({ loading: true });
42   -
43   - isUpdate.value = data.isUpdate;
44   - isFlag.value = data.flag;
45   - excludeStruct.value = data.excludeStruct;
46   - !isUpdate.value ? AddParamFormRef.value?.setFormData(data.record) : '';
47   - setEditData.getEditData = data.record;
48   - setModalProps({ loading: false });
49   - if (excludeStruct.value) {
50   - AddParamFormRef.value?.updateFormExcludeStruct(true);
51   - } else {
52   - AddParamFormRef.value?.updateFormExcludeStruct(false);
53   - }
54   - });
55   -
56   - const handleCancel = () => {
57   - AddParamFormRef.value?.resetFormData();
58   - };
59   -
60   - const handleSubmit = async () => {
61   - const value = await AddParamFormRef.value?.getFormData();
62   - if (!value) return;
63   - emits('data', value);
64   - handleCancel();
65   - };
66   -</script>
67   -<style lang="less" scope></style>
1   -<template>
2   - <!-- 输入参数 -->
3   - <div v-if="isInputParam">
4   - <template v-for="(item, index) in inputParamData" :key="item.name">
5   - <span style="display: none">{{ item }}</span>
6   - <InputParamItem
7   - :title="item.name"
8   - :item="item"
9   - class="mt-4"
10   - :index="index"
11   - :ref="dynamicBindRef.inputParamItemRef"
12   - @delete="deleteInParItem"
13   - @edit="editInParItem"
14   - />
15   - </template>
16   - <div style="display: flex" :class="{ 'mt-2': inputParamData.length > 0 }">
17   - <span class="add-style">+</span>
18   - <span class="add-style" @click="handleAddInParam">增加参数</span>
19   - </div>
20   - </div>
21   - <!-- 输出参数 -->
22   - <div v-if="isOutputParam">
23   - <template v-for="(item, index) in outputParamData" :key="item.name">
24   - <span style="display: none">{{ item + index }}</span>
25   - <InputParamItem
26   - :title="item.name"
27   - :item="item"
28   - class="mt-4"
29   - :index="index"
30   - :ref="dynamicBindRef.outputParamItemRef"
31   - @delete="deleteOutParItem"
32   - @edit="editOutParItem"
33   - />
34   - </template>
35   - <div style="display: flex" :class="{ 'mt-2': outputParamData.length > 0 }">
36   - <span class="add-style">+</span>
37   - <span class="add-style" @click="handleAddOutParam">增加参数</span>
38   - </div>
39   - </div>
40   -</template>
41   -<script lang="ts" setup>
42   - import { ref, unref } from 'vue';
43   - import InputParamItem from './InputParamItem.vue';
44   -
45   - const props = defineProps({
46   - isExcludeStruct: { type: Boolean, default: true },
47   - isInputParam: { type: Boolean, default: false },
48   - isOutputParam: { type: Boolean, default: false },
49   - inputParamData: {
50   - type: Array as PropType<any[]>,
51   - default: () => [],
52   - },
53   - outputParamData: {
54   - type: Array as PropType<any[]>,
55   - default: () => [],
56   - },
57   - });
58   -
59   - const emit = defineEmits([
60   - 'emitAddInParam',
61   - 'emitEditInParam',
62   - 'emitDeletelnParam',
63   - 'emitAddOutParam',
64   - 'emitEditOutParam',
65   - 'emitDeleteOutParam',
66   - ]);
67   -
68   - const dynamicBindRef = {
69   - inputParamItemRef: ref([]),
70   - outputParamItemRef: ref([]),
71   - };
72   -
73   - const commomAddParamObj = {
74   - isUpdate: true,
75   - excludeStruct: props.isExcludeStruct ? true : false,
76   - };
77   -
78   - const commomEditParamObj = {
79   - isUpdate: false,
80   - excludeStruct: props.isExcludeStruct ? true : false,
81   - };
82   -
83   - const handleAddInParam = () => {
84   - emit('emitAddInParam', true, {
85   - ...commomAddParamObj,
86   - flag: 'input',
87   - });
88   - };
89   -
90   - const deleteInParItem = (index) => {
91   - emit('emitDeletelnParam', index);
92   - };
93   -
94   - const editInParItem = (item) => {
95   - emit('emitEditInParam', true, {
96   - ...commomEditParamObj,
97   - record: item,
98   - flag: 'input',
99   - });
100   - };
101   -
102   - const handleAddOutParam = () => {
103   - emit('emitAddOutParam', true, {
104   - ...commomAddParamObj,
105   - flag: 'output',
106   - });
107   - };
108   -
109   - const deleteOutParItem = (index) => {
110   - emit('emitDeleteOutParam', index);
111   - };
112   -
113   - const editOutParItem = (item) => {
114   - emit('emitEditOutParam', true, {
115   - ...commomEditParamObj,
116   - record: item,
117   - flag: 'output',
118   - });
119   - };
120   -
121   - const getInputStructList = () =>
122   - unref(dynamicBindRef.inputParamItemRef)?.map((item: any) => item.getFormData());
123   -
124   - const getOutputStructList = () =>
125   - unref(dynamicBindRef.outputParamItemRef)?.map((item: any) => item.getFormData());
126   -
127   - defineExpose({
128   - getInputStructList,
129   - getOutputStructList,
130   - });
131   -</script>
132   -<style lang="less" scoped>
133   - .add-style {
134   - color: #0170cc;
135   - cursor: pointer;
136   - }
137   -</style>
1   -<template>
2   - <div>
3   - <a-card :title="`参数名称:${item.id}`" style="width: 540px; margin-top: -5px">
4   - <template #extra>
5   - <div style="display: flex; align-items: center">
6   - <span style="color: #0170cc; cursor: pointer" @click="handleEdit">编辑</span>
7   - <a-divider type="vertical" style="height: 12px; background-color: #d8d8d8" />
8   - <span style="color: #0170cc; cursor: pointer" class="ml-1" @click="handleDelete"
9   - >删除</span
10   - >
11   - </div>
12   - </template>
13   - </a-card>
14   - </div>
15   -</template>
16   -<script lang="ts" setup>
17   - import { FunctionJson } from '/@/api/device/model/modelOfMatterModel';
18   -
19   - const emit = defineEmits(['delete', 'edit']);
20   -
21   - type ItemRecrod = FunctionJson & { id: string };
22   -
23   - const props = defineProps({
24   - item: {
25   - type: Object as PropType<ItemRecrod>,
26   - required: true,
27   - default: () => {},
28   - },
29   - });
30   -
31   - const handleDelete = () => {
32   - emit('delete', props.item);
33   - };
34   -
35   - const handleEdit = () => {
36   - emit('edit', props.item);
37   - };
38   -
39   - const getFormData = () => {
40   - return props.item;
41   - };
42   -
43   - defineExpose({
44   - getFormData,
45   - });
46   -</script>
47   -<style lang="less" scoped>
48   - :deep(.ant-card-body) {
49   - display: none !important;
50   - }
51   -</style>
... ... @@ -113,6 +113,15 @@ export const serviceSchemas = (tcpDeviceFlag: boolean): FormSchema[] => {
113 113 },
114 114 },
115 115 {
  116 + field: FormField.SERVICE_COMMAND,
  117 + label: '输入参数',
  118 + component: 'Input',
  119 + ifShow: tcpDeviceFlag,
  120 + componentProps: {
  121 + placeholder: '请输入ASCII或HEX服务命令',
  122 + },
  123 + },
  124 + {
116 125 field: FormField.INPUT_PARAM,
117 126 label: '输入参数',
118 127 component: 'StructForm',
... ... @@ -127,19 +136,9 @@ export const serviceSchemas = (tcpDeviceFlag: boolean): FormSchema[] => {
127 136 component: 'StructForm',
128 137 valueField: 'value',
129 138 changeEvent: 'update:value',
130   - ifShow: !tcpDeviceFlag,
131 139 colProps: { span: 24 },
132 140 },
133 141 {
134   - field: FormField.SERVICE_COMMAND,
135   - label: '服务命令',
136   - component: 'Input',
137   - ifShow: tcpDeviceFlag,
138   - componentProps: {
139   - placeholder: '请输入服务命令',
140   - },
141   - },
142   - {
143 142 field: FormField.REFARK,
144 143 label: '备注',
145 144 component: 'InputTextArea',
... ...
1 1 <template>
2   - <div :class="`${prefixCls}-bottom`">
  2 + <div :class="[`${prefixCls}-bottom`, '!dark:bg-dark-900']">
3 3 <Tabs>
4 4 <template v-for="item in achieveList" :key="item.key">
5 5 <TabPane :tab="item.name">
... ... @@ -37,7 +37,7 @@
37 37 &-bottom {
38 38 padding: 10px;
39 39 margin: 16px;
40   - background-color: @component-background;
  40 + // background-color: @component-background;
41 41 border-radius: 3px;
42 42 }
43 43 }
... ...