|
|
|
<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 { getAllTopics } from '@/api/product/topic'
|
|
|
|
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 { 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: () => getAllTopics(productId!),
|
|
|
|
valueField: 'id',
|
|
|
|
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>
|