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
176 lines
5.3 KiB
1 year ago
|
<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>
|