Commit 0fe77900fc8adcb0f9f9542cc8a22350284e968a

Authored by xp.Huang
2 parents abd96090 33944534

Merge branch 'ww' into 'main'

feat: 场景联动服务调用新增根据物模型服务配置下发参数表单

See merge request yunteng/thingskit-front!495
... ... @@ -40,6 +40,7 @@ import StructForm from './externalCompns/components/StructForm/StructForm.vue';
40 40 import ApiSelectScrollLoad from './components/ApiSelectScrollLoad.vue';
41 41 import TransferModal from './components/TransferModal.vue';
42 42 import TransferTableModal from './components/TransferTableModal.vue';
  43 +import ObjectModelValidateForm from './externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue';
43 44
44 45 const componentMap = new Map<ComponentType, Component>();
45 46
... ... @@ -87,6 +88,7 @@ componentMap.set('StructForm', StructForm);
87 88 componentMap.set('ApiSelectScrollLoad', ApiSelectScrollLoad);
88 89 componentMap.set('TransferModal', TransferModal);
89 90 componentMap.set('TransferTableModal', TransferTableModal);
  91 +componentMap.set('ObjectModelValidateForm', ObjectModelValidateForm);
90 92
91 93 export function add(compName: ComponentType, component: Component) {
92 94 componentMap.set(compName, component);
... ...
  1 +<script lang="ts" setup>
  2 + import { Card } from 'ant-design-vue';
  3 + import { nextTick, onBeforeUpdate, onUpdated } from 'vue';
  4 + import { DataTypeEnum } from '../StructForm/config';
  5 + import { BasicCreateFormParams } from './type';
  6 + import { DynamicProps } from '/#/utils';
  7 + import { Specs, StructJSON } from '/@/api/device/model/modelOfMatterModel';
  8 + import { BasicForm, FormProps, FormSchema, useForm } from '/@/components/Form';
  9 +
  10 + const props = withDefaults(
  11 + defineProps<{
  12 + inputData?: StructJSON[];
  13 + formProps?: FormProps;
  14 + value?: Recordable;
  15 + }>(),
  16 + {
  17 + inputData: () => [] as StructJSON[],
  18 + formProps: () => ({}),
  19 + value: () => ({}),
  20 + }
  21 + );
  22 +
  23 + const emit = defineEmits(['update:value']);
  24 +
  25 + const [register, { setProps, getFieldsValue, setFieldsValue }] = useForm({
  26 + schemas: [],
  27 + showActionButtonGroup: false,
  28 + layout: 'inline',
  29 + labelWidth: 80,
  30 + wrapperCol: { span: 12 },
  31 + ...(props.formProps || ({} as unknown as Partial<DynamicProps<FormProps>>)),
  32 + });
  33 +
  34 + const syncValue = (key: string, value: any) => {
  35 + const record = getFieldsValue();
  36 + emit('update:value', { ...record, [key]: value });
  37 + };
  38 +
  39 + const createInputNumber = ({
  40 + identifier,
  41 + functionName,
  42 + specs,
  43 + }: BasicCreateFormParams): FormSchema => {
  44 + const { valueRange } = specs! as Partial<Specs>;
  45 + const { max = 2147483647, min = -2147483648 } = valueRange || {};
  46 + return {
  47 + field: identifier,
  48 + label: functionName,
  49 + component: 'InputNumber',
  50 + rules: [
  51 + {
  52 + type: 'number',
  53 + trigger: 'change',
  54 + validator: (_rule, value) => {
  55 + if (value < min || value > max) {
  56 + return Promise.reject(`${functionName}取值范围在${min}~${max}之间`);
  57 + }
  58 + return Promise.resolve(value);
  59 + },
  60 + },
  61 + ],
  62 + componentProps: {
  63 + max,
  64 + min,
  65 + // step: step,
  66 + // formatter: (value: string) => value,
  67 + // parser: (string: string) => {
  68 + // if (dataType === DataTypeEnum.IS_NUMBER_INT) {
  69 + // return Number(Number(string).toFixed());
  70 + // }
  71 + // return Number(string);
  72 + // },
  73 + onChange: (value: string) => {
  74 + syncValue(identifier, value);
  75 + },
  76 + },
  77 + } as FormSchema;
  78 + };
  79 +
  80 + const createInput = ({ identifier, functionName, specs }: BasicCreateFormParams): FormSchema => {
  81 + const { length = 10240 } = specs! as Partial<Specs>;
  82 + return {
  83 + field: identifier,
  84 + label: functionName,
  85 + component: 'Input',
  86 + rules: [
  87 + {
  88 + type: 'string',
  89 + trigger: 'change',
  90 + validator: (_rule, value) => {
  91 + if (value.length > length) {
  92 + return Promise.reject(`${functionName}数据长度应该小于${length}`);
  93 + }
  94 + return Promise.resolve(value);
  95 + },
  96 + },
  97 + ],
  98 + componentProps: {
  99 + maxLength: length,
  100 + onChange: (value: InputEvent) => {
  101 + syncValue(identifier, (value.target as HTMLInputElement).value);
  102 + },
  103 + },
  104 + } as FormSchema;
  105 + };
  106 +
  107 + const createSelect = ({ identifier, functionName, specs }: BasicCreateFormParams): FormSchema => {
  108 + const { boolClose, boolOpen } = specs! as Partial<Specs>;
  109 + return {
  110 + field: identifier,
  111 + label: functionName,
  112 + component: 'Select',
  113 + componentProps: {
  114 + options: [
  115 + { label: `${boolClose}-0`, value: 0 },
  116 + { label: `${boolOpen}-0`, value: 1 },
  117 + ],
  118 + onChange: (value: string) => {
  119 + syncValue(identifier, value);
  120 + },
  121 + },
  122 + };
  123 + };
  124 +
  125 + const createInputJson = ({ identifier, functionName }: BasicCreateFormParams): FormSchema => {
  126 + return {
  127 + field: identifier,
  128 + label: functionName,
  129 + component: 'InputTextArea',
  130 + componentProps: {
  131 + onChange: (value: InputEvent) => {
  132 + syncValue(identifier, (value.target as HTMLInputElement).value);
  133 + },
  134 + },
  135 + };
  136 + };
  137 +
  138 + const transformToFormSchema = (inputData: StructJSON[]) => {
  139 + const schemas: FormSchema[] = [];
  140 + for (const item of inputData) {
  141 + const { dataType, identifier, functionName } = item;
  142 + const { type, specs } = dataType! || {};
  143 +
  144 + const params: BasicCreateFormParams = {
  145 + identifier: identifier!,
  146 + functionName: functionName!,
  147 + dataType: dataType! as unknown as DataTypeEnum,
  148 + specs: specs as Partial<Specs>,
  149 + };
  150 + if (type === DataTypeEnum.IS_NUMBER_INT || type === DataTypeEnum.IS_NUMBER_DOUBLE) {
  151 + schemas.push(createInputNumber(params));
  152 + }
  153 +
  154 + if (type === DataTypeEnum.IS_BOOL) {
  155 + schemas.push(createSelect(params));
  156 + }
  157 +
  158 + if (type === DataTypeEnum.IS_STRING) {
  159 + schemas.push(createInput(params));
  160 + }
  161 +
  162 + if (type === DataTypeEnum.IS_STRUCT) {
  163 + schemas.push(createInputJson(params));
  164 + }
  165 + }
  166 +
  167 + return schemas;
  168 + };
  169 +
  170 + onBeforeUpdate(() => {
  171 + if (props.inputData && props.inputData.length) {
  172 + const schemas = transformToFormSchema(props.inputData);
  173 + setProps({ schemas });
  174 + }
  175 + });
  176 +
  177 + onUpdated(async () => {
  178 + if (props.inputData && props.inputData.length) {
  179 + await nextTick();
  180 + setFieldsValue(props.value);
  181 + }
  182 + });
  183 +</script>
  184 +
  185 +<template>
  186 + <Card bordered class="!border-dashed !rounded-lg !border-2px">
  187 + <!-- <Alert class="!mb-4 w-32" message="服务参数配置" type="info" /> -->
  188 + <BasicForm class="object-model-validate-form" @register="register" />
  189 + </Card>
  190 +</template>
  191 +
  192 +<style lang="less">
  193 + .object-model-validate-form {
  194 + .ant-input-number {
  195 + width: 100% !important;
  196 + }
  197 + }
  198 +</style>
... ...
  1 +import { DataTypeEnum } from '../StructForm/config';
  2 +import { Specs } from '/@/api/device/model/modelOfMatterModel';
  3 +
  4 +export interface BasicCreateFormParams {
  5 + identifier: string;
  6 + functionName: string;
  7 + dataType: DataTypeEnum;
  8 + specs: Partial<Specs>;
  9 +}
... ...
... ... @@ -110,6 +110,7 @@
110 110 <StructFormModel
111 111 :has-struct-form="$props.hasStructForm!"
112 112 :disabled="$props.disabled"
  113 + :value-list="getValue"
113 114 @register="registerModal"
114 115 @submit="handleSaveStruct"
115 116 />
... ...
... ... @@ -7,21 +7,28 @@
7 7 import { BasicForm, useForm } from '/@/components/Form';
8 8 import { formSchemas } from './config';
9 9 import { BasicModal, useModalInner } from '/@/components/Modal';
10   - import { OpenModalMode, OpenModalParams } from './type';
  10 + import { OpenModalMode, OpenModalParams, StructRecord } from './type';
11 11 import { ref, unref } from 'vue';
12 12 import { transfromToStructJSON } from './util';
13 13 import { cloneDeep } from 'lodash-es';
14 14 import { DataType, StructJSON } from '/@/api/device/model/modelOfMatterModel';
15 15 import { isArray } from '/@/utils/is';
  16 + import { useMessage } from '/@/hooks/web/useMessage';
16 17
17 18 const modalReceiveRecord = ref<OpenModalParams>({
18 19 mode: OpenModalMode.CREATE,
19 20 });
20 21
21   - const props = defineProps<{ disabled: boolean; hasStructForm: boolean }>();
  22 + const props = defineProps<{
  23 + disabled: boolean;
  24 + hasStructForm: boolean;
  25 + valueList: StructRecord[];
  26 + }>();
22 27
23 28 const emit = defineEmits(['register', 'submit']);
24 29
  30 + const { createMessage } = useMessage();
  31 +
25 32 const [register, { validate, setFieldsValue, setProps }] = useForm({
26 33 labelWidth: 100,
27 34 schemas: formSchemas(props.hasStructForm),
... ... @@ -52,6 +59,10 @@
52 59 setProps({ disabled: props.disabled });
53 60 });
54 61
  62 + const validateRepeat = (value: StructRecord, valueList: StructRecord[]) => {
  63 + return valueList.filter((item) => item.identifier === value.identifier).length >= 1;
  64 + };
  65 +
55 66 const handleSubmit = async () => {
56 67 try {
57 68 const _value = await validate();
... ... @@ -62,6 +73,12 @@
62 73 ? { id: unref(modalReceiveRecord)?.record?.id }
63 74 : {}),
64 75 };
  76 +
  77 + if (validateRepeat(_value, props.valueList)) {
  78 + createMessage.error('存在一致的标识符');
  79 + return;
  80 + }
  81 +
65 82 emit('submit', unref(modalReceiveRecord).mode, cloneDeep(value));
66 83 closeModal();
67 84 } catch (error) {}
... ...
... ... @@ -121,4 +121,5 @@ export type ComponentType =
121 121 | 'StructForm'
122 122 | 'ApiSelectScrollLoad'
123 123 | 'TransferModal'
124   - | 'TransferTableModal';
  124 + | 'TransferTableModal'
  125 + | 'ObjectModelValidateForm';
... ...
... ... @@ -5,19 +5,19 @@ import { findDictItemByCode } from '/@/api/system/dict';
5 5 import { BasicColumn, FormSchema } from '/@/components/Table';
6 6 import { formatToDateTime } from '/@/utils/dateUtil';
7 7
8   -enum EventType {
  8 +export enum EventType {
9 9 ERROR = 'ERROR',
10 10 INFO = 'INFO',
11 11 ALERT = 'ALERT',
12 12 }
13 13
14   -enum EventTypeColor {
  14 +export enum EventTypeColor {
15 15 ERROR = 'error',
16   - INFO = 'warning',
17   - ALERT = 'default',
  16 + INFO = 'success',
  17 + ALERT = 'warning',
18 18 }
19 19
20   -enum EventTypeName {
  20 +export enum EventTypeName {
21 21 ERROR = '故障',
22 22 INFO = '信息',
23 23 ALERT = '告警',
... ...
... ... @@ -8,6 +8,7 @@ import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi';
8 8 import { FormField, FunctionType } from './step/cpns/physical/cpns/config';
9 9 import { h } from 'vue';
10 10 import { Tag } from 'ant-design-vue';
  11 +import { EventType, EventTypeColor, EventTypeName } from '../list/cpns/tabs/EventManage/config';
11 12
12 13 export enum Mode {
13 14 CARD = 'card',
... ... @@ -81,6 +82,19 @@ export const physicalColumn: BasicColumn[] = [
81 82 },
82 83 },
83 84 {
  85 + title: '事件类型',
  86 + dataIndex: 'eventType',
  87 + customRender({ text }) {
  88 + return h(
  89 + Tag,
  90 + {
  91 + color: EventTypeColor[text as EventType],
  92 + },
  93 + () => EventTypeName[text as EventType]
  94 + );
  95 + },
  96 + },
  97 + {
84 98 title: '状态',
85 99 dataIndex: 'status',
86 100 width: 100,
... ...
... ... @@ -567,11 +567,11 @@
567 567 //TODO fengtao
568 568 orgId.value = newValue;
569 569 //TODO fengtao
570   - const data = await getOrganizationAlarmConfig({ organizationId: newValue });
571   - alarmConfigList.value = data.map((item) => ({ label: item.name, value: item.id }));
572 570 setFields(skipUnwrap.triggerItemRefs, true);
573 571 setFields(skipUnwrap.conditionItemRefs, true);
574 572 setFields(skipUnwrap.actionItemRefs, true);
  573 + const data = await getOrganizationAlarmConfig({ organizationId: newValue });
  574 + alarmConfigList.value = data.map((item) => ({ label: item.name, value: item.id }));
575 575 // setFields(skipUnwrap.actionItemRefs, true);
576 576 // console.log(unref(organizationIdRef));
577 577 // setAlarmConfig(skipUnwrap.actionItemRefs, true);
... ...
... ... @@ -20,6 +20,11 @@ export type TOption = {
20 20 value: string;
21 21 };
22 22
  23 +export enum CommandTypeEnum {
  24 + CUSTOM = 0,
  25 + SERVICE = 1,
  26 +}
  27 +
23 28 /**
24 29 * 所使用的枚举值
25 30 */
... ... @@ -575,11 +580,28 @@ export const actionSchema: FormSchema[] = [
575 580 span: 6,
576 581 },
577 582 componentProps: ({ formModel, formActionType }) => {
578   - const { setFieldsValue } = formActionType;
579   - const deviceProfileId = formModel['deviceProfileId'];
  583 + const { updateSchema } = formActionType;
  584 + const deviceProfileId = Reflect.get(formModel, 'deviceProfileId');
  585 + const thingsModelId = Reflect.get(formModel, 'thingsModelId');
580 586 return {
581 587 placeholder: '请选择服务',
582   - api: getModelServices,
  588 + api: async (params: Recordable) => {
  589 + try {
  590 + const record = await getModelServices(params as Record<'deviceProfileId', string>);
  591 + const selected = record.find((item) => item.id === thingsModelId);
  592 + selected &&
  593 + updateSchema({
  594 + field: 'serviceInputValue',
  595 + componentProps: {
  596 + inputData: selected?.functionJson.inputData,
  597 + },
  598 + });
  599 + return record;
  600 + } catch (error) {
  601 + console.error(error);
  602 + return [];
  603 + }
  604 + },
583 605 params: {
584 606 deviceProfileId,
585 607 },
... ... @@ -587,7 +609,15 @@ export const actionSchema: FormSchema[] = [
587 609 valueField: 'id',
588 610 getPopupContainer: () => document.body,
589 611 onChange: (_, options: ModelOfMatterParams) => {
590   - setFieldsValue({ doContext: { ...options.functionJson, callType: options.callType } });
  612 + if (options) {
  613 + // setFieldsValue({ doContext: { ...options.functionJson, callType: options.callType } });
  614 + updateSchema({
  615 + field: 'serviceInputValue',
  616 + componentProps: {
  617 + inputData: options.functionJson.inputData,
  618 + },
  619 + });
  620 + }
591 621 },
592 622 };
593 623 },
... ... @@ -665,6 +695,18 @@ export const actionSchema: FormSchema[] = [
665 695 },
666 696 slot: 'clearAlarm',
667 697 },
  698 + {
  699 + field: 'serviceInputValue',
  700 + component: 'ObjectModelValidateForm',
  701 + label: '',
  702 + changeEvent: 'update:value',
  703 + valueField: 'value',
  704 + show: ({ values }) => values['thingsModelId'],
  705 + colProps: {
  706 + span: 24,
  707 + },
  708 + componentProps: {},
  709 + },
668 710 ];
669 711
670 712 export const alarmScheduleSchemas: FormSchema[] = [
... ...
... ... @@ -103,7 +103,7 @@
103 103 import { BasicForm, useForm } from '/@/components/Form/index';
104 104 import { Tooltip, Select, Checkbox, Card } from 'ant-design-vue';
105 105 import { Icon } from '/@/components/Icon';
106   - import { actionSchema } from '../config/config.data';
  106 + import { actionSchema, CommandTypeEnum } from '../config/config.data';
107 107 import jsoneditor from 'jsoneditor';
108 108 import 'jsoneditor/dist/jsoneditor.min.css';
109 109 import { QuestionCircleOutlined, PlusOutlined } from '@ant-design/icons-vue';
... ... @@ -261,19 +261,26 @@
261 261 //TODO-fengtao-设备验证
262 262 const value = getFieldsValue();
263 263 const doContext = unref(jsonInstance)?.get() || {};
  264 + const serviceInputValue = Reflect.get(value, 'serviceInputValue');
  265 +
264 266 return {
265 267 ...value,
266   - ...(Number(value.commandType) === 0 ? { doContext } : {}),
  268 + ...(Number(value.commandType) === CommandTypeEnum.CUSTOM
  269 + ? { doContext }
  270 + : { doContext: serviceInputValue }),
267 271 clearRule,
268 272 };
269 273 };
270 274
271 275 const setFieldsFormValueFun = (fieldsValue) => {
  276 + const doContext = Reflect.get(fieldsValue, 'doContext');
  277 + const commandType = Reflect.get(fieldsValue, 'commandType');
272 278 setFieldsValue({
273 279 ...fieldsValue,
274 280 ...(isNumber(fieldsValue.commandType)
275 281 ? { commandType: String(fieldsValue.commandType) }
276 282 : {}),
  283 + serviceInputValue: commandType === CommandTypeEnum.SERVICE ? doContext.params || {} : {},
277 284 });
278 285 };
279 286 //ft-add
... ...