|
@@ -1,310 +0,0 @@
|
|
|
-<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>
|
|
|