123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- <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, 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 {
- flow_model_cate,
- }: {
- [key: string]: Array<{
- label: string
- value: string
- }>
- } = proxy.useDict('flow_model_cate')
- // 定义组件的 Props
- interface Props {
- modelValue: string
- title?: string
- readonly?: boolean
- }
- type FlowFieldsInSql = {
- infos: Array<{
- Key: string
- Type: string
- Dc: string
- }>
- }
- // getFlowFields('表单名').then((res:FlowFieldsInSql)=>xxx)
- const props = withDefaults(defineProps<Props>(), {
- title: '参数配置',
- readonly: false,
- })
- const emit = defineEmits<{
- // eslint-disable-next-line no-unused-vars
- (e: 'update:modelValue', value: string): void
- }>()
- const origin = computed<{ [key: string]: string }>({
- get() {
- return JSON.parse(props.modelValue ?? '{}')
- },
- set(value) {
- 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">
- .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>
|