Commit c676c5e3e658c66e83668786b0eef468d5124bdc

Authored by xp.Huang
2 parents e12b8af2 a189f5fa

Merge remote-tracking branch 'origin/ww'

# Conflicts:
#	src/views/device/list/cpns/tabs/commandRecord/index.vue
... ... @@ -2,7 +2,8 @@
2 2 <div class="flex">
3 3 <InputNumber
4 4 placeholder="最小值"
5   - :value="getValue.min"
  5 + :disabled="$props.disabled"
  6 + :value="getValue.min!"
6 7 style="width: 38%"
7 8 @change="(value) => emitChange(value, 'min')"
8 9 />
... ... @@ -11,7 +12,8 @@
11 12 <span style="width: 8px"></span>
12 13 <InputNumber
13 14 placeholder="最大值"
14   - :value="getValue.max"
  15 + :disabled="$props.disabled"
  16 + :value="getValue.max!"
15 17 style="width: 38%"
16 18 @change="(value) => emitChange(value, 'max')"
17 19 />
... ... @@ -33,6 +35,7 @@
33 35 min: Nullable<number>;
34 36 max: Nullable<number>;
35 37 };
  38 + disabled: boolean;
36 39 }>(),
37 40 {
38 41 value: () => ({ min: null, max: null }),
... ...
... ... @@ -19,6 +19,7 @@
19 19 const props = withDefaults(
20 20 defineProps<{
21 21 value: ModelOfMatterParams[];
  22 + disabled: boolean;
22 23 }>(),
23 24 {
24 25 value: () => [],
... ... @@ -82,20 +83,33 @@
82 83 >
83 84 <div>参数名称: {{ item.functionName }}</div>
84 85 <div class="flex">
85   - <Button class="!p-0" type="link" @click="handleUpdate(item)">编辑</Button>
  86 + <Button class="!p-0" type="link" @click="handleUpdate(item)">
  87 + <span>{{ $props.disabled ? '查看' : '编辑' }}</span>
  88 + </Button>
86 89 <Divider type="vertical" />
87   - <Button class="!p-0" type="link" @click="handleDelete(item)">删除</Button>
  90 + <Button
  91 + :disabled="$props.disabled"
  92 + class="!p-0"
  93 + type="link"
  94 + @click="handleDelete(item)"
  95 + >
  96 + <span>删除</span>
  97 + </Button>
88 98 </div>
89 99 </div>
90 100 </section>
91   - <div>
  101 + <div :class="$props.disabled && 'text-gray-400'">
92 102 <span class="mr-2">
93 103 <PlusOutlined />
94 104 </span>
95   - <span @click="handleCreateParams">增加参数</span>
  105 + <span @click="!$props.disabled && handleCreateParams()">增加参数</span>
96 106 </div>
97 107 </div>
98   - <StructFormModel @register="registerModal" @submit="handleSaveStruct" />
  108 + <StructFormModel
  109 + :disabled="$props.disabled"
  110 + @register="registerModal"
  111 + @submit="handleSaveStruct"
  112 + />
99 113 </section>
100 114 </template>
101 115
... ...
... ... @@ -18,14 +18,17 @@
18 18 mode: OpenModalMode.CREATE,
19 19 });
20 20
  21 + const props = defineProps<{ disabled: boolean }>();
  22 +
21 23 const emit = defineEmits(['register', 'submit']);
22 24
23   - const [register, { validate, setFieldsValue }] = useForm({
  25 + const [register, { validate, setFieldsValue, setProps }] = useForm({
24 26 labelWidth: 100,
25 27 schemas: formSchemas,
26 28 actionColOptions: {
27 29 span: 14,
28 30 },
  31 + disabled: props.disabled,
29 32 showResetButton: false,
30 33 submitOnReset: false,
31 34 showActionButtonGroup: false,
... ... @@ -46,6 +49,7 @@
46 49
47 50 setFieldsValue(value);
48 51 }
  52 + setProps({ disabled: props.disabled });
49 53 });
50 54
51 55 const handleSubmit = async () => {
... ... @@ -71,6 +75,7 @@
71 75 :width="800"
72 76 @ok="handleSubmit"
73 77 destroy-on-close
  78 + :show-ok-btn="!$props.disabled"
74 79 >
75 80 <BasicForm @register="register" />
76 81 </BasicModal>
... ...
... ... @@ -11,7 +11,7 @@ export enum DataTypeEnum {
11 11 IS_BOOL = 'BOOL',
12 12 }
13 13
14   -const validateValueRange = (_rule, value: Record<'min' | 'max', number>, _callback) => {
  14 +export const validateValueRange = (_rule, value: Record<'min' | 'max', number>, _callback) => {
15 15 value = value || {};
16 16 const { min, max } = value;
17 17 if (min >= max) {
... ... @@ -20,7 +20,7 @@ const validateValueRange = (_rule, value: Record<'min' | 'max', number>, _callba
20 20 return Promise.resolve();
21 21 };
22 22
23   -const validateJSON = (_rule, value: ModelOfMatterParams[], _callback) => {
  23 +export const validateJSON = (_rule, value: ModelOfMatterParams[], _callback) => {
24 24 if (value.length) {
25 25 return Promise.resolve();
26 26 }
... ... @@ -65,7 +65,15 @@ export const formSchemas: FormSchema[] = [
65 65 defaultValue: 'INT',
66 66 componentProps: {
67 67 placeholder: '请选择数据类型',
68   - api: findDictItemByCode,
  68 + api: async (params: Recordable) => {
  69 + try {
  70 + const record = await findDictItemByCode(params);
  71 + return record.filter((item) => item.itemValue !== 'STRUCT');
  72 + } catch (error) {
  73 + console.log(error);
  74 + return [];
  75 + }
  76 + },
69 77 params: {
70 78 dictCode: 'data_type',
71 79 },
... ...
1   -<template>
2   - <BasicDrawer
3   - v-bind="$attrs"
4   - isDetail
5   - @register="register"
6   - destroyOnClose
7   - @close="closeDrawer"
8   - :title="deviceDetail.alias || deviceDetail.name"
9   - width="80%"
10   - >
11   - <Tabs v-model:activeKey="activeKey" :size="size">
12   - <TabPane key="1" tab="详情">
13   - <Detail
14   - ref="deviceDetailRef"
15   - :deviceDetail="deviceDetail"
16   - @open-gateway-device="handleOpenGatewayDevice"
17   - />
18   - </TabPane>
19   - <TabPane key="modelOfMatter" tab="物模型数据">
20   - <ModelOfMatter :deviceDetail="deviceDetail" />
21   - </TabPane>
22   - <!-- <TabPane key="2" tab="实时数据" v-if="deviceDetail?.deviceType !== 'GATEWAY'">
23   - <RealTimeData :deviceDetail="deviceDetail" />
24   - </TabPane>
25   - <TabPane key="7" tab="历史数据" v-if="deviceDetail?.deviceType !== 'GATEWAY'">
26   - <HistoryData :deviceDetail="deviceDetail" />
27   - </TabPane> -->
28   - <TabPane key="5" tab="命令下发" v-if="deviceDetail?.deviceType !== 'SENSOR'">
29   - <CommandIssuance :deviceDetail="deviceDetail" />
30   - </TabPane>
31   - <TabPane key="3" tab="告警"><Alarm :id="deviceDetail.id" /></TabPane>
32   - <TabPane key="4" tab="子设备" v-if="deviceDetail?.deviceType === 'GATEWAY'">
33   - <ChildDevice
34   - :fromId="deviceDetail?.tbDeviceId"
35   - @openTbDeviceDetail="handleOpenTbDeviceDetail"
36   - />
37   - </TabPane>
38   - <TabPane key="7" tab="命令下发记录">
39   - <CommandRecord :fromId="deviceDetail?.tbDeviceId" />
40   - </TabPane>
41   - <!-- 网关设备并且场家是TBox -->
42   - <TabPane
43   - key="6"
44   - tab="TBox"
45   - v-if="deviceDetail?.deviceType === 'GATEWAY' && deviceDetail?.brand == 'TBox'"
46   - >
47   - <TBoxDetail :deviceDetail="deviceDetail" />
48   - </TabPane>
49   - <!-- 网关设备并且是TBox -->
50   - </Tabs>
51   - </BasicDrawer>
52   -</template>
53   -<script lang="ts">
54   - import { defineComponent, ref } from 'vue';
55   - import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
56   -
57   - import { Tabs } from 'ant-design-vue';
58   - import Detail from '../tabs/Detail.vue';
59   - // import RealTimeData from '../tabs/RealTimeData.vue';
60   - import Alarm from '../tabs/Alarm.vue';
61   - import ChildDevice from '../tabs/ChildDevice.vue';
62   - import TBoxDetail from '../tabs/TBoxDetail.vue';
63   - import CommandIssuance from '../tabs/CommandIssuance.vue';
64   - import { CommandRecord } from '../tabs/commandRecord/index';
65   - import { getDeviceDetail } from '/@/api/device/deviceManager';
66   - // import HistoryData from '../tabs/HistoryData.vue';
67   - import ModelOfMatter from '../tabs/ModelOfMatter.vue';
68   - export default defineComponent({
69   - name: 'DeviceModal',
70   - components: {
71   - BasicDrawer,
72   - Tabs,
73   - TabPane: Tabs.TabPane,
74   - Detail,
75   - // RealTimeData,
76   - Alarm,
77   - ChildDevice,
78   - CommandIssuance,
79   - TBoxDetail,
80   - // HistoryData,
81   - ModelOfMatter,
82   - CommandRecord,
83   - },
84   - emits: ['reload', 'register', 'openTbDeviceDetail', 'openGatewayDeviceDetail'],
85   - setup(_props, { emit }) {
86   - const activeKey = ref('1');
87   - const size = ref('small');
88   - const deviceDetailRef = ref();
89   - const deviceDetail = ref<any>({});
90   - const tbDeviceId = ref('');
91   - // 详情回显
92   - const [register] = useDrawerInner(async (data) => {
93   - const { id } = data;
94   - // 设备详情
95   - const res = await getDeviceDetail(id);
96   - deviceDetail.value = res;
97   - const { latitude, longitude, address } = res.deviceInfo;
98   - if (latitude) {
99   - deviceDetailRef.value.initMap(longitude, latitude, address);
100   - }
101   - });
102   - const closeDrawer = () => {
103   - activeKey.value = '1';
104   - };
105   -
106   - const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => {
107   - emit('openTbDeviceDetail', data);
108   - };
109   -
110   - const handleOpenGatewayDevice = (data: { gatewayId: string; tbDeviceId: string }) => {
111   - emit('openGatewayDeviceDetail', { id: data.gatewayId });
112   - };
113   -
114   - return {
115   - size,
116   - activeKey,
117   - register,
118   - closeDrawer,
119   - deviceDetail,
120   - deviceDetailRef,
121   - tbDeviceId,
122   - handleOpenTbDeviceDetail,
123   - handleOpenGatewayDevice,
124   - };
125   - },
126   - });
127   -</script>
  1 +<template>
  2 + <BasicDrawer
  3 + v-bind="$attrs"
  4 + isDetail
  5 + @register="register"
  6 + destroyOnClose
  7 + @close="closeDrawer"
  8 + :title="deviceDetail.alias || deviceDetail.name"
  9 + width="80%"
  10 + >
  11 + <Tabs v-model:activeKey="activeKey" :size="size">
  12 + <TabPane key="1" tab="详情">
  13 + <Detail
  14 + ref="deviceDetailRef"
  15 + :deviceDetail="deviceDetail"
  16 + @open-gateway-device="handleOpenGatewayDevice"
  17 + />
  18 + </TabPane>
  19 + <TabPane key="modelOfMatter" tab="物模型数据">
  20 + <ModelOfMatter :deviceDetail="deviceDetail" />
  21 + </TabPane>
  22 + <!-- <TabPane key="2" tab="实时数据" v-if="deviceDetail?.deviceType !== 'GATEWAY'">
  23 + <RealTimeData :deviceDetail="deviceDetail" />
  24 + </TabPane>
  25 + <TabPane key="7" tab="历史数据" v-if="deviceDetail?.deviceType !== 'GATEWAY'">
  26 + <HistoryData :deviceDetail="deviceDetail" />
  27 + </TabPane> -->
  28 + <TabPane key="5" tab="命令下发" v-if="deviceDetail?.deviceType !== 'SENSOR'">
  29 + <CommandIssuance :deviceDetail="deviceDetail" />
  30 + </TabPane>
  31 + <TabPane key="3" tab="告警"><Alarm :id="deviceDetail.id" /></TabPane>
  32 + <TabPane key="4" tab="子设备" v-if="deviceDetail?.deviceType === 'GATEWAY'">
  33 + <ChildDevice
  34 + :fromId="deviceDetail?.tbDeviceId"
  35 + @openTbDeviceDetail="handleOpenTbDeviceDetail"
  36 + />
  37 + </TabPane>
  38 + <TabPane key="7" tab="命令下发记录">
  39 + <CommandRecord :fromId="deviceDetail?.tbDeviceId" />
  40 + </TabPane>
  41 + <!-- 网关设备并且场家是TBox -->
  42 + <TabPane
  43 + key="6"
  44 + tab="TBox"
  45 + v-if="deviceDetail?.deviceType === 'GATEWAY' && deviceDetail?.brand == 'TBox'"
  46 + >
  47 + <TBoxDetail :deviceDetail="deviceDetail" />
  48 + </TabPane>
  49 + <!-- 网关设备并且是TBox -->
  50 +
  51 + <TabPane key="eventManage" tab="事件管理">
  52 + <EventManage />
  53 + </TabPane>
  54 + </Tabs>
  55 + </BasicDrawer>
  56 +</template>
  57 +<script lang="ts">
  58 + import { defineComponent, ref } from 'vue';
  59 + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
  60 +
  61 + import { Tabs } from 'ant-design-vue';
  62 + import Detail from '../tabs/Detail.vue';
  63 + // import RealTimeData from '../tabs/RealTimeData.vue';
  64 + import Alarm from '../tabs/Alarm.vue';
  65 + import ChildDevice from '../tabs/ChildDevice.vue';
  66 + import TBoxDetail from '../tabs/TBoxDetail.vue';
  67 + import CommandIssuance from '../tabs/CommandIssuance.vue';
  68 + import { CommandRecord } from '../tabs/commandRecord/index';
  69 + import { getDeviceDetail } from '/@/api/device/deviceManager';
  70 + // import HistoryData from '../tabs/HistoryData.vue';
  71 + import ModelOfMatter from '../tabs/ModelOfMatter.vue';
  72 + import EventManage from '../tabs/EventManage/index.vue';
  73 +
  74 + export default defineComponent({
  75 + name: 'DeviceModal',
  76 + components: {
  77 + BasicDrawer,
  78 + Tabs,
  79 + TabPane: Tabs.TabPane,
  80 + Detail,
  81 + // RealTimeData,
  82 + Alarm,
  83 + ChildDevice,
  84 + CommandIssuance,
  85 + TBoxDetail,
  86 + // HistoryData,
  87 + ModelOfMatter,
  88 + CommandRecord,
  89 + EventManage,
  90 + },
  91 + emits: ['reload', 'register', 'openTbDeviceDetail', 'openGatewayDeviceDetail'],
  92 + setup(_props, { emit }) {
  93 + const activeKey = ref('1');
  94 + const size = ref('small');
  95 + const deviceDetailRef = ref();
  96 + const deviceDetail = ref<any>({});
  97 + const tbDeviceId = ref('');
  98 + // 详情回显
  99 + const [register] = useDrawerInner(async (data) => {
  100 + const { id } = data;
  101 + // 设备详情
  102 + const res = await getDeviceDetail(id);
  103 + deviceDetail.value = res;
  104 + const { latitude, longitude, address } = res.deviceInfo;
  105 + if (latitude) {
  106 + deviceDetailRef.value.initMap(longitude, latitude, address);
  107 + }
  108 + });
  109 + const closeDrawer = () => {
  110 + activeKey.value = '1';
  111 + };
  112 +
  113 + const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => {
  114 + emit('openTbDeviceDetail', data);
  115 + };
  116 +
  117 + const handleOpenGatewayDevice = (data: { gatewayId: string; tbDeviceId: string }) => {
  118 + emit('openGatewayDeviceDetail', { id: data.gatewayId });
  119 + };
  120 +
  121 + return {
  122 + size,
  123 + activeKey,
  124 + register,
  125 + closeDrawer,
  126 + deviceDetail,
  127 + deviceDetailRef,
  128 + tbDeviceId,
  129 + handleOpenTbDeviceDetail,
  130 + handleOpenGatewayDevice,
  131 + };
  132 + },
  133 + });
  134 +</script>
... ...
  1 +import { findDictItemByCode } from '/@/api/system/dict';
  2 +import { BasicColumn, FormSchema } from '/@/components/Table';
  3 +
  4 +export const columnSchema: BasicColumn[] = [
  5 + {
  6 + title: '时间',
  7 + dataIndex: 'time',
  8 + },
  9 + {
  10 + title: '标识符',
  11 + dataIndex: 'identifier',
  12 + helpMessage: ['标识符格式为模块标识符: 功能定义标识符'],
  13 + },
  14 + {
  15 + title: '事件名称',
  16 + dataIndex: 'eventName',
  17 + },
  18 + {
  19 + title: '事件类型',
  20 + dataIndex: 'eventType',
  21 + },
  22 + {
  23 + title: '输出参数',
  24 + dataIndex: 'outputParams',
  25 + slots: { customRender: 'outputParams' },
  26 + },
  27 +];
  28 +
  29 +export const formSchemas: FormSchema[] = [
  30 + {
  31 + field: 'identifier',
  32 + label: '标识符',
  33 + component: 'Input',
  34 + },
  35 + {
  36 + field: 'alarmType',
  37 + label: '告警类型',
  38 + component: 'ApiSelect',
  39 + defaultValue: 'INFO',
  40 + componentProps: {
  41 + placeholder: '请选择事件类型',
  42 + api: findDictItemByCode,
  43 + params: {
  44 + dictCode: 'event_type',
  45 + },
  46 + labelField: 'itemText',
  47 + valueField: 'itemValue',
  48 + },
  49 + },
  50 + {
  51 + field: 'dateRange',
  52 + label: '时间范围',
  53 + component: 'RangePicker',
  54 + colProps: { span: 10 },
  55 + },
  56 +];
... ...
  1 +<script lang="ts" setup>
  2 + import { BasicTable, useTable } from '/@/components/Table';
  3 + import { formSchemas, columnSchema } from './config';
  4 + import { BasicModal, useModal } from '/@/components/Modal';
  5 + import { Textarea } from 'ant-design-vue';
  6 + import { ref } from 'vue';
  7 + import { formatToDateTime } from '/@/utils/dateUtil';
  8 + import { EyeOutlined } from '@ant-design/icons-vue';
  9 +
  10 + const outputData = ref<string>();
  11 +
  12 + const [register] = useTable({
  13 + columns: columnSchema,
  14 + size: 'small',
  15 + showIndexColumn: false,
  16 + useSearchForm: true,
  17 + showTableSetting: true,
  18 + bordered: true,
  19 + dataSource: [
  20 + {
  21 + time: formatToDateTime(new Date()),
  22 + identifier: '标识符',
  23 + eventName: '事件名',
  24 + eventType: '告警',
  25 + outputParams: { test: 1 },
  26 + },
  27 + ],
  28 + formConfig: {
  29 + layout: 'inline',
  30 + baseColProps: { span: 6 },
  31 + labelWidth: 80,
  32 + schemas: formSchemas,
  33 + },
  34 + handleSearchInfoFn: (params: Recordable) => {
  35 + // console.log(params);
  36 + return params;
  37 + },
  38 + });
  39 +
  40 + const [registerModal, { openModal }] = useModal();
  41 +
  42 + const handleViewDetail = () => {
  43 + outputData.value = JSON.stringify(
  44 + {
  45 + test: '123',
  46 + },
  47 + null,
  48 + 2
  49 + );
  50 + openModal(true);
  51 + };
  52 +</script>
  53 +
  54 +<template>
  55 + <BasicTable class="event-manage-table" @register="register">
  56 + <template #outputParams>
  57 + <span class="cursor-pointer text-blue-500" @click="handleViewDetail">
  58 + <EyeOutlined class="svg:text-blue-500" />
  59 + <span class="ml-2">详情</span>
  60 + </span>
  61 + </template>
  62 + </BasicTable>
  63 + <BasicModal title="输出参数" @register="registerModal">
  64 + <Textarea v-model:value="outputData" :autosize="true" />
  65 + </BasicModal>
  66 +</template>
  67 +
  68 +<style lang="less" scoped>
  69 + .event-manage-table {
  70 + background-color: #f0f2f5;
  71 + }
  72 +</style>
... ...
1   -<template>
2   - <div style="background-color: #f0f2f5">
3   - <BasicTable @register="registerTable">
4   - <template #recordContent="{ record }">
5   - <a-button type="link" class="ml-2" @click="handleRecordContent(record)"> 查看 </a-button>
6   - </template>
7   - <template #responseContent="{ record }">
8   - <div v-if="!record.request?.oneway">
9   - <a-button v-if="record?.response === null" type="text" class="ml-2"> 无 </a-button>
10   - <a-button v-else type="link" class="ml-2" @click="handleRecordResponseContent(record)">
11   - 查看
12   - </a-button>
13   - </div>
14   - </template>
15   - </BasicTable>
16   - </div>
17   -</template>
18   -<script lang="ts" setup>
19   - import { h } from 'vue';
20   - import { configColumns } from './config';
21   - import { deviceCommandRecordGetQuery } from '/@/api/device/deviceConfigApi';
22   - import { BasicTable, useTable } from '/@/components/Table';
23   - import { Modal } from 'ant-design-vue';
24   - import { JsonPreview } from '/@/components/CodeEditor';
25   -
26   - const props = defineProps({
27   - fromId: {
28   - type: String,
29   - default: '',
30   - },
31   - });
32   - const [registerTable] = useTable({
33   - api: deviceCommandRecordGetQuery,
34   - columns: configColumns,
35   - beforeFetch: (params) => {
36   - return {
37   - ...params,
38   - tbDeviceId: props.fromId,
39   - };
40   - },
41   - showTableSetting: true,
42   - bordered: true,
43   - showIndexColumn: false,
44   - });
45   - const commonModalInfo = (title, value) => {
46   - Modal.info({
47   - title,
48   - width: 600,
49   - content: h(JsonPreview, { data: value }),
50   - });
51   - };
52   - const handleRecordContent = (record) => {
53   - if (!record?.request?.body?.params) return;
54   - //如果是正常格式则返回params,否则输入什么内容则显示什么内容
55   - const jsonParams = JSON.parse(record?.request?.body?.params);
56   - commonModalInfo('命令下发内容', jsonParams?.params ? jsonParams?.params : jsonParams);
57   - };
58   - const handleRecordResponseContent = (record) => {
59   - const jsonParams = record?.response;
60   - commonModalInfo('响应结果', jsonParams);
61   - };
62   -</script>
  1 +<template>
  2 + <BasicTable class="command-record-table" @register="registerTable">
  3 + <template #recordContent="{ record }">
  4 + <a-button type="link" class="ml-2" @click="handleRecordContent(record)"> 查看 </a-button>
  5 + </template>
  6 + <template #responseContent="{ record }">
  7 + <div v-if="!record.request?.oneway">
  8 + <a-button v-if="record?.response === null" type="text" class="ml-2"> 无 </a-button>
  9 + <a-button v-else type="link" class="ml-2" @click="handleRecordResponseContent(record)">
  10 + 查看
  11 + </a-button>
  12 + </div>
  13 + </template>
  14 + </BasicTable>
  15 +</template>
  16 +<script lang="ts" setup>
  17 + import { h } from 'vue';
  18 + import { configColumns } from './config';
  19 + import { deviceCommandRecordGetQuery } from '/@/api/device/deviceConfigApi';
  20 + import { BasicTable, useTable } from '/@/components/Table';
  21 + import { Modal } from 'ant-design-vue';
  22 + import { JsonPreview } from '/@/components/CodeEditor';
  23 +
  24 + const props = defineProps({
  25 + fromId: {
  26 + type: String,
  27 + default: '',
  28 + },
  29 + });
  30 + const [registerTable] = useTable({
  31 + api: deviceCommandRecordGetQuery,
  32 + columns: configColumns,
  33 + beforeFetch: (params) => {
  34 + return {
  35 + ...params,
  36 + tbDeviceId: props.fromId,
  37 + };
  38 + },
  39 + showTableSetting: true,
  40 + bordered: true,
  41 + showIndexColumn: false,
  42 + });
  43 + const commonModalInfo = (title, value) => {
  44 + Modal.info({
  45 + title,
  46 + width: 600,
  47 + content: h(JsonPreview, { data: value }),
  48 + });
  49 + };
  50 + const handleRecordContent = (record) => {
  51 + if (!record?.request?.body?.params) return;
  52 + //如果是正常格式则返回params,否则输入什么内容则显示什么内容
  53 + const jsonParams = JSON.parse(record?.request?.body?.params);
  54 + commonModalInfo('命令下发内容', jsonParams?.params ? jsonParams?.params : jsonParams);
  55 + };
  56 + const handleRecordResponseContent = (record) => {
  57 + const jsonParams = record?.response;
  58 + commonModalInfo('响应结果', jsonParams);
  59 + };
  60 +</script>
  61 +
  62 +<style lang="less" scoped>
  63 + .command-record-table {
  64 + background-color: #f0f2f5;
  65 + padding: 16px;
  66 + }
  67 +</style>
... ...
... ... @@ -27,17 +27,26 @@
27 27 <TabPane :key="FunctionType.SERVICE" :disabled="isTCPGatewaySubDevice" tab="服务" />
28 28 <TabPane :key="FunctionType.EVENTS" tab="事件" :disabled="isTCPGatewaySubDevice" />
29 29 </Tabs>
30   - <Attribute v-if="activeKey === FunctionType.PROPERTIES" ref="AttrRef" />
  30 + <Attribute
  31 + v-if="activeKey === FunctionType.PROPERTIES"
  32 + :openModalMode="openModalMode"
  33 + ref="AttrRef"
  34 + />
31 35 <Service
32 36 v-if="activeKey === FunctionType.SERVICE"
33 37 :record="$props.record"
  38 + :openModalMode="openModalMode"
34 39 ref="ServiceRef"
35 40 />
36   - <Events v-if="activeKey === FunctionType.EVENTS" ref="EventsRef" />
37   - <div
  41 + <Events
  42 + v-if="activeKey === FunctionType.EVENTS"
  43 + :openModalMode="openModalMode"
  44 + ref="EventsRef"
  45 + />
  46 + <!-- <div
38 47 v-if="openModalMode === OpenModelMode.VIEW"
39 48 class="absolute w-full h-full top-0 cursor-not-allowed z-50"
40   - ></div>
  49 + ></div> -->
41 50 </div>
42 51 </BasicModal>
43 52 </div>
... ... @@ -116,6 +125,9 @@
116 125 const title = unref(openModalMode) === OpenModelMode.UPDATE ? '编辑物模型' : '新增物模型';
117 126 setModalProps({ title, showOkBtn: true, showCancelBtn: true });
118 127 }
  128 + AttrRef.value?.setDisable(unref(openModalMode) === OpenModelMode.VIEW);
  129 + EventsRef.value?.setDisable(unref(openModalMode) === OpenModelMode.VIEW);
  130 + ServiceRef.value?.setDisable(unref(openModalMode) === OpenModelMode.VIEW);
119 131 }
120 132 );
121 133
... ... @@ -153,7 +165,7 @@
153 165 closeModal();
154 166 emit('success');
155 167 } catch (error) {
156   - throw Error(error);
  168 + throw Error(error as string);
157 169 } finally {
158 170 setModalProps({ loading: false, okButtonProps: { loading: false } });
159 171 }
... ...
... ... @@ -4,18 +4,20 @@
4 4 <script lang="ts" setup>
5 5 import { BasicForm, useForm } from '/@/components/Form';
6 6 import { DataType, ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
7   - import { formSchemas } from '/@/components/Form/src/externalCompns/components/StructForm/config';
8 7 import { StructFormValue } from '/@/components/Form/src/externalCompns/components/StructForm/type';
9 8 import {
10 9 transfromToStructJSON,
11 10 excludeIdInStructJSON,
12 11 } from '/@/components/Form/src/externalCompns/components/StructForm/util';
13   - import { FunctionType } from './config';
  12 + import { FunctionType, attributeSchema } from './config';
14 13 import { isArray } from 'lodash';
  14 + import { OpenModelMode } from '../types';
15 15
16   - const [register, { validate, resetFields, setFieldsValue }] = useForm({
  16 + defineProps<{ openModalMode: OpenModelMode }>();
  17 +
  18 + const [register, { validate, resetFields, setFieldsValue, setProps }] = useForm({
17 19 labelWidth: 100,
18   - schemas: formSchemas,
  20 + schemas: attributeSchema,
19 21 actionColOptions: {
20 22 span: 14,
21 23 },
... ... @@ -24,6 +26,10 @@
24 26 showActionButtonGroup: false,
25 27 });
26 28
  29 + const setDisable = (flag: boolean) => {
  30 + setProps({ disabled: flag });
  31 + };
  32 +
27 33 async function getFormData(): Promise<Partial<ModelOfMatterParams>> {
28 34 const _values = (await validate()) as StructFormValue;
29 35 if (!_values) return {};
... ... @@ -68,6 +74,7 @@
68 74 resetFormData,
69 75 getFormData,
70 76 setFormData,
  77 + setDisable,
71 78 });
72 79 </script>
73 80 <style lang="less" scoped></style>
... ...
... ... @@ -7,8 +7,11 @@
7 7 import { ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel';
8 8 import { StructFormValue } from '/@/components/Form/src/externalCompns/components/StructForm/type';
9 9 import { excludeIdInStructJSON } from '/@/components/Form/src/externalCompns/components/StructForm/util';
  10 + import { OpenModelMode } from '../types';
10 11
11   - const [register, { validate, resetFields, setFieldsValue }] = useForm({
  12 + defineProps<{ openModalMode: OpenModelMode }>();
  13 +
  14 + const [register, { validate, resetFields, setFieldsValue, setProps }] = useForm({
12 15 labelWidth: 100,
13 16 schemas: eventSchemas,
14 17 actionColOptions: {
... ... @@ -19,6 +22,10 @@
19 22 showActionButtonGroup: false,
20 23 });
21 24
  25 + const setDisable = (flag: boolean) => {
  26 + setProps({ disabled: flag });
  27 + };
  28 +
22 29 //回显数据
23 30 const setFormData = (record: ModelOfMatterParams) => {
24 31 const { functionJson = {}, functionName, identifier, remark, eventType } = record;
... ... @@ -69,6 +76,7 @@
69 76 setFormData,
70 77 resetFormData,
71 78 getFormData,
  79 + setDisable,
72 80 });
73 81 </script>
74 82 <style lang="less" scoped></style>
... ...
... ... @@ -9,22 +9,29 @@
9 9 import { ModelOfMatterParams, StructJSON } from '/@/api/device/model/modelOfMatterModel';
10 10 import { DeviceRecord } from '/@/api/device/model/deviceModel';
11 11 import { excludeIdInStructJSON } from '/@/components/Form/src/externalCompns/components/StructForm/util';
  12 + import { OpenModelMode } from '../types';
12 13
13 14 const props = defineProps<{
14 15 record: DeviceRecord;
  16 + openModalMode: OpenModelMode;
15 17 }>();
16 18
17   - const [register, { validate, resetFields, setFieldsValue }] = useForm({
  19 + const [register, { validate, resetFields, setFieldsValue, setProps }] = useForm({
18 20 labelWidth: 100,
19 21 schemas: serviceSchemas(props.record.transportType === 'TCP'),
20 22 actionColOptions: {
21 23 span: 14,
22 24 },
  25 + disabled: props.openModalMode === OpenModelMode.VIEW,
23 26 showResetButton: false,
24 27 submitOnReset: false,
25 28 showActionButtonGroup: false,
26 29 });
27 30
  31 + const setDisable = (flag: boolean) => {
  32 + setProps({ disabled: flag });
  33 + };
  34 +
28 35 //回显数据
29 36 const setFormData = (record: ModelOfMatterParams) => {
30 37 const { functionJson = {}, functionName, identifier, remark, callType } = record;
... ... @@ -98,6 +105,7 @@
98 105 setFormData,
99 106 resetFormData,
100 107 getFormData,
  108 + setDisable,
101 109 });
102 110 </script>
103 111 <style lang="less" scoped></style>
... ...
1 1 import { FormSchema } from '/@/components/Table';
2 2 import { findDictItemByCode } from '/@/api/system/dict';
  3 +import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  4 +
  5 +export const validateValueRange = (_rule, value: Record<'min' | 'max', number>, _callback) => {
  6 + value = value || {};
  7 + const { min, max } = value;
  8 + if (min >= max) {
  9 + return Promise.reject('最大值小于最小值');
  10 + }
  11 + return Promise.resolve();
  12 +};
  13 +
  14 +export const validateJSON = (_rule, value: ModelOfMatterParams[], _callback) => {
  15 + if (value.length) {
  16 + return Promise.resolve();
  17 + }
  18 + return Promise.reject('JSON对象不能为空');
  19 +};
3 20
4 21 export enum FormField {
5 22 FUNCTION_NAME = 'functionName',
... ... @@ -358,3 +375,265 @@ export const addParamsSchemas: FormSchema[] = [
358 375 ifShow: ({ values }) => isNumber(values[FormField.TYPE]),
359 376 },
360 377 ];
  378 +
  379 +export const attributeSchema: FormSchema[] = [
  380 + {
  381 + field: FormField.FUNCTION_NAME,
  382 + label: '功能名称',
  383 + required: true,
  384 + component: 'Input',
  385 + colProps: {
  386 + span: 18,
  387 + },
  388 + componentProps: {
  389 + maxLength: 255,
  390 + placeholder: '请输入功能名称',
  391 + },
  392 + },
  393 + {
  394 + field: FormField.IDENTIFIER,
  395 + label: '标识符',
  396 + required: true,
  397 + component: 'Input',
  398 + colProps: {
  399 + span: 18,
  400 + },
  401 + componentProps: {
  402 + maxLength: 255,
  403 + placeholder: '请输入标识符',
  404 + },
  405 + },
  406 + {
  407 + field: FormField.TYPE,
  408 + label: '数据类型',
  409 + required: true,
  410 + component: 'ApiSelect',
  411 + colProps: {
  412 + span: 9,
  413 + },
  414 + defaultValue: 'INT',
  415 + componentProps: {
  416 + placeholder: '请选择数据类型',
  417 + api: findDictItemByCode,
  418 + params: {
  419 + dictCode: 'data_type',
  420 + },
  421 + labelField: 'itemText',
  422 + valueField: 'itemValue',
  423 + getPopupContainer: () => document.body,
  424 + },
  425 + },
  426 + {
  427 + field: FormField.VALUE_RANGE,
  428 + label: '取值范围',
  429 + component: 'CustomMinMaxInput',
  430 + valueField: 'value',
  431 + changeEvent: 'update:value',
  432 + colProps: {
  433 + span: 18,
  434 + },
  435 + ifShow: ({ values }) =>
  436 + values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_INT ||
  437 + values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_DOUBLE,
  438 + rules: [{ validator: validateValueRange }],
  439 + },
  440 + {
  441 + field: FormField.STEP,
  442 + label: '步长',
  443 + component: 'InputNumber',
  444 + colProps: {
  445 + span: 18,
  446 + },
  447 + componentProps: {
  448 + maxLength: 255,
  449 + placeholder: '请输入步长',
  450 + min: 1,
  451 + formatter: (value: number | string) => {
  452 + return value ? Math.floor(Number(value)) : value;
  453 + },
  454 + },
  455 + ifShow: ({ values }) =>
  456 + values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_INT ||
  457 + values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_DOUBLE,
  458 + dynamicRules: ({ model }) => {
  459 + const valueRange = model[FormField.VALUE_RANGE] || {};
  460 + const { min = 0, max = 0 } = valueRange;
  461 + const step = model[FormField.STEP];
  462 + return [
  463 + {
  464 + validator: () => {
  465 + if (step > max - min) {
  466 + return Promise.reject('步长不能大于取值范围的差值');
  467 + }
  468 + return Promise.resolve();
  469 + },
  470 + },
  471 + ];
  472 + },
  473 + },
  474 + {
  475 + field: FormField.UNIT_NAME,
  476 + label: '单位名称',
  477 + component: 'Input',
  478 + show: false,
  479 + },
  480 + {
  481 + field: FormField.UNIT,
  482 + label: '单位',
  483 + component: 'ApiSelect',
  484 + colProps: {
  485 + span: 9,
  486 + },
  487 + componentProps: ({ formActionType }) => {
  488 + const { setFieldsValue } = formActionType;
  489 + return {
  490 + placeholder: '请选择单位',
  491 + api: async (params) => {
  492 + const list = await findDictItemByCode(params);
  493 + list.map((item) => (item.itemText = `${item.itemText} / ${item.itemValue}`));
  494 + return list;
  495 + },
  496 + params: {
  497 + dictCode: 'attribute_unit',
  498 + },
  499 + labelInValue: true,
  500 + labelField: 'itemText',
  501 + valueField: 'itemValue',
  502 + onChange(_, record: Record<'label' | 'value', string>) {
  503 + if (record) {
  504 + const { label } = record;
  505 + setFieldsValue({ [FormField.UNIT_NAME]: label });
  506 + }
  507 + },
  508 + getPopupContainer: () => document.body,
  509 + showSearch: true,
  510 + filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => {
  511 + let { label, value } = option;
  512 + label = label.toLowerCase();
  513 + value = value.toLowerCase();
  514 + inputValue = inputValue.toLowerCase();
  515 + return label.includes(inputValue) || value.includes(inputValue);
  516 + },
  517 + };
  518 + },
  519 + ifShow: ({ values }) =>
  520 + values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_INT ||
  521 + values[FormField.TYPE] === DataTypeEnum.IS_NUMBER_DOUBLE,
  522 + },
  523 + {
  524 + field: FormField.BOOL_CLOSE,
  525 + component: 'Input',
  526 + required: true,
  527 + label: '0 -',
  528 + colProps: {
  529 + span: 18,
  530 + },
  531 + componentProps: {
  532 + placeholder: '如:关',
  533 + },
  534 + defaultValue: '关',
  535 + ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.IS_BOOL,
  536 + dynamicRules: ({ model }) => {
  537 + const close = model[FormField.BOOL_CLOSE];
  538 + const open = model[FormField.BOOL_OPEN];
  539 + return [
  540 + {
  541 + required: true,
  542 + },
  543 + {
  544 + validator() {
  545 + if (open === close) return Promise.reject('布尔值不能相同');
  546 + return Promise.resolve();
  547 + },
  548 + },
  549 + ];
  550 + },
  551 + },
  552 + {
  553 + field: FormField.BOOL_OPEN,
  554 + component: 'Input',
  555 + required: true,
  556 + label: '1 -',
  557 + colProps: {
  558 + span: 18,
  559 + },
  560 + componentProps: {
  561 + placeholder: '如:开',
  562 + },
  563 + defaultValue: '开',
  564 + ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.IS_BOOL,
  565 + dynamicRules: ({ model }) => {
  566 + const close = model[FormField.BOOL_CLOSE];
  567 + const open = model[FormField.BOOL_OPEN];
  568 + return [
  569 + {
  570 + required: true,
  571 + },
  572 + {
  573 + validator() {
  574 + if (open === close) return Promise.reject('布尔值不能相同');
  575 + return Promise.resolve();
  576 + },
  577 + },
  578 + ];
  579 + },
  580 + },
  581 + {
  582 + field: FormField.LENGTH,
  583 + component: 'Input',
  584 + required: true,
  585 + label: '数据长度',
  586 + defaultValue: '10240',
  587 + colProps: {
  588 + span: 8,
  589 + },
  590 + componentProps: {
  591 + placeholder: '请输入数据长度',
  592 + },
  593 + renderComponentContent: () => {
  594 + return {
  595 + suffix: () => '字节',
  596 + };
  597 + },
  598 + ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.IS_STRING,
  599 + },
  600 + {
  601 + field: FormField.ACCESS_MODE,
  602 + component: 'ApiRadioGroup',
  603 + label: '读写类型',
  604 + required: true,
  605 + colProps: {
  606 + span: 24,
  607 + },
  608 + defaultValue: 'r',
  609 + componentProps: {
  610 + placeholder: '请选择读写类型',
  611 + api: findDictItemByCode,
  612 + params: {
  613 + dictCode: 'read_write_type',
  614 + },
  615 + labelField: 'itemText',
  616 + valueField: 'itemValue',
  617 + },
  618 + },
  619 + {
  620 + field: FormField.SPECS_LIST,
  621 + label: 'JSON对象',
  622 + component: 'StructForm',
  623 + valueField: 'value',
  624 + changeEvent: 'update:value',
  625 + colProps: { span: 24 },
  626 + ifShow: ({ values }) => values[FormField.TYPE] === DataTypeEnum.IS_STRUCT,
  627 + rules: [{ required: true, validator: validateJSON }],
  628 + },
  629 + {
  630 + field: FormField.REFARK,
  631 + label: '备注',
  632 + component: 'InputTextArea',
  633 + componentProps: {
  634 + rows: 4,
  635 + maxLength: 100,
  636 + placeholder: '请输入描述',
  637 + },
  638 + },
  639 +];
... ...