ソースを参照

输入框支持补全

kagg886 2 ヶ月 前
コミット
3515bcea64
1 ファイル変更268 行追加3 行削除
  1. 268 3
      src/components/gFlow/propertySetting/webhookParams.vue

+ 268 - 3
src/components/gFlow/propertySetting/webhookParams.vue

@@ -1,7 +1,71 @@
-<template></template>
+<template>
+	<div class="webhook-params">
+		<div class="params-header">
+			<h3>{{ title }}</h3>
+			<el-button type="primary" size="small" @click="addKeyValue" :disabled="readonly"> 添加参数 </el-button>
+		</div>
+
+		<div class="params-content">
+			<div class="params-list">
+				<div v-for="(key, index) in keys" :key="key" class="param-item">
+					<div class="param-key">
+						<el-input v-model="editingKeys[index]" placeholder="参数名" :disabled="readonly" @blur="updateKey(index, key)" />
+					</div>
+
+					<div class="param-value">
+						<el-popover placement="bottom" :width="600" trigger="click">
+							<template #reference>
+								<el-input v-model="origin[key]" placeholder="参数值" :disabled="readonly" @input="updateOrigin" />
+							</template>
+							<div class="popover-content">
+								<div class="two-column-layout">
+									<!-- 第一列:flow_model_cate字典数据 -->
+									<div class="left-column">
+										<div class="column-title">表单类别</div>
+										<div class="category-list">
+											<div
+												v-for="item in flow_model_cate"
+												:key="item.value"
+												class="category-item"
+												:class="{ active: currentSelectCate === item.value }"
+												@click="selectCategory(item.value)"
+											>
+												{{ item.label }}
+											</div>
+										</div>
+									</div>
+
+									<!-- 第二列:currentListSelectCate数据 -->
+									<div class="right-column">
+										<div class="column-title">字段列表</div>
+										<div class="field-list">
+											<div v-for="field in currentListSelectCate" :key="field.Key" class="field-item" @click="selectField(field.Key, key)">
+												<div class="field-name">{{ field.Key }}</div>
+												<div class="field-type">{{ field.Type }}</div>
+												<div class="field-desc">{{ field.Dc }}</div>
+											</div>
+										</div>
+									</div>
+								</div>
+							</div>
+						</el-popover>
+					</div>
+
+					<div class="param-actions">
+						<el-button type="danger" size="small" :icon="Delete" @click="removeKeyValue(key)" :disabled="readonly" />
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
 
 <script lang="ts" setup>
-import { computed, getCurrentInstance } from 'vue'
+import { computed, getCurrentInstance, ref, watch } from 'vue'
+import { ElMessage } from 'element-plus'
+import { Delete } from '@element-plus/icons-vue'
+import { useAsyncState } from '@vueuse/core'
+import { getFlowFields } from '/@/api/flow/flowForm'
 
 const { proxy } = getCurrentInstance() as any
 const {
@@ -46,6 +110,207 @@ const origin = computed<{ [key: string]: string }>({
 		emit('update:modelValue', JSON.stringify(value ?? {}))
 	},
 })
+
+const keys = computed<string[]>(() => Object.keys(origin.value))
+
+// 用于编辑键名的响应式数组
+const editingKeys = ref<string[]>([])
+
+// 监听keys变化,同步editingKeys
+watch(
+	keys,
+	(newKeys) => {
+		editingKeys.value = [...newKeys]
+	},
+	{ immediate: true }
+)
+
+// 添加新的键值对
+const addKeyValue = () => {
+	const newKey = `params_${keys.value.length + 1}`
+	origin.value = { ...origin.value, [newKey]: '' }
+}
+
+// 删除键值对
+const removeKeyValue = (key: string) => {
+	const newOrigin = { ...origin.value }
+	delete newOrigin[key]
+	origin.value = newOrigin
+}
+
+// 更新键名
+const updateKey = (index: number, oldKey: string) => {
+	const newKey = editingKeys.value[index]
+
+	// 验证键名是否有效
+	if (!newKey || newKey.trim() === '') {
+		editingKeys.value[index] = oldKey
+		return
+	}
+
+	// 检查键名是否重复
+	if (newKey !== oldKey && keys.value.includes(newKey)) {
+		editingKeys.value[index] = oldKey
+		ElMessage.warning('参数名已存在')
+		return
+	}
+
+	// 更新键名
+	if (newKey !== oldKey) {
+		const newOrigin = { ...origin.value }
+		const value = newOrigin[oldKey]
+		delete newOrigin[oldKey]
+		newOrigin[newKey] = value
+		origin.value = newOrigin
+	}
+}
+
+// 更新origin对象
+const updateOrigin = () => {
+	// 触发computed的setter
+	origin.value = { ...origin.value }
+}
+
+const currentSelectCate = ref('')
+
+// 选择表单类别
+const selectCategory = (categoryValue: string) => {
+	currentSelectCate.value = categoryValue
+}
+
+// 选择字段
+const selectField = (fieldKey: string, paramKey: string) => {
+	origin.value[paramKey] = `{{.${fieldKey}}`
+	updateOrigin()
+}
+
+watch(currentSelectCate, (newListSelectCate) => {
+	if (newListSelectCate === '') return
+	selectCate(100, newListSelectCate)
+})
+
+const { state: currentListSelectCate, execute: selectCate } = useAsyncState(
+	async (data) => {
+		return await getFlowFields(data)
+			.then((res: any) => (res as FlowFieldsInSql).infos)
+			.catch(() => [] as FlowFieldsInSql['infos'])
+	},
+	[] as FlowFieldsInSql['infos'],
+	{ immediate: false }
+)
 </script>
 
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.webhook-params {
+	width: 100%;
+	.params-header {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		margin-bottom: 16px;
+
+		h3 {
+			margin: 0;
+			font-size: 16px;
+			font-weight: 500;
+		}
+	}
+
+	.params-content {
+		.empty-state {
+			padding: 40px 0;
+			text-align: center;
+		}
+
+		.params-list {
+			.param-item {
+				display: flex;
+				align-items: center;
+				gap: 12px;
+				margin-bottom: 12px;
+
+				.param-key {
+					flex: 1;
+					min-width: 150px;
+				}
+
+				.param-value {
+					flex: 2;
+					min-width: 200px;
+				}
+
+				.param-actions {
+					flex-shrink: 0;
+				}
+			}
+		}
+	}
+}
+
+.popover-content {
+	.two-column-layout {
+		display: flex;
+		gap: 16px;
+		height: 300px;
+
+		.left-column,
+		.right-column {
+			flex: 1;
+			display: flex;
+			flex-direction: column;
+			border: 1px solid #e4e7ed;
+			border-radius: 4px;
+			overflow: hidden;
+
+			.column-title {
+				padding: 8px 12px;
+				background-color: #f5f7fa;
+				border-bottom: 1px solid #e4e7ed;
+				font-weight: 500;
+				font-size: 14px;
+			}
+
+			.category-list,
+			.field-list {
+				flex: 1;
+				overflow-y: auto;
+				padding: 4px 0;
+
+				.category-item,
+				.field-item {
+					padding: 8px 12px;
+					cursor: pointer;
+					transition: background-color 0.2s;
+
+					&:hover {
+						background-color: #f5f7fa;
+					}
+
+					&.active {
+						background-color: #409eff;
+						color: white;
+					}
+				}
+
+				.field-item {
+					.field-name {
+						font-weight: 500;
+						margin-bottom: 2px;
+					}
+
+					.field-type {
+						font-size: 12px;
+						color: #909399;
+						margin-bottom: 2px;
+					}
+
+					.field-desc {
+						font-size: 12px;
+						color: #606266;
+					}
+				}
+			}
+		}
+	}
+}
+</style>