Commit a189f5fa9e07055afdc1968c8b5ea00e669d7e63

Authored by ww
1 parent 147055d4

perf: 产品详情物模型修复查看时不能查看物模型绑定属性

... ... @@ -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 },
... ...
... ... @@ -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 +];
... ...