Commit 5c3d3140de0128bbcfbc1aba607585019364dedf

Authored by ww
1 parent 0616ee93

wip: product detail model of matter tsl

Showing 27 changed files with 1000 additions and 955 deletions
... ... @@ -43,7 +43,7 @@ VITE_GLOB_CONFIGURATION = /thingskit-drawio
43 43 VITE_CONTENT_SECURITY_POLICY = false
44 44
45 45 # Alarm Notify Polling Interval Time
46   -VITE_ALARM_NOTIFY_POLLING_INTERVAL_TIME = 5000
  46 +VITE_ALARM_NOTIFY_POLLING_INTERVAL_TIME = 500000
47 47
48 48 # Alarm Notify Auto Close Time Unit is Second
49 49 VITE_ALARM_NOTIFY_DURATION = 5
... ...
... ... @@ -48,3 +48,40 @@ export interface DeviceProfileModel {
48 48 export type ChildDeviceParams = BasicPageParams & {
49 49 formId: string;
50 50 };
  51 +
  52 +export interface Configuration {
  53 + type: string;
  54 +}
  55 +
  56 +export interface TransportConfiguration {
  57 + type: string;
  58 +}
  59 +
  60 +export interface ProvisionConfiguration {
  61 + type: string;
  62 + provisionDeviceSecret?: any;
  63 +}
  64 +
  65 +export interface ProfileData {
  66 + configuration: Configuration;
  67 + transportConfiguration: TransportConfiguration;
  68 + provisionConfiguration: ProvisionConfiguration;
  69 + alarms?: any;
  70 +}
  71 +
  72 +export interface DeviceRecord {
  73 + id: string;
  74 + creator: string;
  75 + createTime: string;
  76 + name: string;
  77 + tenantId: string;
  78 + transportType: string;
  79 + provisionType: string;
  80 + deviceType: string;
  81 + tbProfileId: string;
  82 + profileData: ProfileData;
  83 + defaultQueueName: string;
  84 + image: string;
  85 + type: string;
  86 + default: boolean;
  87 +}
... ...
  1 +import { FunctionType } from '/@/views/device/profiles/step/cpns/physical/cpns/config';
  2 +
  3 +export interface Specs {
  4 + min: string;
  5 + max: string;
  6 + unit: string;
  7 + unitName: string;
  8 + step: string;
  9 + length: string;
  10 + boolOpen: string;
  11 + boolClose: string;
  12 +}
  13 +
  14 +export interface FunctionJson {
  15 + type: string;
  16 + specs?: Partial<Specs>;
  17 + specsList?: ModelOfMatterParams[];
  18 +}
  19 +
  20 +export interface ModelOfMatterParams {
  21 + deviceProfileId: string;
  22 + functionJson: FunctionJson;
  23 + functionName: string;
  24 + functionType: FunctionType;
  25 + identifier: string;
  26 + remark: string;
  27 + id?: string;
  28 +}
  29 +
  30 +export interface GetModelTslParams {
  31 + functionType: FunctionType;
  32 + deviceProfileId: string;
  33 +}
... ...
  1 +import { BasicPageParams } from '../model/baseModel';
  2 +import { GetModelTslParams, ModelOfMatterParams } from './model/modelOfMatterModel';
  3 +import { defHttp } from '/@/utils/http/axios';
  4 +
  5 +enum ModelOfMatter {
  6 + CREATE = '/things_model',
  7 + UPDATE = '/things_model',
  8 + DELETE = '/things_model',
  9 + TSL = '/things_model',
  10 + LIST = '/things_model/page',
  11 +}
  12 +
  13 +export const getModelList = (params: BasicPageParams) => {
  14 + return defHttp.get({
  15 + url: `${ModelOfMatter.LIST}`,
  16 + params,
  17 + });
  18 +};
  19 +
  20 +export const getModelTsl = (params: GetModelTslParams) => {
  21 + const { functionType, deviceProfileId } = params;
  22 + return defHttp.get({
  23 + url: `${ModelOfMatter.TSL}/${functionType}/${deviceProfileId}`,
  24 + });
  25 +};
  26 +
  27 +export const createModel = (params: Partial<ModelOfMatterParams>) => {
  28 + return defHttp.post({
  29 + url: ModelOfMatter.CREATE,
  30 + params,
  31 + });
  32 +};
  33 +
  34 +export const updateModel = (params: Partial<ModelOfMatterParams>) => {
  35 + return defHttp.put({
  36 + url: ModelOfMatter.UPDATE,
  37 + params,
  38 + });
  39 +};
  40 +
  41 +export const deleteModel = (params: string[]) => {
  42 + return defHttp.delete({
  43 + url: ModelOfMatter.DELETE,
  44 + params: {
  45 + ids: params,
  46 + },
  47 + });
  48 +};
... ...
... ... @@ -20,7 +20,7 @@ enum SysDictApi {
20 20 * @param code
21 21 */
22 22 export const findDictItemByCode = (params?: DictCodeParams) => {
23   - return defHttp.post<SysDictItemResult>({
  23 + return defHttp.post<SysDictItemResult[]>({
24 24 url: SysDictApi.CONFIG_ITEM_URL + '/find',
25 25 params,
26 26 });
... ...
... ... @@ -12,6 +12,8 @@ export { default as ApiTreeSelect } from './src/components/ApiTreeSelect.vue';
12 12 export { default as ApiRadioGroup } from './src/components/ApiRadioGroup.vue';
13 13 export { default as ApiUpload } from './src/components/ApiUpload.vue';
14 14
  15 +export { default as StructForm } from './src/externalCompns/components/StructForm/StructForm.vue';
  16 +
15 17 //注册自定义组件
16 18 export {
17 19 JEasyCron,
... ...
... ... @@ -35,7 +35,8 @@ import ColorPicker from './components/ColorPicker.vue';
35 35 import IconDrawer from './components/IconDrawer.vue';
36 36 import ApiUpload from './components/ApiUpload.vue';
37 37 import ApiSearchSelect from './components/ApiSearchSelect.vue';
38   -import CustomeMinMaxInput from './externalCompns/components/CustomeMinMaxInput.vue';
  38 +import CustomMinMaxInput from './externalCompns/components/CustomMinMaxInput.vue';
  39 +import StructForm from './externalCompns/components/StructForm/StructForm.vue';
39 40
40 41 const componentMap = new Map<ComponentType, Component>();
41 42
... ... @@ -78,7 +79,8 @@ componentMap.set('ColorPicker', ColorPicker);
78 79 componentMap.set('IconDrawer', IconDrawer);
79 80 componentMap.set('ApiUpload', ApiUpload);
80 81 componentMap.set('ApiSearchSelect', ApiSearchSelect);
81   -componentMap.set('CustomeMinMaxInput', CustomeMinMaxInput);
  82 +componentMap.set('CustomMinMaxInput', CustomMinMaxInput);
  83 +componentMap.set('StructForm', StructForm);
82 84
83 85 export function add(compName: ComponentType, component: Component) {
84 86 componentMap.set(compName, component);
... ...
src/components/Form/src/externalCompns/components/CustomMinMaxInput.vue renamed from src/components/Form/src/externalCompns/components/CustomeMinMaxInput.vue
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
  6 +<script lang="ts" setup>
  7 + import StructFormModel from './StructFormModel.vue';
  8 + import { useModal } from '/@/components/Modal';
  9 + import { PlusOutlined } from '@ant-design/icons-vue';
  10 + import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  11 + import { computed, unref } from 'vue';
  12 + import { buildUUID } from '/@/utils/uuid';
  13 + import { Divider, Button } from 'ant-design-vue';
  14 + import { OpenModalMode, OpenModalParams, StructRecord } from './type';
  15 + import { cloneDeep } from 'lodash-es';
  16 +
  17 + const emit = defineEmits(['update:value']);
  18 +
  19 + const props = withDefaults(
  20 + defineProps<{
  21 + value: ModelOfMatterParams[];
  22 + }>(),
  23 + {
  24 + value: () => [],
  25 + }
  26 + );
  27 +
  28 + const getValue = computed<StructRecord[]>(() => {
  29 + const { value } = props;
  30 + return value.map((item) => {
  31 + return {
  32 + ...(item as StructRecord),
  33 + ...((item as StructRecord).id ? {} : { id: buildUUID() }),
  34 + };
  35 + });
  36 + });
  37 +
  38 + const [registerModal, { openModal }] = useModal();
  39 +
  40 + const handleCreateParams = () => {
  41 + openModal(true, {
  42 + mode: OpenModalMode.CREATE,
  43 + } as OpenModalParams);
  44 + };
  45 +
  46 + const handleUpdate = (value: StructRecord) => {
  47 + openModal(true, {
  48 + mode: OpenModalMode.UPDATE,
  49 + record: value,
  50 + } as OpenModalParams);
  51 + };
  52 +
  53 + const handleDelete = (value: StructRecord) => {
  54 + const index = unref(getValue).findIndex((item) => item.id === value.id);
  55 + const _value = cloneDeep(unref(getValue));
  56 + _value.splice(index, 1);
  57 + emit('update:value', _value);
  58 + };
  59 +
  60 + const handleSaveStruct = (mode: OpenModalMode, value: StructRecord) => {
  61 + const _value = cloneDeep(unref(getValue));
  62 +
  63 + if (mode === OpenModalMode.UPDATE) {
  64 + const index = unref(getValue).findIndex((item) => item.id === value.id);
  65 + ~index && _value.splice(index, 1, value);
  66 + } else {
  67 + _value.push(value);
  68 + }
  69 +
  70 + emit('update:value', _value);
  71 + };
  72 +</script>
  73 +
  74 +<template>
  75 + <section>
  76 + <div class="text-blue-500 cursor-pointer">
  77 + <section>
  78 + <div
  79 + class="flex bg-blue-50 mb-2 p-2 text-gray-500 justify-between items-center"
  80 + v-for="item in getValue"
  81 + :key="item.id"
  82 + >
  83 + <div>参数名称: {{ item.functionName }}</div>
  84 + <div class="flex">
  85 + <Button class="!p-0" type="link" @click="handleUpdate(item)">编辑</Button>
  86 + <Divider type="vertical" />
  87 + <Button class="!p-0" type="link" @click="handleDelete(item)">删除</Button>
  88 + </div>
  89 + </div>
  90 + </section>
  91 + <div>
  92 + <span class="mr-2">
  93 + <PlusOutlined />
  94 + </span>
  95 + <span @click="handleCreateParams">增加参数</span>
  96 + </div>
  97 + </div>
  98 + <StructFormModel @register="registerModal" @submit="handleSaveStruct" />
  99 + </section>
  100 +</template>
  101 +
  102 +<style lang="less" scoped></style>
... ...
  1 +<script lang="ts">
  2 + export default {
  3 + inheritAttrs: false,
  4 + };
  5 +</script>
  6 +<script lang="ts" setup>
  7 + import { BasicForm, useForm } from '/@/components/Form';
  8 + import { formSchemas } from './config';
  9 + import { BasicModal, useModalInner } from '/@/components/Modal';
  10 + import { OpenModalMode, OpenModalParams, StructRecord } from './type';
  11 + import { ref, unref } from 'vue';
  12 + import { transformFormValue } from './util';
  13 + import { cloneDeep } from 'lodash-es';
  14 +
  15 + const modalReceiveRecord = ref<OpenModalParams>({
  16 + mode: OpenModalMode.CREATE,
  17 + });
  18 +
  19 + const emit = defineEmits(['register', 'submit']);
  20 +
  21 + const [register, { validate, setFieldsValue }] = useForm({
  22 + labelWidth: 100,
  23 + schemas: formSchemas,
  24 + actionColOptions: {
  25 + span: 14,
  26 + },
  27 + showResetButton: false,
  28 + submitOnReset: false,
  29 + showActionButtonGroup: false,
  30 + });
  31 +
  32 + const [registerModal, { closeModal }] = useModalInner((record: OpenModalParams) => {
  33 + modalReceiveRecord.value = record;
  34 + const data = record.record || {};
  35 + const { functionJson = {} } = data! as StructRecord;
  36 + const { specs = {} } = functionJson as StructRecord['functionJson'];
  37 + if (record.record) {
  38 + const value = {
  39 + ...data,
  40 + ...functionJson,
  41 + ...specs,
  42 + valueRange: {
  43 + min: specs.min,
  44 + max: specs.max,
  45 + },
  46 + };
  47 +
  48 + setFieldsValue(value);
  49 + }
  50 + });
  51 +
  52 + const handleSubmit = async () => {
  53 + try {
  54 + const _value = await validate();
  55 + let value = transformFormValue(_value);
  56 + value = {
  57 + ...value,
  58 + ...(unref(modalReceiveRecord)?.record?.id
  59 + ? { id: unref(modalReceiveRecord)?.record?.id }
  60 + : {}),
  61 + };
  62 + emit('submit', unref(modalReceiveRecord).mode, cloneDeep(value));
  63 + closeModal();
  64 + } catch (error) {}
  65 + };
  66 +</script>
  67 +
  68 +<template>
  69 + <BasicModal
  70 + @register="registerModal"
  71 + :title="modalReceiveRecord.mode === OpenModalMode.CREATE ? '创建参数' : '编辑参数'"
  72 + :width="800"
  73 + @ok="handleSubmit"
  74 + destroy-on-close
  75 + >
  76 + <BasicForm @register="register" />
  77 + </BasicModal>
  78 +</template>
  79 +
  80 +<style lang="less" scoped></style>
... ...
  1 +import { h } from 'vue';
  2 +import { findDictItemByCode } from '/@/api/system/dict';
  3 +import { FormSchema } from '/@/components/Table';
  4 +import { FormField } from '/@/views/device/profiles/step/cpns/physical/cpns/config';
  5 +
  6 +export enum DateTypeEnum {
  7 + IS_NUMBER_INT = 'INT',
  8 + IS_NUMBER_DOUBLE = 'DOUBLE',
  9 + IS_STRING = 'TEXT',
  10 + IS_STRUCT = 'STRUCT',
  11 + IS_BOOL = 'BOOL',
  12 +}
  13 +
  14 +export const formSchemas: FormSchema[] = [
  15 + {
  16 + field: FormField.FUNCTION_NAME,
  17 + label: '功能名称',
  18 + required: true,
  19 + component: 'Input',
  20 + colProps: {
  21 + span: 18,
  22 + },
  23 + componentProps: {
  24 + maxLength: 255,
  25 + placeholder: '请输入功能名称',
  26 + },
  27 + },
  28 + {
  29 + field: FormField.IDENTIFIER,
  30 + label: '标识符',
  31 + required: true,
  32 + component: 'Input',
  33 + colProps: {
  34 + span: 18,
  35 + },
  36 + componentProps: {
  37 + maxLength: 255,
  38 + placeholder: '请输入标识符',
  39 + },
  40 + },
  41 + {
  42 + field: FormField.TYPE,
  43 + label: '数据类型',
  44 + required: true,
  45 + component: 'ApiSelect',
  46 + colProps: {
  47 + span: 9,
  48 + },
  49 + defaultValue: 'INT',
  50 + componentProps: {
  51 + placeholder: '请选择数据类型',
  52 + api: findDictItemByCode,
  53 + params: {
  54 + dictCode: 'data_type',
  55 + },
  56 + labelField: 'itemText',
  57 + valueField: 'itemValue',
  58 + getPopupContainer: () => document.body,
  59 + },
  60 + },
  61 + {
  62 + field: FormField.VALUE_RANGE,
  63 + label: '取值范围',
  64 + component: 'CustomMinMaxInput',
  65 + colProps: {
  66 + span: 18,
  67 + },
  68 + ifShow: ({ values }) =>
  69 + values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_INT ||
  70 + values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_DOUBLE,
  71 + },
  72 + {
  73 + field: FormField.STEP,
  74 + label: '步长',
  75 + component: 'Input',
  76 + colProps: {
  77 + span: 18,
  78 + },
  79 + componentProps: {
  80 + maxLength: 255,
  81 + placeholder: '请输入步长',
  82 + },
  83 + ifShow: ({ values }) =>
  84 + values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_INT ||
  85 + values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_DOUBLE,
  86 + },
  87 + {
  88 + field: FormField.UNIT_NAME,
  89 + label: '单位名称',
  90 + component: 'Input',
  91 + show: false,
  92 + },
  93 + {
  94 + field: FormField.UNIT,
  95 + label: '单位',
  96 + component: 'ApiSelect',
  97 + colProps: {
  98 + span: 9,
  99 + },
  100 + componentProps: ({ formActionType }) => {
  101 + const { setFieldsValue } = formActionType;
  102 + return {
  103 + placeholder: '请选择单位',
  104 + api: findDictItemByCode,
  105 + params: {
  106 + dictCode: 'attribute_unit',
  107 + },
  108 + labelField: 'itemText',
  109 + valueField: 'itemValue',
  110 + onChange(_, record: Record<'label' | 'value', string>) {
  111 + const { label } = record;
  112 + setFieldsValue({ [FormField.UNIT_NAME]: label });
  113 + },
  114 + getPopupContainer: () => document.body,
  115 + };
  116 + },
  117 + ifShow: ({ values }) =>
  118 + values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_INT ||
  119 + values[FormField.TYPE] === DateTypeEnum.IS_NUMBER_DOUBLE,
  120 + renderComponentContent: () => {
  121 + return {
  122 + option: (params: Record<'label' | 'value', string>) => {
  123 + const { label, value } = params;
  124 + return h('span', `${label} / ${value}`);
  125 + },
  126 + };
  127 + },
  128 + },
  129 + {
  130 + field: FormField.BOOL_CLOSE,
  131 + component: 'Input',
  132 + required: true,
  133 + label: '0 -',
  134 + colProps: {
  135 + span: 18,
  136 + },
  137 + componentProps: {
  138 + placeholder: '如:关',
  139 + },
  140 + ifShow: ({ values }) => values[FormField.TYPE] === DateTypeEnum.IS_BOOL,
  141 + },
  142 + {
  143 + field: FormField.BOOL_OPEN,
  144 + component: 'Input',
  145 + required: true,
  146 + label: '1 -',
  147 + colProps: {
  148 + span: 18,
  149 + },
  150 + componentProps: {
  151 + placeholder: '如:开',
  152 + },
  153 + ifShow: ({ values }) => values[FormField.TYPE] === DateTypeEnum.IS_BOOL,
  154 + },
  155 + {
  156 + field: FormField.LENGTH,
  157 + component: 'Input',
  158 + required: true,
  159 + label: '数据长度',
  160 + defaultValue: '10240',
  161 + colProps: {
  162 + span: 8,
  163 + },
  164 + componentProps: {
  165 + placeholder: '请输入数据长度',
  166 + },
  167 + renderComponentContent: () => {
  168 + return {
  169 + suffix: () => '字节',
  170 + };
  171 + },
  172 + ifShow: ({ values }) => values[FormField.TYPE] === DateTypeEnum.IS_STRING,
  173 + },
  174 + {
  175 + field: FormField.R_W_FLAG,
  176 + component: 'ApiRadioGroup',
  177 + label: '读写类型',
  178 + required: true,
  179 + colProps: {
  180 + span: 24,
  181 + },
  182 + defaultValue: 'READ_ONLY',
  183 + componentProps: {
  184 + placeholder: '请选择读写类型',
  185 + api: findDictItemByCode,
  186 + params: {
  187 + dictCode: 'read_write_type',
  188 + },
  189 + labelField: 'itemText',
  190 + valueField: 'itemValue',
  191 + },
  192 + },
  193 + {
  194 + field: FormField.SPECS_LIST,
  195 + label: 'JSON对象',
  196 + component: 'StructForm',
  197 + valueField: 'value',
  198 + changeEvent: 'update:value',
  199 + colProps: { span: 24 },
  200 + ifShow: ({ values }) => values[FormField.TYPE] === DateTypeEnum.IS_STRUCT,
  201 + },
  202 + {
  203 + field: FormField.REFARK,
  204 + label: '备注',
  205 + component: 'InputTextArea',
  206 + componentProps: {
  207 + rows: 4,
  208 + maxLength: 100,
  209 + placeholder: '请输入描述',
  210 + },
  211 + },
  212 +];
... ...
  1 +import { DateTypeEnum } from './config';
  2 +import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  3 +import { FormField } from '/@/views/device/profiles/step/cpns/physical/cpns/config';
  4 +
  5 +export enum OpenModalMode {
  6 + CREATE = 'create',
  7 + UPDATE = 'update',
  8 +}
  9 +
  10 +export interface OpenModalParams {
  11 + mode: OpenModalMode;
  12 + record?: StructRecord;
  13 +}
  14 +
  15 +export interface StructFormValue
  16 + extends Partial<Record<Exclude<FormField, FormField.VALUE_RANGE | FormField.STRUCT>, string>> {
  17 + [FormField.TYPE]: DateTypeEnum;
  18 + [FormField.VALUE_RANGE]?: {
  19 + [FormField.MIN]: string;
  20 + [FormField.MAX]: string;
  21 + };
  22 + [FormField.STRUCT]: StructRecord[];
  23 +}
  24 +
  25 +export interface StructRecord extends ModelOfMatterParams {
  26 + id: string;
  27 +}
... ...
  1 +import { DateTypeEnum } from './config';
  2 +import { StructFormValue } from './type';
  3 +import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  4 +import { useMessage } from '/@/hooks/web/useMessage';
  5 +import { FunctionType } from '/@/views/device/profiles/step/cpns/physical/cpns/config';
  6 +
  7 +export const validateValueRangeAndStep = (min: number, step: number, max: number) => {
  8 + const { createMessage } = useMessage();
  9 + if (min > max) {
  10 + createMessage.error('最大值必须大于最小值,整数型不能有小数位,单精度有效位为7,双精度为16');
  11 + throw '最大值必须大于最小值,整数型不能有小数位,单精度有效位为7,双精度为16';
  12 + }
  13 +
  14 + if (step > max - min) {
  15 + createMessage.error('步长不能大于取值范围的差值');
  16 + throw '步长不能大于取值范围的差值';
  17 + }
  18 +};
  19 +
  20 +export const validateValueBool = (boolClose, boolOpen) => {
  21 + const { createMessage } = useMessage();
  22 +
  23 + if (boolClose == boolOpen) {
  24 + createMessage.error('布尔值不能相同');
  25 + throw '布尔值不能相同';
  26 + }
  27 +};
  28 +
  29 +export const validateValueStruct = (data: []) => {
  30 + const { createMessage } = useMessage();
  31 +
  32 + if (data.length === 0) {
  33 + createMessage.error('struct不能为空');
  34 + throw 'struct不能为空';
  35 + }
  36 +};
  37 +
  38 +export function transformFormValue(value: StructFormValue): Partial<ModelOfMatterParams> {
  39 + const {
  40 + type,
  41 + valueRange,
  42 + step,
  43 + length = '',
  44 + boolClose,
  45 + boolOpen,
  46 + unit,
  47 + unitName,
  48 + functionName,
  49 + identifier,
  50 + remark,
  51 + specsList,
  52 + } = value;
  53 + const { min, max } = valueRange! || {};
  54 + const basic = { functionName, identifier, remark };
  55 + let functionJson = {} as unknown as ModelOfMatterParams['functionJson'];
  56 +
  57 + switch (type) {
  58 + case DateTypeEnum.IS_NUMBER_INT:
  59 + validateValueRangeAndStep(Number(min), Number(step), Number(max));
  60 + functionJson = {
  61 + type,
  62 + specs: { max, min, step, unit, unitName },
  63 + };
  64 + break;
  65 +
  66 + case DateTypeEnum.IS_NUMBER_DOUBLE:
  67 + validateValueRangeAndStep(Number(min), Number(step), Number(max));
  68 + functionJson = {
  69 + type,
  70 + specs: { max, min, step, unit, unitName },
  71 + };
  72 + break;
  73 +
  74 + case DateTypeEnum.IS_BOOL:
  75 + validateValueBool(Number(boolClose), Number(boolOpen));
  76 + functionJson = {
  77 + type,
  78 + specs: {
  79 + boolOpen: boolOpen,
  80 + boolClose: boolClose,
  81 + },
  82 + };
  83 + break;
  84 +
  85 + case DateTypeEnum.IS_STRING:
  86 + functionJson = {
  87 + type,
  88 + specs: { length },
  89 + };
  90 + break;
  91 +
  92 + case DateTypeEnum.IS_STRUCT:
  93 + functionJson = {
  94 + type,
  95 + specsList: specsList! as unknown as ModelOfMatterParams[],
  96 + };
  97 + break;
  98 + }
  99 + return {
  100 + ...basic,
  101 + functionType: FunctionType.PROPERTIES,
  102 + functionJson,
  103 + };
  104 +}
... ...
... ... @@ -112,9 +112,10 @@ export type ComponentType =
112 112 | 'Render'
113 113 | 'Slider'
114 114 | 'JAddInput'
115   - | 'CustomeMinMaxInput'
  115 + | 'CustomMinMaxInput'
116 116 | 'Rate'
117 117 | 'ColorPicker'
118 118 | 'IconDrawer'
119 119 | 'ApiUpload'
120   - | 'ApiSearchSelect';
  120 + | 'ApiSearchSelect'
  121 + | 'StructForm';
... ...
1 1 <template>
2 2 <BasicDrawer v-bind="$attrs" title="产品详情" @register="register" width="60%">
3 3 <Tabs :animated="true" v-model:activeKey="activeKey" @change="handlePanelChange">
4   - <TabPane forceRender key="product" tab="产品">
  4 + <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 9 </TabPane>
10   - <TabPane forceRender key="transport" tab="传输配置">
  10 + <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 15 </TabPane>
16   - <TabPane forceRender key="modelOfMatter" tab="物模型管理">
17   - <PhysicalModelManagementStep />
  16 + <TabPane key="modelOfMatter" tab="物模型管理">
  17 + <PhysicalModelManagementStep :record="record" />
18 18 </TabPane>
19 19 </Tabs>
20 20 </BasicDrawer>
... ... @@ -27,14 +27,15 @@
27 27 import PhysicalModelManagementStep from './step/PhysicalModelManagementStep.vue';
28 28 import { ref, unref } from 'vue';
29 29 import { deviceConfigGetDetail } from '/@/api/device/deviceConfigApi';
  30 + import { DeviceRecord } from '/@/api/device/model/deviceModel';
30 31
31 32 defineEmits(['register']);
32 33
33 34 type ActiveKey = 'product' | 'transport' | 'modelOfMatter';
34 35
35   - const activeKey = ref<ActiveKey>('product');
  36 + const activeKey = ref<ActiveKey>('modelOfMatter');
36 37
37   - const record = ref<Recordable>({});
  38 + const record = ref<DeviceRecord>({} as unknown as DeviceRecord);
38 39
39 40 const DevConStRef = ref<InstanceType<typeof DeviceConfigurationStep>>();
40 41 const TransConStRef = ref<InstanceType<typeof TransportConfigurationStep>>();
... ... @@ -47,7 +48,7 @@
47 48 unref(TransConStRef)?.setFormData(res);
48 49 };
49 50
50   - const [register, {}] = useDrawerInner(async (data: Recordable) => {
  51 + const [register, {}] = useDrawerInner(async (data: { record: DeviceRecord }) => {
51 52 activeKey.value = 'product';
52 53 record.value = await deviceConfigGetDetail(data.record.id);
53 54 setDeviceConfFormData(unref(record));
... ...
... ... @@ -5,6 +5,7 @@ import { MessageEnum } from '/@/enums/messageEnum';
5 5 import { numberRule } from '/@/utils/rules';
6 6
7 7 import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi';
  8 +import { FormField, FunctionType } from './step/cpns/physical/cpns/config';
8 9
9 10 export const steps = [
10 11 {
... ... @@ -17,49 +18,36 @@ export const steps = [
17 18 },
18 19 ];
19 20
  21 +export const formatFunctionType: Record<FunctionType, string> = {
  22 + [FunctionType.PROPERTIES]: '属性',
  23 + [FunctionType.EVENTS]: '事件',
  24 + [FunctionType.SERVICE]: '事件',
  25 +};
  26 +
20 27 export const physicalColumn: BasicColumn[] = [
21 28 {
22 29 title: '功能类型',
23   - dataIndex: 'dType',
  30 + dataIndex: FormField.FUNCTION_TYPE,
24 31 width: 90,
  32 + format: (text: FunctionType) => {
  33 + return formatFunctionType[text];
  34 + },
25 35 },
26 36 {
27 37 title: '功能名称',
28   - dataIndex: 'name',
  38 + dataIndex: FormField.FUNCTION_NAME,
29 39 width: 90,
30 40 },
31 41 {
32 42 title: '标识符',
33   - dataIndex: 'type',
  43 + dataIndex: FormField.IDENTIFIER,
34 44 width: 90,
35 45 },
36 46 {
37 47 title: '数据类型',
38   - dataIndex: 'transportType',
  48 + dataIndex: 'functionJson.type',
39 49 width: 100,
40 50 },
41   - // {
42   - // title: '单位',
43   - // dataIndex: 'description1',
44   - // width: 90,
45   - // },
46   - // {
47   - // title: '读写类型',
48   - // dataIndex: 'default',
49   - // width: 60,
50   - // customRender: ({ record }) => {
51   - // const status = record.actionStatus;
52   - // const enable = status === 'SUCCESS' ? '读写' : '只读';
53   - // const color = enable === '读写' ? 'blue' : 'green';
54   - // const text = enable === '读写' ? '读写' : '只读';
55   - // return h(Tag, { color }, () => text);
56   - // },
57   - // },
58   - // {
59   - // title: '创建人',
60   - // dataIndex: 'description',
61   - // width: 80,
62   - // },
63 51 {
64 52 title: '创建时间',
65 53 dataIndex: 'createTime',
... ... @@ -409,130 +397,3 @@ export const formSchema: FormSchema[] = [
409 397 },
410 398 },
411 399 ];
412   -
413   -export const mockData: any = async () => {
414   - const res = await [
415   - {
416   - dType: 'events',
417   - name: '亮度百分比',
418   - type: 'Brightness',
419   - transportType: 'int32(整数型)',
420   - description1: '饱和度/aw',
421   - default: '1',
422   - actionStatus: 'SUCCESS',
423   - description: 'cheche',
424   - createTime: '2022-10-20 10:24:22',
425   - },
426   - {
427   - dType: 'service',
428   - name: '运行状态',
429   - type: 'RunningState',
430   - transportType: 'bool(布尔型)',
431   - description1: '',
432   - default: '1',
433   - actionStatus: 'FA',
434   - description: 'cheche',
435   - createTime: '2022-10-20 10:24:22',
436   - },
437   - {
438   - dType: 'attr',
439   - name: '设备运行状态',
440   - type: 'E_Status_UP',
441   - transportType: 'text(字符串)',
442   - description1: '',
443   - default: '1',
444   - actionStatus: 'D',
445   - description: 'cheche',
446   - createTime: '2022-10-20 10:24:22',
447   - },
448   - {
449   - dType: 'attr',
450   - name: '过流告警使能',
451   - type: 'OverCurrentEnable',
452   - transportType: 'struct(结构体)',
453   - description1: '',
454   - default: '1',
455   - actionStatus: 'SUCCESS',
456   - description: 'cheche',
457   - createTime: '2022-10-20 10:24:22',
458   - },
459   - {
460   - dType: 'events',
461   - name: '变频器运行状态1',
462   - type: 'Brightness',
463   - transportType: 'int32(整数型)',
464   - description1: '转每分钟/turn/m',
465   - default: '1',
466   - actionStatus: 'Fa',
467   - description: 'cheche',
468   - createTime: '2022-10-20 10:24:22',
469   - },
470   - {
471   - dType: 'service',
472   - name: '产品序列号',
473   - type: 'SerialNo',
474   - transportType: 'text(字符串)',
475   - description1: '',
476   - default: '1',
477   - actionStatus: 'FA',
478   - description: 'cheche',
479   - createTime: '2022-10-20 10:24:22',
480   - },
481   - {
482   - dType: 'service',
483   - name: '音量百分比',
484   - type: 'Volume',
485   - transportType: 'int32(整数型)',
486   - description1: '分贝/db',
487   - default: '1',
488   - actionStatus: 'SUCCESS',
489   - description: 'cheche',
490   - createTime: '2022-10-20 10:24:22',
491   - },
492   - {
493   - dType: 'attr',
494   - name: '易释放氰化物',
495   - type: 'easy_release_cyanide',
496   - transportType: 'double(双精度浮点型)',
497   - description1: '毫克每升/mg/L',
498   - default: '1',
499   - actionStatus: 'SUCCESS',
500   - description: 'cheche',
501   - createTime: '2022-10-20 10:24:22',
502   - },
503   - {
504   - dType: 'attr',
505   - name: '湿度',
506   - type: 'Humidity',
507   - transportType: 'float(单精度浮点型)',
508   - description1: '相对湿度/%RH',
509   - default: '1',
510   - actionStatus: 'SUCCESS',
511   - description: 'cheche',
512   - createTime: '2022-10-20 10:24:22',
513   - },
514   - {
515   - dType: 'attr',
516   - name: '设备固件版本',
517   - type: 'FirmwareVersion',
518   - transportType: 'text(字符串)',
519   - description1: '',
520   - default: '1',
521   - actionStatus: 'SUCCESS',
522   - description: 'cheche',
523   - createTime: '2022-10-20 10:24:22',
524   - },
525   - {
526   - dType: 'events',
527   - name: '用电量',
528   - type: 'PowerConsumption',
529   - transportType: 'float(单精度浮点型)',
530   - description1: '千瓦时/kW.h',
531   - default: '1',
532   - actionStatus: 'F',
533   - description: 'cheche',
534   - createTime: '2022-10-20 10:24:22',
535   - },
536   - ];
537   - return res;
538   -};
... ...
... ... @@ -99,7 +99,7 @@
99 99 </div>
100 100 </template>
101 101 <script lang="ts" setup>
102   - import { ref, nextTick, onUnmounted } from 'vue';
  102 + import { ref, nextTick, onUnmounted, onMounted } from 'vue';
103 103 import { BasicTable, TableImg, useTable, TableAction, BasicColumn } from '/@/components/Table';
104 104 import { columns, searchFormSchema, defaultObj } from './device.profile.data';
105 105 import { useMessage } from '/@/hooks/web/useMessage';
... ... @@ -258,6 +258,7 @@
258 258 }
259 259
260 260 const [registerDrawer, { openDrawer }] = useDrawer();
  261 + onMounted(() => openDrawer(true));
261 262 //详情
262 263 function handleDetailView(record: Recordable) {
263 264 openDrawer(true, { record });
... ...
... ... @@ -8,7 +8,7 @@
8 8 <template #toolbar>
9 9 <div class="flex-auto">
10 10 <div class="mb-2">
11   - <a-alert type="info" show-icon>
  11 + <Alert type="info" show-icon>
12 12 <template #message>
13 13 <span v-if="!isShowBtn">
14 14 当前展示的是已发布到线上的功能定义,如需修改,请点击
... ... @@ -22,15 +22,15 @@
22 22 </span>
23 23 <span v-if="isShowBtn"> 您正在编辑的是草稿,需点击发布后,物模型才会正式生效. </span>
24 24 </template>
25   - </a-alert>
  25 + </Alert>
26 26 </div>
27 27 <div class="flex justify-between items-end">
28 28 <div class="flex gap-2">
29 29 <Authority value="">
30   - <a-button v-if="isShowBtn" type="primary" @click="handleCreateOrEdit(null)">
  30 + <Button v-if="isShowBtn" type="primary" @click="handleCreateOrEdit">
31 31 新增物模型
32   - </a-button>
33   - <a-button type="primary" @click="handleOpenTsl"> 物模型TSL </a-button>
  32 + </Button>
  33 + <Button type="primary" @click="handleOpenTsl"> 物模型TSL </Button>
34 34 </Authority>
35 35 </div>
36 36 <div class="flex gap-2">
... ... @@ -41,25 +41,25 @@
41 41 cancel-text="取消"
42 42 @confirm="handleEmit"
43 43 >
44   - <a-button v-if="isShowBtn" type="primary"> 发布上线 </a-button>
  44 + <Button v-if="isShowBtn" type="primary"> 发布上线 </Button>
45 45 </Popconfirm>
46   - <a-button v-if="isShowBtn" class="!bg-gray-200" type="text" @click="handleReturn">
  46 + <Button v-if="isShowBtn" class="!bg-gray-200" type="text" @click="handleReturn">
47 47 返回
48   - </a-button>
  48 + </Button>
49 49 <Popconfirm
50 50 title="您确定要批量删除数据"
51 51 ok-text="确定"
52 52 cancel-text="取消"
53 53 @confirm="handleDeleteOrBatchDelete(null)"
54 54 >
55   - <a-button
  55 + <Button
56 56 style="display: none"
57 57 type="primary"
58 58 color="error"
59 59 :disabled="hasBatchDelete"
60 60 >
61 61 批量删除
62   - </a-button>
  62 + </Button>
63 63 </Popconfirm>
64 64 </Authority>
65 65 </div>
... ... @@ -97,8 +97,12 @@
97 97 />
98 98 </template>
99 99 </BasicTable>
100   - <PhysicalModelModal @register="registerModal" @success="handleSuccess" />
101   - <PhysicalModelTsl @register="registerModalTsl" />
  100 + <PhysicalModelModal
  101 + :record="$props.record"
  102 + @register="registerModal"
  103 + @success="handleSuccess"
  104 + />
  105 + <PhysicalModelTsl :record="$props.record" @register="registerModalTsl" />
102 106 </div>
103 107 </template>
104 108 <script lang="ts" setup>
... ... @@ -107,29 +111,32 @@
107 111 import { useModal } from '/@/components/Modal';
108 112 import { physicalColumn } from '../device.profile.data';
109 113 import { useBatchDelete } from '/@/hooks/web/useBatchDelete';
110   - import { deleteReportManage } from '/@/api/report/reportManager';
111 114 import { Authority } from '/@/components/Authority';
112   - // import { mockData } from '/@/api/device/deviceConfigApi';
113 115 import PhysicalModelModal from './cpns/physical/PhysicalModelModal.vue';
114 116 import PhysicalModelTsl from './cpns/physical/PhysicalModelTsl.vue';
115   - import { Popconfirm } from 'ant-design-vue';
  117 + import { Popconfirm, Button, Alert } from 'ant-design-vue';
116 118 import { useMessage } from '/@/hooks/web/useMessage';
117   - import { mockData } from '../device.profile.data';
118   -
  119 + import { DeviceRecord } from '/@/api/device/model/deviceModel';
  120 + import { deleteModel, getModelList } from '/@/api/device/modelOfMatter';
  121 + import { OpenModelOfMatterModelParams, OpenModelMode } from './cpns/physical/types';
  122 + import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
119 123 defineEmits(['register']);
  124 +
  125 + defineProps<{
  126 + record: DeviceRecord;
  127 + }>();
  128 +
120 129 const { createMessage } = useMessage();
121 130 const isShowBtn = ref(false);
122 131 const [registerModal, { openModal }] = useModal();
123 132 const [registerModalTsl, { openModal: openModalTsl }] = useModal();
124 133
125 134 const [registerTable, { reload, setProps }] = useTable({
126   - // api: deviceConfigGetQuery,
127   - api: mockData,
  135 + api: getModelList,
128 136 columns: physicalColumn,
129 137 showIndexColumn: false,
130 138 clickToRowSelect: false,
131 139 useSearchForm: false,
132   - // rowKey: 'id',
133 140 showTableSetting: true,
134 141 bordered: true,
135 142 actionColumn: {
... ... @@ -140,16 +147,18 @@
140 147 fixed: 'right',
141 148 },
142 149 });
  150 +
143 151 // 刷新
144 152 const handleSuccess = () => {
145 153 reload();
146 154 };
147 155
148 156 const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete(
149   - deleteReportManage,
  157 + deleteModel,
150 158 handleSuccess,
151 159 setProps
152 160 );
  161 +
153 162 selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => {
154 163 // Demo:status为1的选择框禁用
155 164 if (record.status === 1) {
... ... @@ -158,38 +167,36 @@
158 167 return { disabled: false };
159 168 }
160 169 };
161   - const handleViewDetail = (record: Recordable | null) => {
  170 +
  171 + const handleViewDetail = (record: ModelOfMatterParams) => {
162 172 if (record) {
163 173 openModal(true, {
164   - isUpdate: true,
165 174 record,
166   - isView: true,
167   - isText: 'view',
168   - });
  175 + mode: OpenModelMode.VIEW,
  176 + } as OpenModelOfMatterModelParams);
169 177 }
170 178 };
  179 +
171 180 // 新增或编辑
172   - const handleCreateOrEdit = (record: Recordable | null) => {
  181 + const handleCreateOrEdit = (record?: ModelOfMatterParams) => {
173 182 if (record) {
174 183 openModal(true, {
175   - isUpdate: false,
  184 + mode: OpenModelMode.UPDATE,
176 185 record,
177   - isView: false,
178   - isText: 'edit',
179   - });
  186 + } as OpenModelOfMatterModelParams);
180 187 } else {
181 188 openModal(true, {
182   - isUpdate: true,
183   - isView: false,
184   - isText: 'add',
185   - });
  189 + mode: OpenModelMode.CREATE,
  190 + } as OpenModelOfMatterModelParams);
186 191 }
187 192 };
  193 +
188 194 const handleOpenTsl = () => {
189 195 openModalTsl(true, {
190 196 isUpdate: true,
191 197 });
192 198 };
  199 +
193 200 const handleEditPhysicalModel = () => (isShowBtn.value = true);
194 201
195 202 const handleReturn = () => (isShowBtn.value = false);
... ...
... ... @@ -8,160 +8,138 @@
8 8 @ok="handleSubmit"
9 9 @cancel="handleCancel"
10 10 >
11   - <div v-if="isViewDetail">
12   - <Attribute v-show="activeKey === '1'" ref="AttrRef" />
13   - <Service v-show="activeKey === '2'" ref="ServiceRef" />
14   - <Events v-show="activeKey === '3'" ref="EventsRef" />
15   - </div>
16   - <div v-if="!isViewDetail">
17   - <div>
  11 + <div>
  12 + <div v-if="openModalMode === OpenModelMode.CREATE">
18 13 <Typography>
19 14 <TypographyParagraph>
20   - <blockquote style="background: #f2f2f2">{{ blockContent }}</blockquote>
  15 + <blockquote class="bg-gray-100">{{ blockContent }}</blockquote>
21 16 </TypographyParagraph>
22 17 </Typography>
23 18 </div>
24   - <Tabs type="card" v-model:activeKey="activeKey" :size="size">
25   - <TabPane :disabled="attrDisable" forceRender key="1" tab="属性">
26   - <Attribute v-show="activeKey === '1'" ref="AttrRef" />
27   - </TabPane>
28   - <TabPane :disabled="serveiceDisable" forceRender key="2" tab="服务">
29   - <Service v-show="activeKey === '2'" ref="ServiceRef" />
30   - </TabPane>
31   - <TabPane
32   - :disabled="eventDisable"
33   - forceRender
34   - key="3"
35   - v-show="activeKey === '3'"
36   - tab="事件"
37   - >
38   - <Events v-show="activeKey === '3'" ref="EventsRef" />
39   - </TabPane>
  19 + <Tabs
  20 + v-if="openModalMode === OpenModelMode.CREATE"
  21 + type="card"
  22 + v-model:activeKey="activeKey"
  23 + :size="size"
  24 + >
  25 + <TabPane :key="FunctionType.PROPERTIES" tab="属性" />
  26 + <TabPane :key="FunctionType.SERVICE" tab="服务" />
  27 + <TabPane :key="FunctionType.EVENTS" tab="事件" />
40 28 </Tabs>
  29 + <Attribute v-show="activeKey === FunctionType.PROPERTIES" ref="AttrRef" />
  30 + <Service v-show="activeKey === FunctionType.SERVICE" ref="ServiceRef" />
  31 + <Events v-show="activeKey === FunctionType.EVENTS" ref="EventsRef" />
41 32 </div>
42 33 </BasicModal>
43 34 </div>
44 35 </template>
45 36 <script lang="ts" setup>
46   - import { ref, unref, reactive, nextTick } from 'vue';
  37 + import { ref, unref } from 'vue';
47 38 import { BasicModal, useModalInner } from '/@/components/Modal';
48 39 import { Tabs, TabPane, Typography, TypographyParagraph } from 'ant-design-vue';
49 40 import Attribute from './cpns/Attribute.vue';
50 41 import Service from './cpns/Service.vue';
51 42 import Events from './cpns/Events.vue';
52   - import { mockData } from '../physical/cpns/components/mock';
  43 + import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  44 + import { createModel, updateModel } from '/@/api/device/modelOfMatter';
  45 + import { DeviceRecord } from '/@/api/device/model/deviceModel';
  46 + import { useMessage } from '/@/hooks/web/useMessage';
  47 + import { OpenModelMode, OpenModelOfMatterModelParams } from './types/index';
  48 + import { FunctionType } from './cpns/config';
  49 + import { StructRecord } from '/@/components/Form/src/externalCompns/components/StructForm/type';
  50 +
  51 + const emit = defineEmits(['register', 'success']);
  52 +
  53 + const props = defineProps<{
  54 + record: DeviceRecord;
  55 + }>();
53 56
54   - defineEmits(['register']);
55   - const attrDisable = ref(false);
56   - const serveiceDisable = ref(false);
57   - const eventDisable = ref(false);
58 57 const blockContent = `属性一般是设备的运行状态,如当前温度等;服务是设备可被调用的方法,支持定义参数,如执行某项任务;事件则是设备上报的
59 58 通知,如告警,需要被及时处理。`;
60   - const activeKey = ref('1');
  59 + const activeKey = ref<FunctionType>(FunctionType.PROPERTIES);
61 60 const size = ref('small');
62 61 const AttrRef = ref<InstanceType<typeof Attribute>>();
63 62 const ServiceRef = ref<InstanceType<typeof Service>>();
64 63 const EventsRef = ref<InstanceType<typeof Events>>();
65   - const isUpdate = ref(false);
66   - const isViewDetail = ref('');
67   - const isText = ref('');
68   - const dType = ref('');
69   - const allData: any = reactive({
70   - properties: [],
71   - events: [],
72   - services: [],
73   - productKey: '',
74   - _ppk: {},
75   - });
  64 + const openModalMode = ref<OpenModelMode>(OpenModelMode.CREATE);
  65 +
  66 + const functionType = ref<FunctionType>();
  67 + const { createMessage } = useMessage();
  68 +
  69 + const setAttrFormData = (data: StructRecord) => AttrRef.value?.setFormData(data);
  70 + const setServiceFormData = (data) => ServiceRef.value?.setFormData(data);
  71 + const setEventsFormData = (data) => EventsRef.value?.setFormData(data);
76 72
77   - const setAttrFormData = (data: {}) => AttrRef.value?.setFormData(data);
78   - const setServiceFormData = (data: {}) => ServiceRef.value?.setFormData(data);
79   - const setEventsFormData = (data: {}) => EventsRef.value?.setFormData(data);
80 73 const enums = {
81   - attr: setAttrFormData,
82   - service: setServiceFormData,
83   - events: setEventsFormData,
  74 + [FunctionType.PROPERTIES]: setAttrFormData,
  75 + [FunctionType.SERVICE]: setServiceFormData,
  76 + [FunctionType.EVENTS]: setEventsFormData,
84 77 };
85   - function action(val, data) {
86   - let F = enums[val];
87   - F(data);
  78 +
  79 + function setFormData(type: FunctionType, value: StructRecord) {
  80 + const setFn = enums[type];
  81 + setFn(value);
88 82 }
89   - const dynamicData = (t, a, s, e) => {
90   - switch (t) {
91   - case 'attr':
92   - activeKey.value = '1';
93   - action(t, a);
94   - attrDisable.value = false;
95   - serveiceDisable.value = true;
96   - eventDisable.value = true;
97   - break;
98   - case 'service':
99   - activeKey.value = '2';
100   - action(t, s);
101   - attrDisable.value = true;
102   - serveiceDisable.value = false;
103   - eventDisable.value = true;
104   - break;
105   - case 'events':
106   - activeKey.value = '3';
107   - action(t, e);
108   - attrDisable.value = true;
109   - serveiceDisable.value = true;
110   - eventDisable.value = false;
111   - break;
112   - }
113   - };
114   - const [register, { closeModal, setModalProps }] = useModalInner(async (data) => {
115   - setModalProps({ loading: true });
116   - handleCancel(false);
117   - isUpdate.value = data.isUpdate;
118   - isViewDetail.value = data.isView;
119   - isText.value = data.isText;
120   - dType.value = data.record?.dType;
121   - if (!unref(isViewDetail)) {
122   - const title = !unref(isUpdate) ? '编辑物模型' : '新增物模型';
123   - if (!unref(isUpdate)) {
124   - nextTick(() => {
125   - dynamicData(dType.value, mockData.properties, mockData.services, mockData.events);
126   - });
  83 +
  84 + const [register, { closeModal, setModalProps }] = useModalInner(
  85 + async (data: OpenModelOfMatterModelParams) => {
  86 + const { mode, record } = data;
  87 + openModalMode.value = mode;
  88 + if (record) {
  89 + functionType.value = data.record.functionType;
  90 + activeKey.value = data.record.functionType;
  91 + setFormData(record.functionType, record as unknown as StructRecord);
  92 + }
  93 + if (unref(openModalMode) === OpenModelMode.VIEW) {
  94 + setModalProps({ showOkBtn: false, showCancelBtn: false, title: '查看物模型' });
  95 + // setFormData(functionType.value, record);
  96 + } else {
  97 + const title = unref(openModalMode) === OpenModelMode.UPDATE ? '编辑物模型' : '新增物模型';
  98 + if (OpenModelMode.UPDATE) {
  99 + // setFormData(functionType.value, record);
  100 + }
  101 + setModalProps({ title, showOkBtn: true, showCancelBtn: true });
127 102 }
128   - setModalProps({ title, showOkBtn: true, showCancelBtn: true });
129   - } else {
130   - setModalProps({ showOkBtn: false, showCancelBtn: false, title: '查看物模型' });
131   - nextTick(() => {
132   - dynamicData(dType.value, mockData.properties, mockData.services, mockData.events);
133   - });
134 103 }
135   - setModalProps({ loading: false });
136   - });
  104 + );
  105 +
137 106 const handleCancel = (flag) => {
138 107 AttrRef.value?.resetFormData();
139 108 ServiceRef.value?.resetFormData();
140 109 EventsRef.value?.resetFormData();
141   - activeKey.value = '1';
142   - allData.properties = [];
143   - allData.events = [];
144   - allData.services = [];
145   - attrDisable.value = false;
146   - serveiceDisable.value = false;
147   - eventDisable.value = false;
  110 + activeKey.value = FunctionType.PROPERTIES;
148 111 if (flag) {
149 112 closeModal();
150 113 }
151 114 };
  115 +
152 116 const handleSubmit = async () => {
153   - if (activeKey.value == '1') {
154   - const valueAttr = await AttrRef.value?.getFormData();
155   - allData.properties.push(valueAttr);
156   - } else if (activeKey.value == '2') {
157   - const valueService = await ServiceRef.value?.getFormData();
158   - allData.services.push(valueService);
159   - } else {
160   - const valueEvents = await EventsRef.value?.getFormData();
161   - allData.events.push(valueEvents);
  117 + try {
  118 + setModalProps({ loading: false, okButtonProps: { loading: true } });
  119 +
  120 + let params: Partial<ModelOfMatterParams>;
  121 + if (activeKey.value == FunctionType.PROPERTIES) {
  122 + params = (await AttrRef.value?.getFormData()) || {};
  123 + } else if (activeKey.value == FunctionType.SERVICE) {
  124 + params = await ServiceRef.value?.getFormData();
  125 + } else {
  126 + params = await EventsRef.value?.getFormData();
  127 + }
  128 + params.deviceProfileId = props.record.id;
  129 + if (unref(openModalMode) === OpenModelMode.CREATE) {
  130 + await createModel(params);
  131 + createMessage.success('创建成功');
  132 + } else {
  133 + params.id = props.record.id;
  134 + await updateModel(params);
  135 + createMessage.success('修改成功');
  136 + }
  137 + closeModal();
  138 + emit('success');
  139 + } catch (error) {
  140 + } finally {
  141 + setModalProps({ loading: false, okButtonProps: { loading: false } });
162 142 }
163   - console.log('搜集值', allData);
164   - closeModal();
165 143 };
166 144 </script>
167 145
... ...
1 1 <template>
2 2 <div>
3   - <BasicForm @register="register">
4   - <template #outputParamSlot>
5   - <div>
6   - <template v-for="(item, index) in outputParamData" :key="item">
7   - <span style="display: none">{{ item + index }}</span>
8   - <InputParamItem
9   - :title="item.name"
10   - :item="item"
11   - class="mt-4"
12   - :index="item.id"
13   - :ref="dynamicBindRef.outputParamItemRef"
14   - @delete="deleteOutParItem"
15   - @edit="editOutParItem"
16   - />
17   - </template>
18   - <div style="display: flex" :class="{ 'mt-2': outputParamData.length > 0 }">
19   - <span class="add-style">+</span>
20   - <span class="add-style" @click="handleAddOutParam">增加参数</span>
21   - </div>
22   - </div>
23   - </template>
24   - </BasicForm>
25   - <AddParamsModal @register="registerModal" @data="getData" />
  3 + <BasicForm @register="register" />
26 4 </div>
27 5 </template>
28 6 <script lang="ts" setup>
29   - import { ref, unref } from 'vue';
30 7 import { BasicForm, useForm } from '/@/components/Form';
31   - import { attrSchemas } from './config';
32   - import { useModal } from '/@/components/Modal';
33   - import InputParamItem from './components/InputParamItem.vue';
34   - import AddParamsModal from './components/AddParamsModal.vue';
35   - import { validateValueStruct } from '../hook/useValidateParital';
36   - import { useChangeTypeGetTypeForm } from '../hook/useTypeGetForm';
37   - import { buildUUID } from '/@/utils/uuid';
  8 + import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  9 + import { formSchemas } from '/@/components/Form/src/externalCompns/components/StructForm/config';
  10 + import { transformFormValue } from '/@/components/Form/src/externalCompns/components/StructForm/util';
  11 + import {
  12 + StructFormValue,
  13 + StructRecord,
  14 + } from '/@/components/Form/src/externalCompns/components/StructForm/type';
38 15
39   - const outputParamData: any = ref([]);
40   - const dynamicBindRef = {
41   - outputParamItemRef: ref([]),
42   - };
43   -
44   - const [registerModal, { openModal }] = useModal();
45   -
46   - const [register, { validate, setFieldsValue, resetFields }] = useForm({
  16 + const [register, { validate, resetFields, setFieldsValue }] = useForm({
47 17 labelWidth: 100,
48   - schemas: attrSchemas,
  18 + schemas: formSchemas,
49 19 actionColOptions: {
50 20 span: 14,
51 21 },
... ... @@ -54,112 +24,38 @@
54 24 showActionButtonGroup: false,
55 25 });
56 26
57   - const getData = (d, f) => {
58   - if (f == 'output') {
59   - if (d.id !== null) {
60   - const findIndex = unref(outputParamData).findIndex((f) => f.id == d.id);
61   - if (findIndex !== -1) unref(outputParamData).splice(findIndex, 1, d);
62   - } else {
63   - unref(outputParamData).push({ ...d, id: buildUUID() });
64   - }
65   - }
66   - };
67   -
68   - const handleAddOutParam = () => {
69   - openModal(true, {
70   - isUpdate: true,
71   - flag: 'output',
72   - excludeStruct: true,
73   - });
74   - };
75   -
76   - const deleteOutParItem = (index) => {
77   - unref(outputParamData).splice(index, 1);
78   - };
79   -
80   - const editOutParItem = (item) => {
81   - openModal(true, {
82   - isUpdate: false,
83   - record: item,
84   - flag: 'output',
85   - excludeStruct: true,
86   - });
87   - };
88   -
89   - const setTypeData = (T, D) => {
90   - if (T === 'INT' || T === 'DOUBLE' || T === 'TEXT') {
91   - return {
92   - ...D?.dataSpecs,
93   - valueRange: D?.dataSpecs,
94   - };
95   - } else if (T === 'BOOL') {
96   - return {
97   - boolClose: D?.dataSpecsList[0]?.name,
98   - boolOpen: D?.dataSpecsList[1]?.name,
99   - };
100   - }
101   - };
102   -
103   - //回显数据
104   - const setFormData = (v) => {
105   - setFieldsValue({ ...v[0] });
106   - setFieldsValue(setTypeData(v[0].dataType, v[0]));
107   - const { dataSpecsList } = v[0];
108   - if (dataSpecsList !== undefined) {
109   - outputParamData.value = [...new Array(dataSpecsList.length).keys()];
110   - outputParamData.value = dataSpecsList;
111   - }
112   - };
  27 + async function getFormData(): Promise<Partial<ModelOfMatterParams>> {
  28 + const _values = (await validate()) as StructFormValue;
  29 + if (!_values) return {};
  30 + let value = transformFormValue(_values);
  31 + return value;
  32 + }
113 33
114   - //获取结构体数据
115   - const getStructList = () => {
116   - const val = unref(dynamicBindRef.outputParamItemRef)?.map((item: any) => item.getFormData());
117   - return val;
  34 + const resetFormData = () => {
  35 + resetFields();
118 36 };
119 37
120   - const getBoolOrStructData = (T, S, B) => {
121   - if (T === 'STRUCT') {
122   - return S;
123   - } else {
124   - return B;
125   - }
126   - };
  38 + const setFormData = (record: StructRecord) => {
  39 + const { functionJson } = record as StructRecord;
  40 + const { specs = {} } = functionJson || ({} as StructRecord['functionJson']);
127 41
128   - async function getFormData() {
129   - const values = await validate();
130   - if (!values) return;
131   - const dataSpecsList = getStructList();
132   - if (values.dataType === 'STRUCT') {
133   - validateValueStruct(dataSpecsList as any);
134   - }
135   - const dataSpecs = useChangeTypeGetTypeForm(values.dataType, values);
136   - const dataSpecsListBool = useChangeTypeGetTypeForm(values.dataType, values);
137   - const { valueRange, step, unit, outputParam, ...value } = values;
138   - const none = {
139   - ...outputParam,
140   - ...step,
141   - ...unit,
142   - ...valueRange,
143   - };
144   - console.log(none);
145   - return {
146   - ...value,
147   - ...{ dataSpecs },
148   - ...{
149   - dataSpecsList: getBoolOrStructData(values.dataType, dataSpecsList, dataSpecsListBool),
  42 + const value = {
  43 + ...record,
  44 + ...functionJson,
  45 + ...specs,
  46 + valueRange: {
  47 + min: specs.min,
  48 + max: specs.max,
150 49 },
151 50 };
152   - }
153 51
154   - const resetFormData = () => {
155   - resetFields();
156   - outputParamData.value = [];
  52 + setFieldsValue(value);
157 53 };
158 54
159 55 defineExpose({
160   - setFormData,
161 56 resetFormData,
162 57 getFormData,
  58 + setFormData,
163 59 });
164 60 </script>
165 61 <style lang="less" scoped>
... ...
... ... @@ -3,20 +3,20 @@
3 3 <BasicForm @register="registerForm">
4 4 <template #structSlot>
5 5 <div>
6   - <template v-for="(item, index) in outputParamData" :key="item">
7   - <span style="display: none">{{ item }}</span>
  6 + <template v-for="item in outputParamData" :key="item.id">
  7 + <span class="hidden">{{ item }}</span>
8 8 <InputParamItem
9   - :title="item.name"
10 9 :item="item"
11 10 class="mt-4"
12   - :index="index"
13 11 :ref="dynamicBindRef.outputParamItemRef"
14 12 @delete="deleteOutParItem"
15 13 @edit="editOutParItem"
16 14 />
17 15 </template>
18   - <div style="display: flex" :class="{ 'mt-2': outputParamData.length > 0 }">
19   - <span class="add-style">+</span>
  16 + <div class="flex" :class="{ 'mt-2': outputParamData.length > 0 }">
  17 + <span class="add-style">
  18 + <PlusOutlined />
  19 + </span>
20 20 <span class="add-style" @click="handleAddOutParam">增加参数</span>
21 21 </div>
22 22 </div>
... ... @@ -28,21 +28,28 @@
28 28 <script lang="ts" setup>
29 29 import { ref, unref } from 'vue';
30 30 import { BasicForm, useForm } from '/@/components/Form';
31   - import { addParamsSchemas } from '../config';
  31 + import { addParamsSchemas, FormField } from '../config';
32 32 import { useModal } from '/@/components/Modal';
33 33 import InputParamItem from './InputParamItem.vue';
34 34 import AddParamsModal from './AddParamsModal.vue';
35 35 import { buildUUID } from '/@/utils/uuid';
36   - import { useChangeTypeGetTypeForm, useUpdateFormExcludeStruct } from '../../hook/useTypeGetForm';
  36 + import { PlusOutlined } from '@ant-design/icons-vue';
  37 + import { FunctionJson, ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  38 + import { transformFormValue } from '/@/components/Form/src/externalCompns/components/StructForm/util';
  39 + import { StructFormValue } from '/@/components/Form/src/externalCompns/components/StructForm/type';
  40 + type OutputParam = FunctionJson & { id: string };
37 41
38 42 defineEmits(['register']);
39   - const outputParamData: any = ref([]);
  43 +
  44 + const outputParamData = ref<OutputParam[]>([]);
  45 +
40 46 const dynamicBindRef = {
41 47 outputParamItemRef: ref([]),
42 48 };
  49 +
43 50 const [registerModal, { openModal }] = useModal();
44 51
45   - const [registerForm, { validate, setFieldsValue, resetFields, updateSchema }] = useForm({
  52 + const [registerForm, { validate, resetFields, updateSchema }] = useForm({
46 53 labelWidth: 100,
47 54 schemas: addParamsSchemas,
48 55 actionColOptions: {
... ... @@ -53,15 +60,8 @@
53 60 showActionButtonGroup: false,
54 61 });
55 62
56   - const getData = (d, f) => {
57   - if (f == 'output') {
58   - if (d.id !== null) {
59   - const findIndex = unref(outputParamData).findIndex((f) => f.id == d.id);
60   - if (findIndex !== -1) unref(outputParamData).splice(findIndex, 1, d);
61   - } else {
62   - unref(outputParamData).push({ ...d, id: buildUUID() });
63   - }
64   - }
  63 + const getData = (value: FunctionJson) => {
  64 + unref(outputParamData).push({ ...value, id: buildUUID() });
65 65 };
66 66
67 67 const handleAddOutParam = () => {
... ... @@ -72,11 +72,12 @@
72 72 });
73 73 };
74 74
75   - const deleteOutParItem = (index) => {
76   - unref(outputParamData).splice(index, 1);
  75 + const deleteOutParItem = (value: OutputParam) => {
  76 + const index = unref(outputParamData).findIndex((item) => item.id === value.id);
  77 + ~index && unref(outputParamData).splice(index, 1);
77 78 };
78 79
79   - const editOutParItem = (item) => {
  80 + const editOutParItem = (item: FunctionJson) => {
80 81 openModal(true, {
81 82 isUpdate: false,
82 83 record: item,
... ... @@ -85,98 +86,26 @@
85 86 });
86 87 };
87 88
88   - const updateFormExcludeStruct = (flag) => useUpdateFormExcludeStruct(flag, updateSchema);
89   -
90   - const getOutputStructList = () =>
91   - unref(dynamicBindRef.outputParamItemRef)?.map((item: any) => item.getFormData());
92   -
93   - const getBoolOrStruct = (T, S, B) => {
94   - if (T === 'STRUCT') {
95   - return S;
96   - } else if (T === 'INT' || T === 'DOUBLE' || T === 'TEXT') {
97   - return null;
98   - } else {
99   - return B;
100   - }
101   - };
102   -
103   - const getIntOrText = (T, D) => {
104   - if (T === 'STRUCT') {
105   - return null;
106   - } else if (T === 'INT' || T === 'DOUBLE' || T === 'TEXT') {
107   - return D;
108   - }
109   - };
110   -
111   - const getFormData = async () => {
112   - const values = await validate();
113   - if (!values) return;
114   - const outputParams = getOutputStructList();
115   - outputParams.forEach((f) => {
116   - f.dataType = 'STRUCT';
117   - f.childDataType = values.dataType;
118   - f.childName = values.name;
  89 + const updateFormExcludeStruct = () => {
  90 + const options = useUpdateFormExcludeStruct();
  91 + updateSchema({
  92 + field: FormField.TYPE,
  93 + componentProps: { options },
119 94 });
120   - const dataSpecs = useChangeTypeGetTypeForm(values.dataType, values);
121   - const dataSpecsList = useChangeTypeGetTypeForm(values.dataType, values);
122   - const { boolClose, boolOpen, step, unit, valueRange, ...value } = values;
123   - const none = {
124   - ...boolClose,
125   - ...boolOpen,
126   - ...step,
127   - ...unit,
128   - ...valueRange,
129   - };
130   - console.log(none);
131   - return {
132   - ...value,
133   - ...{
134   - dataSpecs: getIntOrText(values.dataType, dataSpecs),
135   - },
136   - // ...{
137   - // childSpecsDTO: getIntOrText(values.dataType, dataSpecs),
138   - // },
139   - ...{
140   - dataSpecsList: getBoolOrStruct(values.dataType, outputParams, dataSpecsList),
141   - },
142   - // ...{ childEnumSpecsDTO: getBoolOrStruct(values.dataType, outputParams, dataSpecsList) },
143   - // ...{
144   - // childDataType: values.dataType,
145   - // childName: values.name,
146   - // },
147   - };
148 95 };
149 96
150   - const setFormData = (v) => {
151   - setFieldsValue(v);
152   - setFieldsValue({
153   - ...v.dataSpecs,
154   - valueRange: v.dataSpecs,
155   - });
  97 + const getFormData = async (): Promise<Partial<ModelOfMatterParams>> => {
156 98 try {
157   - setFieldsValue({
158   - boolClose: v.dataType == 'BOOL' ? v.dataSpecsList[0].name : '',
159   - boolOpen: v.dataType == 'BOOL' ? v.dataSpecsList[1].name : '',
160   - });
161   - } catch (e) {
162   - console.log(e);
163   - }
164   - const { dataSpecsList, dataType, childDataType } = v;
165   - if (childDataType == 'BOOL') {
166   - setFieldsValue({
167   - dataType: childDataType,
168   - boolClose: dataSpecsList[0].name,
169   - boolOpen: dataSpecsList[1].name,
170   - });
171   - }
172   - try {
173   - if (dataType == 'BOOL' || dataType == 'STRUCT') {
174   - outputParamData.value = [...new Array(dataSpecsList.length).keys()];
175   - outputParamData.value = dataSpecsList;
176   - }
177   - } catch (e) {
178   - console.log(e);
179   - }
  99 + const values = (await validate()) as StructFormValue;
  100 + if (!values) return {} as unknown as ModelOfMatterParams;
  101 + const functionJson = transformFormValue(values);
  102 + return functionJson;
  103 + } catch (error) {}
  104 + return {} as unknown as ModelOfMatterParams;
  105 + };
  106 +
  107 + const setFormData = (value: FunctionJson) => {
  108 + setFormData(value);
180 109 };
181 110
182 111 const resetFormData = () => {
... ...
... ... @@ -17,7 +17,6 @@
17 17 import { ref, computed, reactive } from 'vue';
18 18 import { BasicModal, useModalInner } from '/@/components/Modal';
19 19 import AddParamForm from './AddParamForm.vue';
20   - import { validateValueStruct } from '../../hook/useValidateParital';
21 20
22 21 const emits = defineEmits(['register', 'data']);
23 22 const setEditData: any = reactive({
... ... @@ -29,9 +28,9 @@
29 28 const excludeStruct = ref(false);
30 29 const getTitle = computed(() => (!isUpdate.value ? '编辑参数' : '新增参数'));
31 30
32   - const [register, { closeModal, setModalProps }] = useModalInner(async (data) => {
  31 + const [register, { setModalProps }] = useModalInner(async (data) => {
33 32 setModalProps({ loading: true });
34   - handleCancel(false);
  33 +
35 34 isUpdate.value = data.isUpdate;
36 35 isFlag.value = data.flag;
37 36 excludeStruct.value = data.excludeStruct;
... ... @@ -45,29 +44,15 @@
45 44 }
46 45 });
47 46
48   - const handleCancel = (flag) => {
  47 + const handleCancel = () => {
49 48 AddParamFormRef.value?.resetFormData();
50   - if (flag) {
51   - closeModal();
52   - }
53 49 };
54 50
55 51 const handleSubmit = async () => {
56 52 const value = await AddParamFormRef.value?.getFormData();
57 53 if (!value) return;
58   - if (value.dataType === 'STRUCT') {
59   - validateValueStruct(value.dataSpecsList as any);
60   - }
61   - emits(
62   - 'data',
63   - {
64   - ...value,
65   - ...{ id: !isUpdate.value ? setEditData.getEditData.id : null },
66   - ...{ index: !isUpdate.value ? setEditData.getEditData.index : null },
67   - },
68   - isFlag.value
69   - );
70   - handleCancel(true);
  54 + emits('data', value);
  55 + handleCancel();
71 56 };
72 57 </script>
73 58 <style lang="less" scope></style>
... ...
1 1 <template>
2 2 <div>
3   - <a-card :title="`参数名称:${title}`" style="width: 540px; margin-top: -5px">
  3 + <a-card :title="`参数名称:${item.id}`" style="width: 540px; margin-top: -5px">
4 4 <template #extra>
5 5 <div style="display: flex; align-items: center">
6   - <span style="color: #0170cc; cursor: pointer" @click="handleEdit(item, index)">编辑</span>
  6 + <span style="color: #0170cc; cursor: pointer" @click="handleEdit">编辑</span>
7 7 <a-divider type="vertical" style="height: 12px; background-color: #d8d8d8" />
8   - <span style="color: #0170cc; cursor: pointer" class="ml-1" @click="handleDelete(index)"
  8 + <span style="color: #0170cc; cursor: pointer" class="ml-1" @click="handleDelete"
9 9 >删除</span
10 10 >
11 11 </div>
... ... @@ -14,33 +14,26 @@
14 14 </div>
15 15 </template>
16 16 <script lang="ts" setup>
  17 + import { FunctionJson } from '/@/api/device/model/modelOfMatterModel';
  18 +
17 19 const emit = defineEmits(['delete', 'edit']);
  20 +
  21 + type ItemRecrod = FunctionJson & { id: string };
  22 +
18 23 const props = defineProps({
19   - index: {
20   - type: Number,
21   - required: true,
22   - },
23   - title: {
24   - type: String,
25   - default: '',
26   - },
27 24 item: {
28   - type: Object,
  25 + type: Object as PropType<ItemRecrod>,
29 26 required: true,
30 27 default: () => {},
31 28 },
32 29 });
33 30
34   - const handleDelete = (index) => {
35   - emit('delete', index);
  31 + const handleDelete = () => {
  32 + emit('delete', props.item);
36 33 };
37 34
38   - const handleEdit = (item, index) => {
39   - const value = {
40   - ...item,
41   - ...{ index },
42   - };
43   - emit('edit', value);
  35 + const handleEdit = () => {
  36 + emit('edit', props.item);
44 37 };
45 38
46 39 const getFormData = () => {
... ...
1 1 import { FormSchema } from '/@/components/Table';
2 2 import { findDictItemByCode } from '/@/api/system/dict';
3 3
  4 +export enum FormField {
  5 + FUNCTION_NAME = 'functionName',
  6 + FUNCTION_TYPE = 'functionType',
  7 + FUNCTION_JSON = 'functionJson',
  8 + IDENTIFIER = 'identifier',
  9 + TYPE = 'type',
  10 + REFARK = 'remark',
  11 + MIN = 'min',
  12 + MAX = 'max',
  13 + UNIT = 'unit',
  14 + UNIT_NAME = 'unitName',
  15 + STEP = 'step',
  16 + VALUE_RANGE = 'valueRange',
  17 + BOOL_CLOSE = 'boolClose',
  18 + BOOL_OPEN = 'boolOpen',
  19 + LENGTH = 'length',
  20 + R_W_FLAG = 'rwFlag',
  21 + SPECS_LIST = 'specsList',
  22 + CALL_TYPE = 'callType',
  23 + INPUT_PARAM = 'inputParam',
  24 + EVENT_TYPE = 'eventType',
  25 +
  26 + STRUCT = 'struct',
  27 +}
  28 +
  29 +export enum FunctionType {
  30 + PROPERTIES = 'properties',
  31 + EVENTS = 'events',
  32 + SERVICE = 'services',
  33 +}
  34 +
  35 +/**
  36 + * 新增参数 动态显示表单
  37 + */
  38 +export enum DateTypeEnum {
  39 + IS_NUMBER_INT = 'INT',
  40 + IS_NUMBER_DOUBLE = 'DOUBLE',
  41 + IS_STRING = 'TEXT',
  42 + IS_STRUCT = 'STRUCT',
  43 + IS_BOOL = 'BOOL',
  44 +}
  45 +
  46 +const isNumber = (type: string) => {
  47 + return type === DateTypeEnum.IS_NUMBER_INT || type === DateTypeEnum.IS_NUMBER_DOUBLE;
  48 +};
  49 +
  50 +const isString = (type: string) => {
  51 + return type === DateTypeEnum.IS_STRING;
  52 +};
  53 +const isStruct = (type: string) => {
  54 + return type === DateTypeEnum.IS_STRUCT;
  55 +};
  56 +
  57 +const isBool = (type: string) => {
  58 + return type === DateTypeEnum.IS_BOOL;
  59 +};
  60 +
4 61 export const defaultTslContent = {
5 62 schema: 'https://iotx-tsl.oss-ap-southeast-1.aliyuncs.com/schema.json',
6 63 profile: {
... ... @@ -24,180 +81,9 @@ export const defaultTslContent = {
24 81 ],
25 82 };
26 83
27   -export const attrSchemas: FormSchema[] = [
28   - {
29   - field: 'name',
30   - label: '功能名称',
31   - required: true,
32   - component: 'Input',
33   - colProps: {
34   - span: 18,
35   - },
36   - componentProps: {
37   - maxLength: 255,
38   - placeholder: '请输入功能名称',
39   - },
40   - },
41   - {
42   - field: 'identifier',
43   - label: '标识符',
44   - required: true,
45   - component: 'Input',
46   - colProps: {
47   - span: 18,
48   - },
49   - componentProps: {
50   - maxLength: 255,
51   - placeholder: '请输入标识符',
52   - },
53   - },
54   - {
55   - field: 'dataType',
56   - label: '数据类型',
57   - required: true,
58   - component: 'ApiSelect',
59   - colProps: {
60   - span: 9,
61   - },
62   - defaultValue: 'INT',
63   - componentProps: {
64   - placeholder: '请选择数据类型',
65   - api: findDictItemByCode,
66   - params: {
67   - dictCode: 'data_type',
68   - },
69   - labelField: 'itemText',
70   - valueField: 'itemValue',
71   - },
72   - },
73   - {
74   - field: 'valueRange',
75   - label: '取值范围',
76   - component: 'CustomeMinMaxInput',
77   - colProps: {
78   - span: 18,
79   - },
80   - ifShow: ({ values }) => isNumber(values.dataType),
81   - },
82   - {
83   - field: 'step',
84   - label: '步长',
85   - component: 'Input',
86   - colProps: {
87   - span: 18,
88   - },
89   - componentProps: {
90   - maxLength: 255,
91   - placeholder: '请输入步长',
92   - },
93   - ifShow: ({ values }) => isNumber(values.dataType),
94   - },
95   - {
96   - field: 'unit',
97   - label: '单位',
98   - component: 'ApiSelect',
99   - colProps: {
100   - span: 9,
101   - },
102   - componentProps: {
103   - placeholder: '请选择单位',
104   - api: findDictItemByCode,
105   - params: {
106   - dictCode: 'attribute_unit',
107   - },
108   - labelField: 'itemText',
109   - valueField: 'itemValue',
110   - },
111   - ifShow: ({ values }) => isNumber(values.dataType),
112   - },
113   - {
114   - field: 'boolClose',
115   - component: 'Input',
116   - required: true,
117   - label: '0 -',
118   - colProps: {
119   - span: 18,
120   - },
121   - componentProps: {
122   - placeholder: '如:关',
123   - },
124   - ifShow: ({ values }) => isBool(values.dataType),
125   - },
126   - {
127   - field: 'boolOpen',
128   - component: 'Input',
129   - required: true,
130   - label: '1 -',
131   - colProps: {
132   - span: 18,
133   - },
134   - componentProps: {
135   - placeholder: '如:开',
136   - },
137   - ifShow: ({ values }) => isBool(values.dataType),
138   - },
139   - {
140   - field: 'length',
141   - component: 'Input',
142   - required: true,
143   - label: '数据长度',
144   - defaultValue: '10240',
145   - colProps: {
146   - span: 8,
147   - },
148   - componentProps: {
149   - placeholder: '请输入数据长度',
150   - },
151   - renderComponentContent: () => {
152   - return {
153   - suffix: () => '字节',
154   - };
155   - },
156   - ifShow: ({ values }) => isString(values.dataType),
157   - },
158   - {
159   - field: 'rwFlag',
160   - component: 'ApiRadioGroup',
161   - label: '读写类型',
162   - required: true,
163   - colProps: {
164   - span: 24,
165   - },
166   - defaultValue: 'READ_ONLY',
167   - componentProps: {
168   - placeholder: '请选择读写类型',
169   - api: findDictItemByCode,
170   - params: {
171   - dictCode: 'read_write_type',
172   - },
173   - labelField: 'itemText',
174   - valueField: 'itemValue',
175   - },
176   - },
177   - {
178   - field: 'outputParam',
179   - label: 'JSON 对象',
180   - component: 'Input',
181   - // required: true,
182   - slot: 'outputParamSlot',
183   - colProps: { span: 24 },
184   - ifShow: ({ values }) => isStruct(values.dataType),
185   - },
186   - {
187   - label: '描述',
188   - field: 'description',
189   - component: 'InputTextArea',
190   - componentProps: {
191   - rows: 6,
192   - maxLength: 100,
193   - placeholder: '请输入描述',
194   - },
195   - },
196   -];
197   -
198 84 export const serviceSchemas: FormSchema[] = [
199 85 {
200   - field: 'serviceName',
  86 + field: FormField.FUNCTION_NAME,
201 87 label: '功能名称',
202 88 required: true,
203 89 component: 'Input',
... ... @@ -210,7 +96,7 @@ export const serviceSchemas: FormSchema[] = [
210 96 },
211 97 },
212 98 {
213   - field: 'identifier',
  99 + field: FormField.IDENTIFIER,
214 100 label: '标识符',
215 101 required: true,
216 102 component: 'Input',
... ... @@ -223,7 +109,7 @@ export const serviceSchemas: FormSchema[] = [
223 109 },
224 110 },
225 111 {
226   - field: 'callType',
  112 + field: FormField.CALL_TYPE,
227 113 component: 'ApiRadioGroup',
228 114 label: '调用方式',
229 115 required: true,
... ... @@ -242,22 +128,22 @@ export const serviceSchemas: FormSchema[] = [
242 128 },
243 129 },
244 130 {
245   - field: 'inputParam',
  131 + field: FormField.INPUT_PARAM,
246 132 label: '输入参数',
247 133 component: 'Input',
248 134 slot: 'inputParamSlot',
249 135 colProps: { span: 24 },
250 136 },
251 137 {
252   - field: 'outputParam',
  138 + field: FormField.SPECS_LIST,
253 139 label: '输出参数',
254 140 component: 'Input',
255 141 slot: 'outputParamSlot',
256 142 colProps: { span: 24 },
257 143 },
258 144 {
259   - label: '描述',
260   - field: 'description',
  145 + field: FormField.REFARK,
  146 + label: '备注',
261 147 component: 'InputTextArea',
262 148 componentProps: {
263 149 rows: 6,
... ... @@ -269,7 +155,7 @@ export const serviceSchemas: FormSchema[] = [
269 155
270 156 export const eventSchemas: FormSchema[] = [
271 157 {
272   - field: 'eventName',
  158 + field: FormField.FUNCTION_NAME,
273 159 label: '功能名称',
274 160 required: true,
275 161 component: 'Input',
... ... @@ -282,7 +168,7 @@ export const eventSchemas: FormSchema[] = [
282 168 },
283 169 },
284 170 {
285   - field: 'identifier',
  171 + field: FormField.IDENTIFIER,
286 172 label: '标识符',
287 173 required: true,
288 174 component: 'Input',
... ... @@ -295,7 +181,7 @@ export const eventSchemas: FormSchema[] = [
295 181 },
296 182 },
297 183 {
298   - field: 'eventType',
  184 + field: FormField.EVENT_TYPE,
299 185 component: 'ApiRadioGroup',
300 186 label: '事件类型',
301 187 required: true,
... ... @@ -314,15 +200,15 @@ export const eventSchemas: FormSchema[] = [
314 200 },
315 201 },
316 202 {
317   - field: 'outputParam',
  203 + field: FormField.SPECS_LIST,
318 204 label: '输出参数',
319 205 component: 'Input',
320 206 slot: 'outputParamSlot',
321 207 colProps: { span: 24 },
322 208 },
323 209 {
324   - label: '描述',
325   - field: 'description',
  210 + field: FormField.REFARK,
  211 + label: '备注',
326 212 component: 'InputTextArea',
327 213 componentProps: {
328 214 rows: 6,
... ... @@ -332,34 +218,9 @@ export const eventSchemas: FormSchema[] = [
332 218 },
333 219 ];
334 220
335   -/**
336   - * 新增参数 动态显示表单
337   - */
338   -enum DateTypeEnum {
339   - IS_NUMBER_INT = 'INT',
340   - IS_NUMBER_DOUBLE = 'DOUBLE',
341   - IS_STRING = 'TEXT',
342   - IS_STRUCT = 'STRUCT',
343   - IS_BOOL = 'BOOL',
344   -}
345   -const isNumber = (type: string) => {
346   - return type === DateTypeEnum.IS_NUMBER_INT || type === DateTypeEnum.IS_NUMBER_DOUBLE;
347   -};
348   -
349   -const isString = (type: string) => {
350   - return type === DateTypeEnum.IS_STRING;
351   -};
352   -const isStruct = (type: string) => {
353   - return type === DateTypeEnum.IS_STRUCT;
354   -};
355   -
356   -const isBool = (type: string) => {
357   - return type === DateTypeEnum.IS_BOOL;
358   -};
359   -
360 221 export const addParamsSchemas: FormSchema[] = [
361 222 {
362   - field: 'name',
  223 + field: FormField.FUNCTION_NAME,
363 224 label: '参数名称',
364 225 required: true,
365 226 component: 'Input',
... ... @@ -372,7 +233,7 @@ export const addParamsSchemas: FormSchema[] = [
372 233 },
373 234 },
374 235 {
375   - field: 'identifier',
  236 + field: FormField.IDENTIFIER,
376 237 label: '标识符',
377 238 required: true,
378 239 component: 'Input',
... ... @@ -385,7 +246,7 @@ export const addParamsSchemas: FormSchema[] = [
385 246 },
386 247 },
387 248 {
388   - field: 'dataType',
  249 + field: FormField.TYPE,
389 250 label: '数据类型',
390 251 required: true,
391 252 component: 'ApiSelect',
... ... @@ -404,17 +265,16 @@ export const addParamsSchemas: FormSchema[] = [
404 265 },
405 266 },
406 267 {
407   - field: 'structSlot',
  268 + field: FormField.STRUCT,
408 269 label: 'JSON 对象',
409 270 component: 'Input',
410   - slot: 'structSlot',
411 271 colProps: {
412 272 span: 23,
413 273 },
414   - ifShow: ({ values }) => isStruct(values.dataType),
  274 + ifShow: ({ values }) => isStruct(values[FormField.TYPE]),
415 275 },
416 276 {
417   - field: 'boolClose',
  277 + field: FormField.BOOL_CLOSE,
418 278 component: 'Input',
419 279 required: true,
420 280 label: '0 -',
... ... @@ -424,10 +284,10 @@ export const addParamsSchemas: FormSchema[] = [
424 284 componentProps: {
425 285 placeholder: '如:关',
426 286 },
427   - ifShow: ({ values }) => isBool(values.dataType),
  287 + ifShow: ({ values }) => isBool(values[FormField.TYPE]),
428 288 },
429 289 {
430   - field: 'boolOpen',
  290 + field: FormField.BOOL_OPEN,
431 291 component: 'Input',
432 292 required: true,
433 293 label: '1 -',
... ... @@ -437,10 +297,10 @@ export const addParamsSchemas: FormSchema[] = [
437 297 componentProps: {
438 298 placeholder: '如:开',
439 299 },
440   - ifShow: ({ values }) => isBool(values.dataType),
  300 + ifShow: ({ values }) => isBool(values[FormField.TYPE]),
441 301 },
442 302 {
443   - field: 'length',
  303 + field: FormField.LENGTH,
444 304 component: 'Input',
445 305 required: true,
446 306 label: '数据长度',
... ... @@ -456,19 +316,19 @@ export const addParamsSchemas: FormSchema[] = [
456 316 suffix: () => '字节',
457 317 };
458 318 },
459   - ifShow: ({ values }) => isString(values.dataType),
  319 + ifShow: ({ values }) => isString(values[FormField.TYPE]),
460 320 },
461 321 {
462   - field: 'valueRange',
  322 + field: FormField.VALUE_RANGE,
463 323 label: '取值范围',
464   - component: 'CustomeMinMaxInput',
  324 + component: 'CustomMinMaxInput',
465 325 colProps: {
466 326 span: 23,
467 327 },
468   - ifShow: ({ values }) => isNumber(values.dataType),
  328 + ifShow: ({ values }) => isNumber(values[FormField.TYPE]),
469 329 },
470 330 {
471   - field: 'step',
  331 + field: FormField.STEP,
472 332 label: '步长',
473 333 component: 'Input',
474 334 colProps: {
... ... @@ -478,10 +338,10 @@ export const addParamsSchemas: FormSchema[] = [
478 338 maxLength: 255,
479 339 placeholder: '请输入步长',
480 340 },
481   - ifShow: ({ values }) => isNumber(values.dataType),
  341 + ifShow: ({ values }) => isNumber(values[FormField.TYPE]),
482 342 },
483 343 {
484   - field: 'unit',
  344 + field: FormField.UNIT,
485 345 label: '单位',
486 346 component: 'ApiSelect',
487 347 colProps: {
... ... @@ -496,6 +356,6 @@ export const addParamsSchemas: FormSchema[] = [
496 356 labelField: 'itemText',
497 357 valueField: 'itemValue',
498 358 },
499   - ifShow: ({ values }) => isNumber(values.dataType),
  359 + ifShow: ({ values }) => isNumber(values[FormField.TYPE]),
500 360 },
501 361 ];
... ...
1   -import { validateValueBool, validateValueRangeAndStep } from './useValidateParital';
2   -import { findDictItemByCode } from '/@/api/system/dict';
3   -
4   -///根据不同数据类型得到不同表单数据
5   -type TForm = {
6   - dataType: string;
7   - max?: string;
8   - min?: string;
9   - step?: string;
10   - unit?: string;
11   - boolClose?: string;
12   - boolOpen?: string;
13   - length?: string;
14   - valueRange?: {
15   - min: string;
16   - max: string;
17   - };
18   -};
19   -export const useChangeTypeGetTypeForm = (type, options: TForm) => {
20   - switch (type) {
21   - //INT和DOUBLE收集表单一样
22   - case 'INT':
23   - validateValueRangeAndStep(
24   - Number(options?.valueRange?.min),
25   - Number(options?.step),
26   - Number(options?.valueRange?.max)
27   - );
28   - return {
29   - dataType: options?.dataType,
30   - max: options?.valueRange?.max,
31   - min: options?.valueRange?.min,
32   - step: options?.step,
33   - unit: options?.unit,
34   - };
35   - case 'DOUBLE':
36   - validateValueRangeAndStep(
37   - Number(options?.valueRange?.min),
38   - Number(options?.step),
39   - Number(options?.valueRange?.max)
40   - );
41   - return {
42   - dataType: options?.dataType,
43   - max: options?.valueRange?.max,
44   - min: options?.valueRange?.min,
45   - step: options?.step,
46   - unit: options?.unit,
47   - };
48   - case 'BOOL':
49   - validateValueBool(Number(options?.boolClose), Number(options?.boolOpen));
50   - return [
51   - {
52   - dataType: options?.dataType,
53   - name: options?.boolClose,
54   - value: '0',
55   - },
56   - {
57   - dataType: options?.dataType,
58   - name: options?.boolOpen,
59   - value: '1',
60   - },
61   - ];
62   - case 'TEXT':
63   - return {
64   - dataType: options?.dataType,
65   - length: options?.length,
66   - };
67   - }
68   -};
69   -
70   -//是否排除结构体
71   -export const useUpdateFormExcludeStruct = async (F, U) => {
72   - const res: any = await findDictItemByCode({ dictCode: 'data_type' });
73   - const optionTrue = res
74   - .map((m) => {
75   - if (F) {
76   - if (m.itemValue !== 'STRUCT') {
77   - return {
78   - value: m.itemValue,
79   - label: m.itemText,
80   - };
81   - }
82   - } else {
83   - return {
84   - value: m.itemValue,
85   - label: m.itemText,
86   - };
87   - }
88   - })
89   - .filter(Boolean);
90   - U({
91   - field: 'dataType',
92   - componentProps: {
93   - options: optionTrue,
94   - },
95   - });
96   -};
1   -/**
2   - * 校验部分字段
3   - */
4   -import { useMessage } from '/@/hooks/web/useMessage';
5   -const { createMessage } = useMessage();
6   -
7   -export const validateValueRangeAndStep = (min, step, max) => {
8   - if (min > max) {
9   - createMessage.error('最大值必须大于最小值,整数型不能有小数位,单精度有效位为7,双精度为16');
10   - throw '最大值必须大于最小值,整数型不能有小数位,单精度有效位为7,双精度为16';
11   - }
12   - if (step > max - min) {
13   - createMessage.error('步长不能大于取值范围的差值');
14   - throw '步长不能大于取值范围的差值';
15   - }
16   -};
17   -
18   -export const validateValueBool = (boolClose, boolOpen) => {
19   - if (boolClose == boolOpen) {
20   - createMessage.error('布尔值不能相同');
21   - throw '布尔值不能相同';
22   - }
23   -};
24   -
25   -export const validateValueStruct = (data: []) => {
26   - if (data.length === 0) {
27   - createMessage.error('struct不能为空');
28   - throw 'struct不能为空';
29   - }
30   -};
  1 +import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel';
  2 +
  3 +export enum OpenModelMode {
  4 + UPDATE = 'update',
  5 + CREATE = 'create',
  6 + VIEW = 'view',
  7 +}
  8 +
  9 +export interface OpenModelOfMatterModelParams {
  10 + mode: OpenModelMode;
  11 + record: ModelOfMatterParams;
  12 +}
... ...