Browse Source

多数据源

master
han\hanst 5 months ago
parent
commit
0ac4537265
  1. 374
      src/views/modules/labelSetting/components/DataSourceDialog.vue

374
src/views/modules/labelSetting/components/DataSourceDialog.vue

@ -3,30 +3,65 @@
title="数据源选择"
:visible="visible"
:close-on-click-modal="false"
width="800px"
width="880px"
top="5vh"
append-to-body
custom-class="data-source-dialog"
@close="handleClose"
>
<div class="data-source-content">
<el-form label-position="top">
<el-form-item label="可用数据字段">
<el-checkbox-group v-model="selectedKeys" class="checkbox-grid">
<el-checkbox
v-for="key in dataKeys"
:key="key.fieldName"
:label="key.fieldName"
class="checkbox-item"
>
{{ key.fieldName+(key.fieldDescription?('('+key.fieldDescription +')'):'')}}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<!-- 主体我们放一个专门的可滚动区域 -->
<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"
:class="{ 'duplicate-field': key.isDuplicate }"
>
<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"
:class="{ 'duplicate-field': key.isDuplicate }"
>
<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>
@ -43,14 +78,13 @@ export default {
type: Array,
default: () => []
},
//
currentText: {
type: String,
default: ''
},
sourceType: {
type: String,
default: 'text' //
default: 'text'
}
},
emits: ['update:visible', 'confirm'],
@ -59,41 +93,56 @@ export default {
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()
}
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.length) {
if (!this.currentText || !this.dataKeys || !this.dataKeys.length) {
this.selectedKeys = []
return
}
//
const foundKeys = []
this.dataKeys.forEach(key => {
// #{key}
const pattern = new RegExp(`#\\{${key.fieldName}\\}`, 'g')
if (pattern.test(this.currentText)) {
foundKeys.push(key.fieldName)
}
const found = []
this.dataKeys.forEach(k => {
const pat = new RegExp(`#\\{${k.fieldName}\\}`, 'g')
if (pat.test(this.currentText)) found.push(k.fieldName)
})
this.selectedKeys = foundKeys
this.selectedKeys = found
},
handleClose() {
this.$emit('update:visible', false)
},
handleConfirm() {
this.$emit('confirm', this.selectedKeys, this.sourceType)
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()
}
}
@ -101,214 +150,147 @@ export default {
</script>
<style scoped>
/* ---------- 对话框整体 ---------- */
.data-source-dialog {
max-width: 98vw !important;
max-height: 92vh !important;
border-radius: 12px !important;
box-shadow: 0 12px 32px rgba(0,0,0,0.15) !important;
background: #fff !important;
/* 确保 dialog 在 body 上并覆盖画布 */
}
.data-source-dialog .el-dialog__header {
padding: 16px 20px 8px !important;
border-bottom: 1px solid #e4e7ed !important;
background: #fff !important;
.el-dialog__wrapper {
z-index: 3000 !important; /* 提升到高于页面画布的层级 */
}
.data-source-dialog .el-dialog__title {
font-size: 20px !important;
font-weight: 700 !important;
color: #222 !important;
/* 把 el-dialog 设置成 flex 布局:header/body/footer 三段式 */
.data-source-dialog .el-dialog {
display: flex;
flex-direction: column;
max-height: 90vh;
box-sizing: border-box;
}
.data-source-dialog .el-dialog__body {
padding: 10px 20px 0 20px !important;
max-height: 70vh !important;
min-height: 80px;
overflow-y: auto !important;
background: #fff !important;
/* 中间真正滚动的区域:固定高度(max)并可滚动,避免内容跑出弹窗 */
.data-source-body {
flex: 1 1 auto;
overflow: auto;
padding: 12px 18px;
box-sizing: border-box;
}
.data-source-content {
width: 100%;
min-height: 60px;
/* 表单内容器布局 */
.data-source-form {
margin: 0;
}
/* 表单项样式优化 */
.el-form-item {
/* 分组标题 */
.view-group {
margin-bottom: 12px;
padding: 10px;
background: #fafbfc;
border: 1px solid #e8eef0;
border-radius: 8px;
box-sizing: border-box;
}
.el-form-item:last-child {
margin-bottom: 0;
}
.el-form-item__label {
font-size: 14px !important;
font-weight: 600 !important;
color: #303133 !important;
padding-bottom: 8px !important;
line-height: 1.4 !important;
.view-title {
color: #17b3a3;
font-weight: 700;
margin-bottom: 8px;
font-size: 14px;
}
/* 复选框网格布局 */
/* ---------- 复选框网格更紧凑 ---------- */
.checkbox-grid {
display: grid;
grid-template-columns: repeat(4, 1fr); /* 固定一行4个 */
gap: 8px 10px;
margin-top: 6px;
padding: 0;
background: none;
border: none;
border-radius: 0;
/* 让复选框区域高度自适应内容 */
max-height: none;
overflow-y: visible;
min-height: 80px;
display: flex;
flex-wrap: wrap;
margin: -4px; /* 缩小外边距 */
box-sizing: border-box;
}
/* 复选框项样式 */
.checkbox-item {
margin: 0 !important;
display: flex !important;
align-items: center !important;
height: 28px;
padding: 2px 6px;
padding: 4px;
margin: 4px;
width: calc(20% - 8px); /* 默认 5 列布局,更紧凑 */
min-width: 150px; /* 允许更窄 */
background: #fff;
border: 1px solid #e4e7ed;
border-radius: 4px;
transition: all 0.15s cubic-bezier(.4,0,.2,1);
border: 1px solid #e6eef0;
border-radius: 4px; /* 缩小圆角 */
display: flex;
align-items: flex-start;
cursor: pointer;
box-shadow: none;
transition: background 0.12s;
}
.checkbox-item:hover {
border-color: #17b3a3;
background: #f0fdfa;
transform: translateY(-1px) scale(1.01);
}
.checkbox-item.is-checked {
border-color: #17b3a3;
background: #e6f7f4;
background: #f7fdfb;
border-color: #cfeee8;
}
/* 复选框内部元素样式 */
.checkbox-item .el-checkbox__input {
margin-right: 8px;
/* 内部的文字和 badge */
.label-inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 4px; /* 缩小间距 */
width: 100%;
}
.checkbox-item .el-checkbox__inner {
width: 16px !important;
height: 16px !important;
border: 2px solid #dcdfe6 !important;
border-radius: 4px !important;
transition: all 0.2s ease !important;
.field-name {
display: block;
font-size: 12px;
color: #333;
line-height: 1.4;
white-space: nowrap; /* 单行显示 */
overflow: hidden; /* 隐藏溢出 */
text-overflow: ellipsis; /* 超出显示 ... */
max-width: 120px; /* 限制最大宽度 */
}
.checkbox-item .el-checkbox__inner:hover {
border-color: #409eff !important;
.duplicate-badge {
padding: 1px 4px;
font-size: 10px; /* 更小的 badge */
border-radius: 3px;
}
.checkbox-item .el-checkbox__input.is-checked .el-checkbox__inner {
background-color: #409eff !important;
border-color: #409eff !important;
/* 缩小复选框 */
.checkbox-item .el-checkbox__inner {
width: 14px !important;
height: 14px !important;
}
.checkbox-item .el-checkbox__inner::after {
height: 7px !important;
left: 4px !important;
top: 1px !important;
width: 3px !important;
border: 2px solid #fff !important;
border-left: 0 !important;
border-top: 0 !important;
/* 响应式:小屏幕保持紧凑 */
@media (max-width: 1100px) {
.checkbox-item { width: calc(25% - 8px); min-width: 140px; } /* 4 列 */
}
.checkbox-item .el-checkbox__label {
font-size: 13px !important;
font-weight: 500 !important;
color: #333 !important;
padding-left: 0 !important;
@media (max-width: 840px) {
.checkbox-item { width: calc(33.333% - 8px); min-width: 130px; } /* 3 列 */
}
.checkbox-item.is-checked .el-checkbox__label {
color: #17b3a3 !important;
@media (max-width: 520px) {
.checkbox-item { width: calc(50% - 8px); min-width: auto; } /* 2 列 */
}
/* 对话框底部按钮 */
/* ---------- Footer 固定在对话框底部(但不覆写内容) ---------- */
.dialog-footer {
text-align: center;
padding-top: 12px;
border-top: 1px solid #e4e7ed;
margin-top: 350px;
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: 80px;
min-width: 88px;
height: 36px;
font-size: 14px;
border-radius: 6px;
transition: all 0.2s;
font-weight: 600;
}
.dialog-footer .el-button + .el-button {
margin-left: 14px;
border-radius: 6px;
}
.dialog-footer .el-button--primary {
background: linear-gradient(135deg, #17b3a3 0%, #1dc5ef 100%);
color: #fff;
border: none;
box-shadow: 0 2px 8px rgba(23,179,163,0.12);
}
.dialog-footer .el-button--primary:hover {
background: linear-gradient(135deg, #1dc5ef 0%, #17b3a3 100%);
transform: translateY(-1px) scale(1.03);
box-shadow: 0 4px 12px rgba(23,179,163,0.18);
}
.dialog-footer .el-button--primary:active {
transform: translateY(0);
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.3);
}
/* 对话框整体样式优化 */
.data-source-dialog {
border-radius: 12px !important;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.15) !important;
max-height: 85vh !important;
overflow: visible !important;
}
.data-source-dialog .el-dialog__header {
padding: 20px 24px 16px !important;
border-bottom: 1px solid #e4e7ed !important;
}
.data-source-dialog .el-dialog__title {
font-size: 18px !important;
font-weight: 600 !important;
color: #303133 !important;
}
.data-source-dialog .el-dialog__body {
padding: 20px 24px 0 24px !important;
max-height: 65vh !important;
overflow-y: auto !important;
}
.data-source-dialog .el-dialog__footer {
padding: 16px 24px 20px !important;
border-top: 1px solid #e4e7ed !important;
background: #fff !important;
position: sticky !important;
bottom: 0 !important;
}
</style>
Loading…
Cancel
Save