<script lang="ts" setup> import { BasicModal, useModalInner } from '@/components/Modal' import type { FormSchema, FormSchemaInner, Rule } from '@/components/Form' import { BasicForm, useForm } from '@/components/Form' import { CloudCommandType } from '@/api/device-manage/device/types' import { sendCommandToDevice, sendMessageToDevice } from '@/api/device-manage/device/cloud-command' import CodeEditor from '@/components/CodeEditor/src/CodeEditor.vue' import { getAllModelAttributes } from '@/api/product/model' import { getDeviceTopicList } from '@/api/device-manage/device' import { ModelAttributeDataTypesEnum, type SimpleAttribute } from '@/api/product/types' import { useMessage } from '@/hooks/web/useMessage' const emit = defineEmits(['register', 'success']) const [registerForm, { updateSchema, resetSchema, validate, setFieldsValue, clearValidate }] = useForm({ schemas: [], labelWidth: 100, baseColProps: { span: 24 }, showActionButtonGroup: false, actionColOptions: { span: 23 }, }) let productId: string let deviceId: string let commandType: CloudCommandType const CommandAndAttributeSchemas: FormSchema[] = [ { field: 'itemId', label: '选择属性', required: true, component: 'ApiSelect', componentProps: { api: () => getAllModelAttributes(productId!, commandType), valueField: 'id', labelField: 'name', allowClear: false, onChange(_, option: SimpleAttribute & { label: string }) { // label is SimpleAttribute.name if (!option) return const { dataType, label, dataSpecs, modelId } = option setFieldsValue({ modelId, value: undefined }) // avoid non-null check clearValidate() let schema: Partial<FormSchemaInner> = {} if (dataType === ModelAttributeDataTypesEnum.Bool) { schema = { rules: [], // remove rules cache component: 'RadioGroup', componentProps: { options: [ { label: dataSpecs.falseDesc, value: 0 }, { label: dataSpecs.trueDesc, value: 1 }, ], }, } } else { let rules: Rule[] = [] switch (dataType) { case ModelAttributeDataTypesEnum.Text: rules = [{ max: dataSpecs.maxLength, message: `限制最大长度为 ${dataSpecs.maxLength}` }] break case ModelAttributeDataTypesEnum.Float: case ModelAttributeDataTypesEnum.Int32: rules = [ { type: 'number', min: +dataSpecs.min, max: +dataSpecs.max, message: `数值范围为: ${dataSpecs.min}-${dataSpecs.max}` }, ] break default: { const _exhaustiveCheck: never = dataType return _exhaustiveCheck } } schema = { rules, // if it isn't text, then it's a float or int32 component: dataType === ModelAttributeDataTypesEnum.Text ? 'InputTextArea' : 'InputNumber', componentProps: dataType !== ModelAttributeDataTypesEnum.Text ? { precision: dataType === ModelAttributeDataTypesEnum.Float ? dataSpecs.scale : 0, } : { rows: 3 }, } } updateSchema({ label, field: 'value', ifShow: true, ...schema, }) }, }, }, { field: 'value', fields: ['modelId'], required: true, component: 'Input', ifShow: false, }, ] const MessageSchemas: FormSchema[] = [ { field: 'topic', label: 'Topic', required: true, component: 'ApiSelect', componentProps: { api: async () => (await getDeviceTopicList({ deviceId, current: 1, size: 500 })).records, valueField: 'topic', labelField: 'topic', }, }, { field: 'message', label: '指令内容', rules: [ { async validator(_, value) { try { const code = JSON.stringify(JSON.parse(value)) if (code === '{}') // eslint-disable-next-line unicorn/error-message throw new Error() } catch { // eslint-disable-next-line prefer-promise-reject-errors return Promise.reject('指令内容必须是 JSON 格式, 且不能为空') } }, required: true, }, ], slot: 'Message', helpMessage: '指令内容必须是 JSON 格式', defaultValue: {}, componentProps: { rows: 10, }, }, ] const [register, { closeModal, setModalProps }] = useModalInner((params: { type: CloudCommandType, productId: string, deviceId: string }) => { productId = params.productId deviceId = params.deviceId commandType = params.type resetSchema(commandType === CloudCommandType.Message ? MessageSchemas : CommandAndAttributeSchemas) }) async function handleSubmit() { try { const values = await validate<any>() setModalProps({ confirmLoading: true }) values.deviceId = deviceId const isSendMessage = commandType === CloudCommandType.Message await (isSendMessage ? sendMessageToDevice(values) : sendCommandToDevice(values)) useMessage().createMessage.success('下发成功') emit('success') closeModal() } catch {} finally { setModalProps({ confirmLoading: false }) } } </script> <template> <BasicModal v-bind="$attrs" :min-height="100" @register="register" @ok="handleSubmit" > <BasicForm @register="registerForm"> <template #Message="{ model, field }"> <div h="200px" border="1px solid gray-200" w-full overflow-hidden rounded> <CodeEditor v-model:value="model[field]" /> </div> </template> </BasicForm> </BasicModal> </template>