You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
292 lines
7.4 KiB
292 lines
7.4 KiB
<template>
|
|
<el-dialog
|
|
title="数据源选择"
|
|
:visible="visible"
|
|
:close-on-click-modal="false"
|
|
width="880px"
|
|
top="5vh"
|
|
append-to-body
|
|
custom-class="data-source-dialog"
|
|
@close="handleClose"
|
|
>
|
|
<!-- 主体:我们放一个专门的可滚动区域 -->
|
|
<div class="data-source-body">
|
|
<el-form label-position="top" class="data-source-form">
|
|
<!-- 可选:分组显示 -->
|
|
<template v-if="hasViewGroups">
|
|
<div
|
|
v-for="group in viewGroups"
|
|
:key="group.viewSource"
|
|
class="view-group"
|
|
>
|
|
<div class="view-title">
|
|
{{ group.viewSource + ' (' + group.fields.length + '个字段)' }}
|
|
</div>
|
|
<div class="checkbox-grid">
|
|
<label
|
|
v-for="key in group.fields"
|
|
:key="key.fieldName"
|
|
class="checkbox-item">
|
|
<el-checkbox :label="key.fieldName" v-model="selectedKeys">
|
|
<span class="label-inner">
|
|
<span class="field-name" :title="getFieldDisplayName(key)">{{ getFieldDisplayName(key) }}</span>
|
|
</span>
|
|
</el-checkbox>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template v-else>
|
|
<div class="view-group">
|
|
<div class="view-title">可用数据字段</div>
|
|
<div class="checkbox-grid">
|
|
<label
|
|
v-for="key in dataKeys"
|
|
:key="key.fieldName"
|
|
class="checkbox-item">
|
|
<el-checkbox :label="key.fieldName" v-model="selectedKeys">
|
|
<span class="label-inner">
|
|
<span class="field-name" :title="getFieldDisplayName(key)">{{ getFieldDisplayName(key) }}</span>
|
|
</span>
|
|
</el-checkbox>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</el-form>
|
|
</div>
|
|
|
|
<!-- footer 使用 el-dialog 的 footer slot(保持默认位置) -->
|
|
<div slot="footer" class="dialog-footer">
|
|
<el-button @click="handleClose">取消</el-button>
|
|
<el-button type="primary" @click="handleConfirm">确定</el-button>
|
|
</div>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
name: 'DataSourceDialog',
|
|
props: {
|
|
visible: Boolean,
|
|
dataKeys: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
currentText: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
sourceType: {
|
|
type: String,
|
|
default: 'text'
|
|
}
|
|
},
|
|
emits: ['update:visible', 'confirm'],
|
|
data() {
|
|
return {
|
|
selectedKeys: []
|
|
}
|
|
},
|
|
computed: {
|
|
hasViewGroups() {
|
|
return this.dataKeys && this.dataKeys.some(k => k.viewSource)
|
|
},
|
|
viewGroups() {
|
|
if (!this.hasViewGroups) return []
|
|
const groups = {}
|
|
this.dataKeys.forEach(key => {
|
|
const vs = key.viewSource || '未知视图'
|
|
if (!groups[vs]) groups[vs] = {viewSource: vs, fields: []}
|
|
groups[vs].fields.push(key)
|
|
})
|
|
return Object.values(groups)
|
|
}
|
|
},
|
|
watch: {
|
|
visible(newVal) {
|
|
if (newVal) this.initializeSelection()
|
|
},
|
|
dataKeys() {
|
|
// 当字段更新时,重新初始化选中(如果对话框是可见的)
|
|
if (this.visible) this.initializeSelection()
|
|
}
|
|
},
|
|
methods: {
|
|
getFieldDisplayName(key) {
|
|
const name = key.displayName || key.fieldName
|
|
return name + (key.fieldDescription ? `(${key.fieldDescription})` : '')
|
|
},
|
|
initializeSelection() {
|
|
if (!this.currentText || !this.dataKeys || !this.dataKeys.length) {
|
|
this.selectedKeys = []
|
|
return
|
|
}
|
|
const found = []
|
|
this.dataKeys.forEach(k => {
|
|
const pat = new RegExp(`#\\{${k.fieldName}\\}`, 'g')
|
|
if (pat.test(this.currentText)) found.push(k.fieldName)
|
|
})
|
|
this.selectedKeys = found
|
|
},
|
|
handleClose() {
|
|
this.$emit('update:visible', false)
|
|
},
|
|
handleConfirm() {
|
|
const processed = this.selectedKeys.map(s => {
|
|
const f = this.dataKeys.find(k => k.fieldName === s)
|
|
return f && f.originalFieldName ? f.originalFieldName : s
|
|
})
|
|
this.$emit('confirm', processed, this.sourceType)
|
|
this.handleClose()
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* ---------- 对话框整体 ---------- */
|
|
.data-source-dialog {
|
|
/* 确保 dialog 在 body 上并覆盖画布 */
|
|
}
|
|
|
|
.el-dialog__wrapper {
|
|
z-index: 3000 !important; /* 提升到高于页面画布的层级 */
|
|
}
|
|
|
|
/* 把 el-dialog 设置成 flex 布局:header/body/footer 三段式 */
|
|
.data-source-dialog .el-dialog {
|
|
display: flex;
|
|
flex-direction: column;
|
|
max-height: 90vh;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* 中间真正滚动的区域:固定高度(max)并可滚动,避免内容跑出弹窗 */
|
|
.data-source-body {
|
|
flex: 1 1 auto;
|
|
overflow: auto;
|
|
padding: 12px 18px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
/* 表单内容器布局 */
|
|
.data-source-form {
|
|
margin: 0;
|
|
}
|
|
|
|
/* 分组标题 */
|
|
.view-group {
|
|
margin-bottom: 12px;
|
|
padding: 10px;
|
|
background: #fafbfc;
|
|
border: 1px solid #e8eef0;
|
|
border-radius: 8px;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.view-title {
|
|
color: #17b3a3;
|
|
font-weight: 700;
|
|
margin-bottom: 8px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
/* ---------- 复选框网格更紧凑 ---------- */
|
|
.checkbox-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
margin: -4px; /* 缩小外边距 */
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.checkbox-item {
|
|
padding: 4px;
|
|
margin: 4px;
|
|
width: calc(20% - 8px); /* 默认 5 列布局,更紧凑 */
|
|
min-width: 150px; /* 允许更窄 */
|
|
background: #fff;
|
|
border: 1px solid #e6eef0;
|
|
border-radius: 4px; /* 缩小圆角 */
|
|
display: flex;
|
|
align-items: flex-start;
|
|
cursor: pointer;
|
|
transition: background 0.12s;
|
|
}
|
|
|
|
.checkbox-item:hover {
|
|
background: #f7fdfb;
|
|
border-color: #cfeee8;
|
|
}
|
|
|
|
/* 内部的文字和 badge */
|
|
.label-inner {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 4px; /* 缩小间距 */
|
|
width: 100%;
|
|
}
|
|
|
|
.field-name {
|
|
display: block;
|
|
font-size: 12px;
|
|
color: #333;
|
|
line-height: 1.4;
|
|
white-space: nowrap; /* 单行显示 */
|
|
overflow: hidden; /* 隐藏溢出 */
|
|
text-overflow: ellipsis; /* 超出显示 ... */
|
|
max-width: 120px; /* 限制最大宽度 */
|
|
}
|
|
|
|
.duplicate-badge {
|
|
padding: 1px 4px;
|
|
font-size: 10px; /* 更小的 badge */
|
|
border-radius: 3px;
|
|
}
|
|
|
|
/* 缩小复选框 */
|
|
.checkbox-item .el-checkbox__inner {
|
|
width: 14px !important;
|
|
height: 14px !important;
|
|
}
|
|
|
|
/* 响应式:小屏幕保持紧凑 */
|
|
@media (max-width: 1100px) {
|
|
.checkbox-item { width: calc(25% - 8px); min-width: 140px; } /* 4 列 */
|
|
}
|
|
@media (max-width: 840px) {
|
|
.checkbox-item { width: calc(33.333% - 8px); min-width: 130px; } /* 3 列 */
|
|
}
|
|
@media (max-width: 520px) {
|
|
.checkbox-item { width: calc(50% - 8px); min-width: auto; } /* 2 列 */
|
|
}
|
|
|
|
|
|
/* ---------- Footer 固定在对话框底部(但不覆写内容) ---------- */
|
|
.dialog-footer {
|
|
padding: 10px 18px;
|
|
border-top: 1px solid #e8eef0;
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 14px;
|
|
background: #fff;
|
|
box-sizing: border-box;
|
|
z-index: 40;
|
|
}
|
|
|
|
/* 按钮样式保持 */
|
|
.dialog-footer .el-button {
|
|
min-width: 88px;
|
|
height: 36px;
|
|
font-weight: 600;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.dialog-footer .el-button--primary {
|
|
background: linear-gradient(135deg, #17b3a3 0%, #1dc5ef 100%);
|
|
color: #fff;
|
|
border: none;
|
|
}
|
|
</style>
|