From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/views/iot/rule/scene/form/inputs/JsonParamsInput.vue | 519 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 519 insertions(+), 0 deletions(-)
diff --git a/src/views/iot/rule/scene/form/inputs/JsonParamsInput.vue b/src/views/iot/rule/scene/form/inputs/JsonParamsInput.vue
new file mode 100644
index 0000000..5bfa970
--- /dev/null
+++ b/src/views/iot/rule/scene/form/inputs/JsonParamsInput.vue
@@ -0,0 +1,519 @@
+<!-- JSON鍙傛暟杈撳叆缁勪欢 - 閫氱敤鐗堟湰 -->
+<template>
+ <!-- 鍙傛暟閰嶇疆 -->
+ <div class="w-full space-y-12px">
+ <!-- JSON 杈撳叆妗� -->
+ <div class="relative">
+ <el-input
+ v-model="paramsJson"
+ type="textarea"
+ :rows="4"
+ :placeholder="placeholder"
+ @input="handleParamsChange"
+ :class="{ 'is-error': jsonError }"
+ />
+ <!-- 鏌ョ湅璇︾粏绀轰緥寮瑰嚭灞� -->
+ <div class="absolute top-8px right-8px">
+ <el-popover
+ placement="left-start"
+ :width="450"
+ trigger="click"
+ :show-arrow="true"
+ :offset="8"
+ popper-class="json-params-detail-popover"
+ >
+ <template #reference>
+ <el-button
+ type="info"
+ :icon="InfoFilled"
+ circle
+ size="small"
+ :title="JSON_PARAMS_INPUT_CONSTANTS.VIEW_EXAMPLE_TITLE"
+ />
+ </template>
+
+ <!-- 寮瑰嚭灞傚唴瀹� -->
+ <div class="json-params-detail-content">
+ <div class="flex items-center gap-8px mb-16px">
+ <Icon :icon="titleIcon" class="text-[var(--el-color-primary)] text-18px" />
+ <span class="text-16px font-600 text-[var(--el-text-color-primary)]">
+ {{ title }}
+ </span>
+ </div>
+
+ <div class="space-y-16px">
+ <!-- 鍙傛暟鍒楄〃 -->
+ <div v-if="paramsList.length > 0">
+ <div class="flex items-center gap-8px mb-8px">
+ <Icon :icon="paramsIcon" class="text-[var(--el-color-primary)] text-14px" />
+ <span class="text-14px font-500 text-[var(--el-text-color-primary)]">
+ {{ paramsLabel }}
+ </span>
+ </div>
+ <div class="ml-22px space-y-8px">
+ <div
+ v-for="param in paramsList"
+ :key="param.identifier"
+ class="flex items-center justify-between p-8px bg-[var(--el-fill-color-lighter)] rounded-4px"
+ >
+ <div class="flex-1">
+ <div class="text-12px font-500 text-[var(--el-text-color-primary)]">
+ {{ param.name }}
+ <el-tag v-if="param.required" size="small" type="danger" class="ml-4px">
+ {{ JSON_PARAMS_INPUT_CONSTANTS.REQUIRED_TAG }}
+ </el-tag>
+ </div>
+ <div class="text-11px text-[var(--el-text-color-secondary)]">
+ {{ param.identifier }}
+ </div>
+ </div>
+ <div class="flex items-center gap-8px">
+ <el-tag :type="getParamTypeTag(param.dataType)" size="small">
+ {{ getParamTypeName(param.dataType) }}
+ </el-tag>
+ <span class="text-11px text-[var(--el-text-color-secondary)]">
+ {{ getExampleValue(param) }}
+ </span>
+ </div>
+ </div>
+ </div>
+
+ <div class="mt-12px ml-22px">
+ <div class="text-12px text-[var(--el-text-color-secondary)] mb-6px">
+ {{ JSON_PARAMS_INPUT_CONSTANTS.COMPLETE_JSON_FORMAT }}
+ </div>
+ <pre
+ class="p-12px bg-[var(--el-fill-color-light)] rounded-4px text-11px text-[var(--el-text-color-primary)] overflow-x-auto border-l-3px border-[var(--el-color-primary)]"
+ >
+ <code>{{ generateExampleJson() }}</code>
+ </pre>
+ </div>
+ </div>
+
+ <!-- 鏃犲弬鏁版彁绀� -->
+ <div v-else>
+ <div class="text-center py-16px">
+ <p class="text-14px text-[var(--el-text-color-secondary)]">{{ emptyMessage }}</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </el-popover>
+ </div>
+ </div>
+
+ <!-- 楠岃瘉鐘舵�佸拰閿欒鎻愮ず -->
+ <div class="flex items-center justify-between">
+ <div class="flex items-center gap-8px">
+ <Icon
+ :icon="
+ jsonError
+ ? JSON_PARAMS_INPUT_ICONS.STATUS_ICONS.ERROR
+ : JSON_PARAMS_INPUT_ICONS.STATUS_ICONS.SUCCESS
+ "
+ :class="jsonError ? 'text-[var(--el-color-danger)]' : 'text-[var(--el-color-success)]'"
+ class="text-14px"
+ />
+ <span
+ :class="jsonError ? 'text-[var(--el-color-danger)]' : 'text-[var(--el-color-success)]'"
+ class="text-12px"
+ >
+ {{ jsonError || JSON_PARAMS_INPUT_CONSTANTS.JSON_FORMAT_CORRECT }}
+ </span>
+ </div>
+
+ <!-- 蹇�熷~鍏呮寜閽� -->
+ <div v-if="paramsList.length > 0" class="flex items-center gap-8px">
+ <span class="text-12px text-[var(--el-text-color-secondary)]">{{
+ JSON_PARAMS_INPUT_CONSTANTS.QUICK_FILL_LABEL
+ }}</span>
+ <el-button size="small" type="primary" plain @click="fillExampleJson">
+ {{ JSON_PARAMS_INPUT_CONSTANTS.EXAMPLE_DATA_BUTTON }}
+ </el-button>
+ <el-button size="small" type="danger" plain @click="clearParams">{{
+ JSON_PARAMS_INPUT_CONSTANTS.CLEAR_BUTTON
+ }}</el-button>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script setup lang="ts">
+import { useVModel } from '@vueuse/core'
+import { InfoFilled } from '@element-plus/icons-vue'
+import {
+ IoTDataSpecsDataTypeEnum,
+ JSON_PARAMS_INPUT_CONSTANTS,
+ JSON_PARAMS_INPUT_ICONS,
+ JSON_PARAMS_EXAMPLE_VALUES,
+ JsonParamsInputTypeEnum,
+ type JsonParamsInputType
+} from '@/views/iot/utils/constants'
+
+/** JSON鍙傛暟杈撳叆缁勪欢 - 閫氱敤鐗堟湰 */
+defineOptions({ name: 'JsonParamsInput' })
+
+interface JsonParamsConfig {
+ // 鏈嶅姟閰嶇疆
+ service?: {
+ name: string
+ inputParams?: any[]
+ }
+ // 浜嬩欢閰嶇疆
+ event?: {
+ name: string
+ outputParams?: any[]
+ }
+ // 灞炴�ч厤缃�
+ properties?: any[]
+ // 鑷畾涔夐厤缃�
+ custom?: {
+ name: string
+ params: any[]
+ }
+}
+
+interface Props {
+ modelValue?: string
+ config?: JsonParamsConfig
+ type?: JsonParamsInputType
+ placeholder?: string
+}
+
+interface Emits {
+ (e: 'update:modelValue', value: string): void
+}
+
+const props = withDefaults(defineProps<Props>(), {
+ type: JsonParamsInputTypeEnum.SERVICE,
+ placeholder: JSON_PARAMS_INPUT_CONSTANTS.PLACEHOLDER
+})
+
+const emit = defineEmits<Emits>()
+
+const localValue = useVModel(props, 'modelValue', emit, {
+ defaultValue: ''
+})
+
+const paramsJson = ref('') // JSON鍙傛暟瀛楃涓�
+const jsonError = ref('') // JSON楠岃瘉閿欒淇℃伅
+
+// 璁$畻灞炴�э細鍙傛暟鍒楄〃
+const paramsList = computed(() => {
+ switch (props.type) {
+ case JsonParamsInputTypeEnum.SERVICE:
+ return props.config?.service?.inputParams || []
+ case JsonParamsInputTypeEnum.EVENT:
+ return props.config?.event?.outputParams || []
+ case JsonParamsInputTypeEnum.PROPERTY:
+ return props.config?.properties || []
+ case JsonParamsInputTypeEnum.CUSTOM:
+ return props.config?.custom?.params || []
+ default:
+ return []
+ }
+})
+
+// 璁$畻灞炴�э細鏍囬
+const title = computed(() => {
+ switch (props.type) {
+ case JsonParamsInputTypeEnum.SERVICE:
+ return JSON_PARAMS_INPUT_CONSTANTS.TITLES.SERVICE(props.config?.service?.name)
+ case JsonParamsInputTypeEnum.EVENT:
+ return JSON_PARAMS_INPUT_CONSTANTS.TITLES.EVENT(props.config?.event?.name)
+ case JsonParamsInputTypeEnum.PROPERTY:
+ return JSON_PARAMS_INPUT_CONSTANTS.TITLES.PROPERTY
+ case JsonParamsInputTypeEnum.CUSTOM:
+ return JSON_PARAMS_INPUT_CONSTANTS.TITLES.CUSTOM(props.config?.custom?.name)
+ default:
+ return JSON_PARAMS_INPUT_CONSTANTS.TITLES.DEFAULT
+ }
+})
+
+// 璁$畻灞炴�э細鏍囬鍥炬爣
+const titleIcon = computed(() => {
+ switch (props.type) {
+ case JsonParamsInputTypeEnum.SERVICE:
+ return JSON_PARAMS_INPUT_ICONS.TITLE_ICONS.SERVICE
+ case JsonParamsInputTypeEnum.EVENT:
+ return JSON_PARAMS_INPUT_ICONS.TITLE_ICONS.EVENT
+ case JsonParamsInputTypeEnum.PROPERTY:
+ return JSON_PARAMS_INPUT_ICONS.TITLE_ICONS.PROPERTY
+ case JsonParamsInputTypeEnum.CUSTOM:
+ return JSON_PARAMS_INPUT_ICONS.TITLE_ICONS.CUSTOM
+ default:
+ return JSON_PARAMS_INPUT_ICONS.TITLE_ICONS.DEFAULT
+ }
+})
+
+// 璁$畻灞炴�э細鍙傛暟鍥炬爣
+const paramsIcon = computed(() => {
+ switch (props.type) {
+ case JsonParamsInputTypeEnum.SERVICE:
+ return JSON_PARAMS_INPUT_ICONS.PARAMS_ICONS.SERVICE
+ case JsonParamsInputTypeEnum.EVENT:
+ return JSON_PARAMS_INPUT_ICONS.PARAMS_ICONS.EVENT
+ case JsonParamsInputTypeEnum.PROPERTY:
+ return JSON_PARAMS_INPUT_ICONS.PARAMS_ICONS.PROPERTY
+ case JsonParamsInputTypeEnum.CUSTOM:
+ return JSON_PARAMS_INPUT_ICONS.PARAMS_ICONS.CUSTOM
+ default:
+ return JSON_PARAMS_INPUT_ICONS.PARAMS_ICONS.DEFAULT
+ }
+})
+
+// 璁$畻灞炴�э細鍙傛暟鏍囩
+const paramsLabel = computed(() => {
+ switch (props.type) {
+ case JsonParamsInputTypeEnum.SERVICE:
+ return JSON_PARAMS_INPUT_CONSTANTS.PARAMS_LABELS.SERVICE
+ case JsonParamsInputTypeEnum.EVENT:
+ return JSON_PARAMS_INPUT_CONSTANTS.PARAMS_LABELS.EVENT
+ case JsonParamsInputTypeEnum.PROPERTY:
+ return JSON_PARAMS_INPUT_CONSTANTS.PARAMS_LABELS.PROPERTY
+ case JsonParamsInputTypeEnum.CUSTOM:
+ return JSON_PARAMS_INPUT_CONSTANTS.PARAMS_LABELS.CUSTOM
+ default:
+ return JSON_PARAMS_INPUT_CONSTANTS.PARAMS_LABELS.DEFAULT
+ }
+})
+
+// 璁$畻灞炴�э細绌虹姸鎬佹秷鎭�
+const emptyMessage = computed(() => {
+ switch (props.type) {
+ case JsonParamsInputTypeEnum.SERVICE:
+ return JSON_PARAMS_INPUT_CONSTANTS.EMPTY_MESSAGES.SERVICE
+ case JsonParamsInputTypeEnum.EVENT:
+ return JSON_PARAMS_INPUT_CONSTANTS.EMPTY_MESSAGES.EVENT
+ case JsonParamsInputTypeEnum.PROPERTY:
+ return JSON_PARAMS_INPUT_CONSTANTS.EMPTY_MESSAGES.PROPERTY
+ case JsonParamsInputTypeEnum.CUSTOM:
+ return JSON_PARAMS_INPUT_CONSTANTS.EMPTY_MESSAGES.CUSTOM
+ default:
+ return JSON_PARAMS_INPUT_CONSTANTS.EMPTY_MESSAGES.DEFAULT
+ }
+})
+
+// 璁$畻灞炴�э細鏃犻厤缃秷鎭�
+const noConfigMessage = computed(() => {
+ switch (props.type) {
+ case JsonParamsInputTypeEnum.SERVICE:
+ return JSON_PARAMS_INPUT_CONSTANTS.NO_CONFIG_MESSAGES.SERVICE
+ case JsonParamsInputTypeEnum.EVENT:
+ return JSON_PARAMS_INPUT_CONSTANTS.NO_CONFIG_MESSAGES.EVENT
+ case JsonParamsInputTypeEnum.PROPERTY:
+ return JSON_PARAMS_INPUT_CONSTANTS.NO_CONFIG_MESSAGES.PROPERTY
+ case JsonParamsInputTypeEnum.CUSTOM:
+ return JSON_PARAMS_INPUT_CONSTANTS.NO_CONFIG_MESSAGES.CUSTOM
+ default:
+ return JSON_PARAMS_INPUT_CONSTANTS.NO_CONFIG_MESSAGES.DEFAULT
+ }
+})
+
+/**
+ * 澶勭悊鍙傛暟鍙樺寲浜嬩欢
+ */
+const handleParamsChange = () => {
+ try {
+ jsonError.value = '' // 娓呴櫎涔嬪墠鐨勯敊璇�
+
+ if (paramsJson.value.trim()) {
+ const parsed = JSON.parse(paramsJson.value)
+ localValue.value = paramsJson.value
+
+ // 棰濆鐨勫弬鏁伴獙璇�
+ if (typeof parsed !== 'object' || parsed === null) {
+ jsonError.value = JSON_PARAMS_INPUT_CONSTANTS.PARAMS_MUST_BE_OBJECT
+ return
+ }
+
+ // 楠岃瘉蹇呭~鍙傛暟
+ for (const param of paramsList.value) {
+ if (param.required && (!parsed[param.identifier] || parsed[param.identifier] === '')) {
+ jsonError.value = JSON_PARAMS_INPUT_CONSTANTS.PARAM_REQUIRED_ERROR(param.name)
+ return
+ }
+ }
+ } else {
+ localValue.value = ''
+ }
+
+ // 楠岃瘉閫氳繃
+ jsonError.value = ''
+ } catch (error) {
+ jsonError.value = JSON_PARAMS_INPUT_CONSTANTS.JSON_FORMAT_ERROR(
+ error instanceof Error ? error.message : JSON_PARAMS_INPUT_CONSTANTS.UNKNOWN_ERROR
+ )
+ }
+}
+
+/**
+ * 蹇�熷~鍏呯ず渚嬫暟鎹�
+ */
+const fillExampleJson = () => {
+ paramsJson.value = generateExampleJson()
+ handleParamsChange()
+}
+
+/**
+ * 娓呯┖鍙傛暟
+ */
+const clearParams = () => {
+ paramsJson.value = ''
+ localValue.value = ''
+ jsonError.value = ''
+}
+
+/**
+ * 鑾峰彇鍙傛暟绫诲瀷鍚嶇О
+ * @param dataType 鏁版嵁绫诲瀷
+ * @returns 绫诲瀷鍚嶇О
+ */
+const getParamTypeName = (dataType: string) => {
+ // 浣跨敤 constants.ts 涓凡鏈夌殑 getDataTypeName 鍑芥暟閫昏緫
+ const typeMap = {
+ [IoTDataSpecsDataTypeEnum.INT]: '鏁存暟',
+ [IoTDataSpecsDataTypeEnum.FLOAT]: '娴偣鏁�',
+ [IoTDataSpecsDataTypeEnum.DOUBLE]: '鍙岀簿搴�',
+ [IoTDataSpecsDataTypeEnum.TEXT]: '瀛楃涓�',
+ [IoTDataSpecsDataTypeEnum.BOOL]: '甯冨皵鍊�',
+ [IoTDataSpecsDataTypeEnum.ENUM]: '鏋氫妇',
+ [IoTDataSpecsDataTypeEnum.DATE]: '鏃ユ湡',
+ [IoTDataSpecsDataTypeEnum.STRUCT]: '缁撴瀯浣�',
+ [IoTDataSpecsDataTypeEnum.ARRAY]: '鏁扮粍'
+ }
+ return typeMap[dataType] || dataType
+}
+
+/**
+ * 鑾峰彇鍙傛暟绫诲瀷鏍囩鏍峰紡
+ * @param dataType 鏁版嵁绫诲瀷
+ * @returns 鏍囩鏍峰紡
+ */
+const getParamTypeTag = (dataType: string) => {
+ const tagMap = {
+ [IoTDataSpecsDataTypeEnum.INT]: 'primary',
+ [IoTDataSpecsDataTypeEnum.FLOAT]: 'success',
+ [IoTDataSpecsDataTypeEnum.DOUBLE]: 'success',
+ [IoTDataSpecsDataTypeEnum.TEXT]: 'info',
+ [IoTDataSpecsDataTypeEnum.BOOL]: 'warning',
+ [IoTDataSpecsDataTypeEnum.ENUM]: 'danger',
+ [IoTDataSpecsDataTypeEnum.DATE]: 'primary',
+ [IoTDataSpecsDataTypeEnum.STRUCT]: 'info',
+ [IoTDataSpecsDataTypeEnum.ARRAY]: 'warning'
+ }
+ return tagMap[dataType] || 'info'
+}
+
+/**
+ * 鑾峰彇绀轰緥鍊�
+ * @param param 鍙傛暟瀵硅薄
+ * @returns 绀轰緥鍊�
+ */
+const getExampleValue = (param: any) => {
+ const exampleConfig =
+ JSON_PARAMS_EXAMPLE_VALUES[param.dataType] || JSON_PARAMS_EXAMPLE_VALUES.DEFAULT
+ return exampleConfig.display
+}
+
+/**
+ * 鐢熸垚绀轰緥JSON
+ * @returns JSON瀛楃涓�
+ */
+const generateExampleJson = () => {
+ if (paramsList.value.length === 0) {
+ return '{}'
+ }
+
+ const example = {}
+ paramsList.value.forEach((param) => {
+ const exampleConfig =
+ JSON_PARAMS_EXAMPLE_VALUES[param.dataType] || JSON_PARAMS_EXAMPLE_VALUES.DEFAULT
+ example[param.identifier] = exampleConfig.value
+ })
+
+ return JSON.stringify(example, null, 2)
+}
+
+/**
+ * 澶勭悊鏁版嵁鍥炴樉
+ * @param value 鍊煎瓧绗︿覆
+ */
+const handleDataDisplay = (value: string) => {
+ if (!value || !value.trim()) {
+ paramsJson.value = ''
+ jsonError.value = ''
+ return
+ }
+
+ try {
+ // 灏濊瘯瑙f瀽JSON锛屽鏋滄垚鍔熷垯鏍煎紡鍖�
+ const parsed = JSON.parse(value)
+ paramsJson.value = JSON.stringify(parsed, null, 2)
+ jsonError.value = ''
+ } catch {
+ // 濡傛灉涓嶆槸鏈夋晥鐨凧SON锛岀洿鎺ヤ娇鐢ㄥ師瀛楃涓�
+ paramsJson.value = value
+ jsonError.value = ''
+ }
+}
+
+// 鐩戝惉澶栭儴鍊煎彉鍖栵紙缂栬緫妯″紡鏁版嵁鍥炴樉锛�
+watch(
+ () => localValue.value,
+ async (newValue, oldValue) => {
+ // 閬垮厤寰幆鏇存柊
+ if (newValue === oldValue) return
+
+ // 浣跨敤 nextTick 纭繚鍦ㄤ笅涓�涓� tick 涓鐞嗘暟鎹�
+ await nextTick()
+ handleDataDisplay(newValue || '')
+ },
+ { immediate: true }
+)
+
+// 缁勪欢鎸傝浇鍚庝篃灏濊瘯澶勭悊涓�娆℃暟鎹洖鏄�
+onMounted(async () => {
+ await nextTick()
+ if (localValue.value) {
+ handleDataDisplay(localValue.value)
+ }
+})
+
+// 鐩戝惉閰嶇疆鍙樺寲
+watch(
+ () => props.config,
+ (newConfig, oldConfig) => {
+ // 鍙湁鍦ㄩ厤缃湡姝e彉鍖栨椂鎵嶆竻绌烘暟鎹�
+ if (JSON.stringify(newConfig) !== JSON.stringify(oldConfig)) {
+ // 濡傛灉娌℃湁澶栭儴浼犲叆鐨勫�硷紝鎵嶆竻绌烘暟鎹�
+ if (!localValue.value) {
+ paramsJson.value = ''
+ jsonError.value = ''
+ }
+ }
+ }
+)
+</script>
+
+<style scoped>
+/* 寮瑰嚭灞傚唴瀹规牱寮� */
+.json-params-detail-content {
+ padding: 4px 0;
+}
+
+/* 寮瑰嚭灞傝嚜瀹氫箟鏍峰紡 */
+:global(.json-params-detail-popover) {
+ max-width: 500px !important;
+}
+
+:global(.json-params-detail-popover .el-popover__content) {
+ padding: 16px !important;
+}
+
+/* JSON 浠g爜鍧楁牱寮� */
+.json-params-detail-content pre {
+ max-height: 200px;
+ overflow-y: auto;
+}
+</style>
--
Gitblit v1.8.0