| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- <template>
- <Dialog v-model="dialogVisible" :title="dialogTitle" width="900px">
- <el-form
- ref="formRef"
- v-loading="formLoading"
- :model="formData"
- :rules="formRules"
- label-width="100px">
- <el-form-item label="功能标识" prop="identifier">
- <el-input v-model="formData.identifier" placeholder="请输入功能标识" />
- </el-form-item>
- <el-form-item label="功能名称" prop="name">
- <el-input v-model="formData.name" placeholder="请输入功能名称" />
- </el-form-item>
- <el-form-item label="功能描述" prop="description">
- <el-input
- v-model="formData.description"
- type="textarea"
- :rows="3"
- :maxlength="200"
- placeholder="请输入功能描述" />
- </el-form-item>
- <el-form-item label="功能类型" prop="type">
- <el-radio-group v-model="formData.type">
- <el-radio-button
- v-for="dict in getIntDictOptions(DICT_TYPE.IOT_THING_MODEL_TYPE)"
- :key="dict.value"
- :value="dict.value">
- {{ dict.label }}
- </el-radio-button>
- </el-radio-group>
- </el-form-item>
- <el-form-item v-if="formData.type === 1" label="属性" prop="property">
- <div class="json-editor-field">
- <div class="json-editor-toolbar">
- <span class="json-editor-toolbar__tip">请输入属性 JSON 数据</span>
- <div class="json-editor-toolbar__actions">
- <el-button text type="primary" @click="formatJsonField('property')">
- 美化 JSON
- </el-button>
- <el-button text @click="compressJsonField('property')">压缩 JSON</el-button>
- </div>
- </div>
- <v-ace-editor
- v-model:value="formData.property"
- lang="json"
- theme="monokai"
- class="json-editor"
- :options="editorOptions" />
- </div>
- </el-form-item>
- <el-form-item v-if="formData.type === 3" label="事件" prop="event">
- <div class="json-editor-field">
- <div class="json-editor-toolbar">
- <span class="json-editor-toolbar__tip">请输入事件 JSON 数据</span>
- <div class="json-editor-toolbar__actions">
- <el-button text type="primary" @click="formatJsonField('event')">美化 JSON</el-button>
- <el-button text @click="compressJsonField('event')">压缩 JSON</el-button>
- </div>
- </div>
- <v-ace-editor
- v-model:value="formData.event"
- lang="json"
- theme="monokai"
- class="json-editor"
- :options="editorOptions" />
- </div>
- </el-form-item>
- <el-form-item v-if="formData.type === 2" label="服务" prop="service">
- <div class="json-editor-field">
- <div class="json-editor-toolbar">
- <span class="json-editor-toolbar__tip">请输入服务 JSON 数据</span>
- <div class="json-editor-toolbar__actions">
- <el-button text type="primary" @click="formatJsonField('service')">
- 美化 JSON
- </el-button>
- <el-button text @click="compressJsonField('service')">压缩 JSON</el-button>
- </div>
- </div>
- <v-ace-editor
- v-model:value="formData.service"
- lang="json"
- theme="monokai"
- class="json-editor"
- :options="editorOptions" />
- </div>
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button :disabled="formLoading" type="primary" @click="submitForm">确定</el-button>
- <el-button @click="dialogVisible = false">取消</el-button>
- </template>
- </Dialog>
- </template>
- <script lang="ts" setup>
- import '@/components/mt-edit/ace-edit'
- import { VAceEditor } from 'vue3-ace-editor'
- import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
- import { ThingModelCommon, type CommonThingModelData } from '@/api/iot/thingmodel'
- defineOptions({ name: 'CommonThingModelForm' })
- const { t } = useI18n()
- const message = useMessage()
- const dialogVisible = ref(false)
- const dialogTitle = ref('')
- const formLoading = ref(false)
- const formType = ref('')
- const formRef = ref()
- const editorOptions = {
- useWorker: true,
- enableBasicAutocompletion: true,
- enableSnippets: true,
- enableLiveAutocompletion: true
- }
- const createDefaultFormData = (): CommonThingModelData => ({
- identifier: '',
- name: '',
- description: '',
- type: 1,
- property: '',
- event: '',
- service: ''
- })
- const formData = ref<CommonThingModelData>(createDefaultFormData())
- const getJsonFieldByType = () => {
- if (formData.value.type === 1) return 'property'
- if (formData.value.type === 2) return 'service'
- return 'event'
- }
- const tryFormatJson = (value?: string, indent = 2) => {
- if (!value) return ''
- const trimmed = value.trim()
- if (!trimmed) return ''
- return JSON.stringify(JSON.parse(trimmed), null, indent)
- }
- const formatJsonField = (field: 'property' | 'event' | 'service') => {
- try {
- formData.value[field] = tryFormatJson(formData.value[field], 2)
- message.success('JSON 已美化')
- } catch {
- message.warning('当前内容不是合法 JSON,无法美化')
- }
- }
- const compressJsonField = (field: 'property' | 'event' | 'service') => {
- try {
- formData.value[field] = tryFormatJson(formData.value[field], 0)
- message.success('JSON 已压缩')
- } catch {
- message.warning('当前内容不是合法 JSON,无法压缩')
- }
- }
- const validateJsonField = (field: 'property' | 'event' | 'service', label: string) => {
- return (_rule: any, value: string, callback: (error?: Error) => void) => {
- const currentType = formData.value.type
- const fieldTypeMap = {
- property: 1,
- service: 2,
- event: 3
- }
- if (currentType !== fieldTypeMap[field]) {
- callback()
- return
- }
- if (!value) {
- callback(new Error(`${label}不能为空`))
- return
- }
- try {
- JSON.parse(value)
- callback()
- } catch {
- callback(new Error(`${label}必须是合法的 JSON`))
- }
- }
- }
- const formRules = reactive({
- identifier: [{ required: true, message: '功能标识不能为空', trigger: 'blur' }],
- name: [{ required: true, message: '功能名称不能为空', trigger: 'blur' }],
- type: [{ required: true, message: '功能类型不能为空', trigger: 'change' }]
- // property: [{ validator: validateJsonField('property', '属性'), trigger: 'blur' }],
- // event: [{ validator: validateJsonField('event', '事件'), trigger: 'blur' }],
- // service: [{ validator: validateJsonField('service', '服务'), trigger: 'blur' }]
- })
- const open = async (type: string, id?: number) => {
- dialogVisible.value = true
- dialogTitle.value = t('action.' + type)
- formType.value = type
- resetForm()
- if (!id) return
- formLoading.value = true
- try {
- const data = await ThingModelCommon.getCommonThingModel(id)
- formData.value = {
- ...createDefaultFormData(),
- ...data
- }
- const activeField = getJsonFieldByType()
- if (formData.value[activeField]) {
- formData.value[activeField] = tryFormatJson(formData.value[activeField], 2)
- }
- } finally {
- formLoading.value = false
- }
- }
- defineExpose({ open, close: () => (dialogVisible.value = false) })
- const emit = defineEmits(['success'])
- const submitForm = async () => {
- await formRef.value.validate()
- formLoading.value = true
- try {
- const payload: CommonThingModelData = {
- ...formData.value,
- property: formData.value.type === 1 ? formData.value.property : '',
- service: formData.value.type === 2 ? formData.value.service : '',
- event: formData.value.type === 3 ? formData.value.event : ''
- }
- if (formType.value === 'create') {
- await ThingModelCommon.createCommonThingModel(payload)
- message.success(t('common.createSuccess'))
- } else {
- await ThingModelCommon.updateCommonThingModel(payload)
- message.success(t('common.updateSuccess'))
- }
- dialogVisible.value = false
- emit('success')
- } finally {
- formLoading.value = false
- }
- }
- const resetForm = () => {
- formData.value = createDefaultFormData()
- formRef.value?.resetFields()
- }
- watch(
- () => formData.value.type,
- () => {
- const activeField = getJsonFieldByType()
- if (formData.value[activeField]) {
- try {
- formData.value[activeField] = tryFormatJson(formData.value[activeField], 2)
- } catch {
- // Keep original input when JSON is incomplete during editing.
- }
- }
- }
- )
- </script>
- <style scoped>
- .json-editor-field {
- width: 100%;
- border: 1px solid var(--el-border-color);
- border-radius: 8px;
- overflow: hidden;
- background: #111827;
- }
- .json-editor-toolbar {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 12px;
- padding: 10px 12px;
- background: #1f2937;
- border-bottom: 1px solid rgb(255 255 255 / 0.08);
- }
- .json-editor-toolbar__tip {
- font-size: 12px;
- color: rgb(255 255 255 / 0.72);
- }
- .json-editor-toolbar__actions {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .json-editor {
- width: 100%;
- height: 320px;
- }
- </style>
|