|
|
<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>
|