You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
5.3 KiB

<script lang="ts" setup>
import { useRoute } from 'vue-router'
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'
const props = defineProps<{ productId?: string, type?: CloudCommandType }>()
const emit = defineEmits(['register', 'success'])
const [registerForm, { updateSchema, resetSchema, validate, setFieldsValue, clearValidate }] = useForm({
schemas: [],
labelWidth: 100,
baseColProps: { span: 24 },
showActionButtonGroup: false,
actionColOptions: { span: 23 },
})
const CommandAndAttributeSchemas: FormSchema[] = [
{
field: 'itemId',
label: '选择属性',
required: true,
component: 'ApiSelect',
componentProps: {
api: () => getAllModelAttributes(props.productId!, props.type!),
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
}
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(props.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((type: CloudCommandType) => {
resetSchema(type === CloudCommandType.Message ? MessageSchemas : CommandAndAttributeSchemas)
})
const route = useRoute()
async function handleSubmit() {
try {
const values = await validate<any>()
setModalProps({ confirmLoading: true })
values.deviceId = route.params.id
const isSendMessage = props.type === CloudCommandType.Message
await (isSendMessage ? sendMessageToDevice(values) : sendCommandToDevice(values))
emit('success')
closeModal()
}
catch {
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>