Compare commits
3 Commits
cd2b745336
...
zh
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b40163b2e7 | ||
|
|
59c51ca360 | ||
|
|
7a7df06d66 |
@@ -135,6 +135,7 @@ const amountObj=ref<any>({})
|
|||||||
const crudRef = ref()
|
const crudRef = ref()
|
||||||
const dimensionFields=ref<any>({})
|
const dimensionFields=ref<any>({})
|
||||||
const exportLoading = ref(false)
|
const exportLoading = ref(false)
|
||||||
|
const fieldList = ref<any[]>([]) // 添加fieldList引用
|
||||||
const permissions =
|
const permissions =
|
||||||
wsCache.get(CACHE_KEY.USER).lideeYunjipermissions?.[route.meta.menuDataId as string] || false
|
wsCache.get(CACHE_KEY.USER).lideeYunjipermissions?.[route.meta.menuDataId as string] || false
|
||||||
const selectIds = computed(() => {
|
const selectIds = computed(() => {
|
||||||
@@ -167,7 +168,10 @@ const summaryMethod1=({columns,data})=>{
|
|||||||
const initTable = async () => {
|
const initTable = async () => {
|
||||||
isInit.value = false
|
isInit.value = false
|
||||||
loading.value = true
|
loading.value = true
|
||||||
const { fieldList, reportVo } = await ReportApi.getWebConfig(props.reportCode)
|
const { fieldList: apiFieldList, reportVo } = await ReportApi.getWebConfig(props.reportCode)
|
||||||
|
|
||||||
|
fieldList.value = apiFieldList
|
||||||
|
|
||||||
const isHeight = reportVo.tableConfig?.includes('height')
|
const isHeight = reportVo.tableConfig?.includes('height')
|
||||||
const isPage = reportVo.dataConfig?.includes('page')
|
const isPage = reportVo.dataConfig?.includes('page')
|
||||||
const isPermi = reportVo.dataConfig?.includes('authTrue')
|
const isPermi = reportVo.dataConfig?.includes('authTrue')
|
||||||
@@ -184,16 +188,47 @@ const initTable = async () => {
|
|||||||
border: reportVo.tableConfig.includes('border'),
|
border: reportVo.tableConfig.includes('border'),
|
||||||
stripe: reportVo.tableConfig.includes('stripe'),
|
stripe: reportVo.tableConfig.includes('stripe'),
|
||||||
showSummary:false,
|
showSummary:false,
|
||||||
|
|
||||||
column: {}
|
column: {}
|
||||||
}
|
}
|
||||||
//国际化处理
|
|
||||||
const fieldLengObj = assembleLengObj(fieldList, 'labelI18n', 'fieldCode', 'fieldName')
|
const fieldLengObj = assembleLengObj(apiFieldList, 'labelI18n', 'fieldCode', 'fieldName')
|
||||||
for (const key in fieldLengObj) {
|
for (const key in fieldLengObj) {
|
||||||
mergeLocaleMessage(key, { [props.reportCode]: fieldLengObj[key] })
|
mergeLocaleMessage(key, { [props.reportCode]: fieldLengObj[key] })
|
||||||
}
|
}
|
||||||
//字段处理
|
|
||||||
fieldList.forEach((item,index) => {
|
// 分离固定列和动态列
|
||||||
|
const fixedFields = apiFieldList.filter(f => f.isFixedColumn === 'Y')
|
||||||
|
const dynamicFields = apiFieldList.filter(f => f.isFixedColumn !== 'Y')
|
||||||
|
|
||||||
|
// 处理固定列
|
||||||
|
fixedFields.forEach((item) => {
|
||||||
|
const config: any = {
|
||||||
|
prop: item.fieldCode,
|
||||||
|
label: t(`${props.reportCode}.${item.fieldCode}`),
|
||||||
|
type: 'input',
|
||||||
|
overHidden: true,
|
||||||
|
isExport: item.isExport == 'Y',
|
||||||
|
search: item.queryIsWeb == 'Y',
|
||||||
|
fixed: true
|
||||||
|
}
|
||||||
|
tableOption.value.column[item.fieldCode] = config
|
||||||
|
})
|
||||||
|
|
||||||
|
// 构建父子关系映射(仅用于识别子字段配置)
|
||||||
|
const childFieldConfigs = new Map()
|
||||||
|
dynamicFields.forEach(field => {
|
||||||
|
if (field.parentFieldCode && field.parentFieldCode !== '') {
|
||||||
|
if (!childFieldConfigs.has(field.parentFieldCode)) {
|
||||||
|
childFieldConfigs.set(field.parentFieldCode, [])
|
||||||
|
}
|
||||||
|
childFieldConfigs.get(field.parentFieldCode).push(field)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理动态列(暂不构建children,等数据返回后动态生成)
|
||||||
|
dynamicFields.forEach((item, index) => {
|
||||||
|
if (item.parentFieldCode && item.parentFieldCode !== '') return
|
||||||
|
|
||||||
const config: any = {
|
const config: any = {
|
||||||
prop: item.fieldCode,
|
prop: item.fieldCode,
|
||||||
label: t(`${props.reportCode}.${item.fieldCode}`),
|
label: t(`${props.reportCode}.${item.fieldCode}`),
|
||||||
@@ -202,7 +237,10 @@ const initTable = async () => {
|
|||||||
isExport: item.isExport == 'Y',
|
isExport: item.isExport == 'Y',
|
||||||
sortable: item.isShowSort == 'Y' ? 'custom' : false,
|
sortable: item.isShowSort == 'Y' ? 'custom' : false,
|
||||||
search: item.queryIsWeb == 'Y',
|
search: item.queryIsWeb == 'Y',
|
||||||
|
_hasChildConfig: childFieldConfigs.has(item.fieldCode),
|
||||||
|
_childConfigs: childFieldConfigs.get(item.fieldCode) || []
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!!item.isAmount){
|
if(!!item.isAmount){
|
||||||
index==0?amountFieds.value.fistField=config.prop:''
|
index==0?amountFieds.value.fistField=config.prop:''
|
||||||
amountFieds.value[item.isAmount]=config
|
amountFieds.value[item.isAmount]=config
|
||||||
@@ -218,25 +256,17 @@ const initTable = async () => {
|
|||||||
config.type = 'date'
|
config.type = 'date'
|
||||||
config.format = 'YYYY-MM-DD'
|
config.format = 'YYYY-MM-DD'
|
||||||
config.valueFormat = 'YYYY-MM-DD'
|
config.valueFormat = 'YYYY-MM-DD'
|
||||||
if(config.searchRange){
|
if(config.searchRange) dateRange.value.push(config.prop)
|
||||||
dateRange.value.push(config.prop)
|
|
||||||
}
|
|
||||||
} else if (item.fieldType == 'Time') {
|
} else if (item.fieldType == 'Time') {
|
||||||
config.type = 'time'
|
config.type = 'time'
|
||||||
config.format = 'HH:mm:ss'
|
config.format = 'HH:mm:ss'
|
||||||
config.valueFormat = 'HH:mm:ss'
|
config.valueFormat = 'HH:mm:ss'
|
||||||
|
if(config.searchRange) timeRange.value.push(config.prop)
|
||||||
if(config.searchRange){
|
|
||||||
timeRange.value.push(config.prop)
|
|
||||||
}
|
|
||||||
} else if (item.fieldType == 'DateTime') {
|
} else if (item.fieldType == 'DateTime') {
|
||||||
config.type = 'datetime'
|
config.type = 'datetime'
|
||||||
config.format = 'YYYY-MM-DD HH:mm:ss'
|
config.format = 'YYYY-MM-DD HH:mm:ss'
|
||||||
config.valueFormat = 'YYYY-MM-DD HH:mm:ss'
|
config.valueFormat = 'YYYY-MM-DD HH:mm:ss'
|
||||||
if(config.searchRange){
|
if(config.searchRange) dateTimeRange.value.push(config.prop)
|
||||||
dateTimeRange.value.push(config.prop)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.type == 'number' && config.searchRange) numberRange.value.push(config.prop)
|
if (config.type == 'number' && config.searchRange) numberRange.value.push(config.prop)
|
||||||
@@ -247,7 +277,6 @@ const initTable = async () => {
|
|||||||
tableOption.value.column[item.fieldCode] = config
|
tableOption.value.column[item.fieldCode] = config
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
isInit.value = true
|
isInit.value = true
|
||||||
searchChange()
|
searchChange()
|
||||||
initTableLayout()
|
initTableLayout()
|
||||||
@@ -318,9 +347,163 @@ const getTableData = async (isLoading = true) => {
|
|||||||
if (isLoading) loading.value = true
|
if (isLoading) loading.value = true
|
||||||
const searchObj = await getSearchData()
|
const searchObj = await getSearchData()
|
||||||
try {
|
try {
|
||||||
const data = await ReportApi.getTableList(props.reportCode, searchObj)
|
// 获取数据
|
||||||
|
let data = await ReportApi.getTableList(props.reportCode, searchObj)
|
||||||
|
|
||||||
|
// 功能测试:CS_DTBT报表使用模拟数据
|
||||||
|
if (props.reportCode === 'CS_DTBT') {
|
||||||
|
data = {
|
||||||
|
records: [
|
||||||
|
{ "yuefen": "一月", "benyue": 100, "leiji": 110 },
|
||||||
|
{ "yuefen": "一月", "benyue": 120, "leiji": 130 },
|
||||||
|
{ "yuefen": "二月", "benyue": 140, "leiji": 150 },
|
||||||
|
{ "yuefen": "二月", "benyue": 160, "leiji": 170 },
|
||||||
|
{ "yuefen": "三月", "benyue": 180, "leiji": 190 },
|
||||||
|
{ "yuefen": "三月", "benyue": 200, "leiji": 210 },
|
||||||
|
{ "yuefen": "四月", "benyue": null, "leiji": null },
|
||||||
|
{ "yuefen": "四月", "benyue": 220, "leiji": 230 },
|
||||||
|
{ "yuefen": "五月", "benyue": 333, "leiji": 444 },
|
||||||
|
{ "yuefen": "六月", "benyue": 555, "leiji": 555 },
|
||||||
|
{ "yuefen": "六月", "benyue": 666, "leiji": 666 },
|
||||||
|
|
||||||
|
],
|
||||||
|
total: 6
|
||||||
|
}
|
||||||
|
}
|
||||||
if (tablePage.value) tablePage.value['total'] = data.total
|
if (tablePage.value) tablePage.value['total'] = data.total
|
||||||
tableData.value = data.records
|
|
||||||
|
// 查找动态分组字段(用于生成一级表头)
|
||||||
|
const groupField = fieldList.value.find(f => f.isDynamicGroup === 'Y')
|
||||||
|
|
||||||
|
// 动态生成二维表头
|
||||||
|
if (data.records && data.records.length > 0) {
|
||||||
|
const newColumns = {}
|
||||||
|
|
||||||
|
// 保留固定列
|
||||||
|
for (const colKey in tableOption.value.column) {
|
||||||
|
const colConfig = tableOption.value.column[colKey]
|
||||||
|
if (colConfig.fixed) {
|
||||||
|
newColumns[colKey] = colConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupField) {
|
||||||
|
// 有分组字段,从数据中提取所有不重复的分组值(一级表头)
|
||||||
|
const groupValues = [...new Set(data.records.map(r => r[groupField.fieldCode]))].filter(Boolean)
|
||||||
|
|
||||||
|
// 找到所有子字段配置(按sortNum排序)
|
||||||
|
const childFields = fieldList.value
|
||||||
|
.filter(f =>
|
||||||
|
f.parentFieldCode &&
|
||||||
|
f.parentFieldCode !== '' &&
|
||||||
|
f.isFixedColumn !== 'Y'
|
||||||
|
)
|
||||||
|
.sort((a, b) => (a.sortNum || 0) - (b.sortNum || 0))
|
||||||
|
|
||||||
|
// 为每个分组值生成列
|
||||||
|
groupValues.forEach(groupValue => {
|
||||||
|
const parentProp = `group_${groupValue}`
|
||||||
|
newColumns[parentProp] = {
|
||||||
|
label: groupValue,
|
||||||
|
children: childFields.map(childField => ({
|
||||||
|
prop: `${parentProp}_${childField.fieldCode}`,
|
||||||
|
label: t(`${props.reportCode}.${childField.fieldCode}`),
|
||||||
|
type: ['Integer', 'BigInt', 'BigDecimal'].includes(childField.fieldType) ? 'number' : 'input',
|
||||||
|
overHidden: true,
|
||||||
|
isExport: childField.isExport == 'Y'
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 没有分组字段,使用原有的逻辑
|
||||||
|
for (const colKey in tableOption.value.column) {
|
||||||
|
const colConfig = tableOption.value.column[colKey]
|
||||||
|
if (!colConfig.fixed) {
|
||||||
|
newColumns[colKey] = colConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tableOption.value.column = newColumns
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将扁平数据按分组字段转换为二维表头数据
|
||||||
|
let processedData = []
|
||||||
|
|
||||||
|
if (groupField && data.records.length > 0) {
|
||||||
|
// 有分组字段,根据分组字段值进行分组
|
||||||
|
const fixedFields = fieldList.value.filter(f => f.isFixedColumn === 'Y')
|
||||||
|
const childFields = fieldList.value
|
||||||
|
.filter(f => f.parentFieldCode && f.parentFieldCode !== '' && f.isFixedColumn !== 'Y')
|
||||||
|
.sort((a, b) => (a.sortNum || 0) - (b.sortNum || 0))
|
||||||
|
|
||||||
|
// 获取所有分组值
|
||||||
|
const groupValues = [...new Set(data.records.map(r => r[groupField.fieldCode]))].filter(Boolean)
|
||||||
|
|
||||||
|
// 按分组字段值对数据进行分组
|
||||||
|
const groupedData = {}
|
||||||
|
data.records.forEach(record => {
|
||||||
|
const groupValue = record[groupField.fieldCode]
|
||||||
|
if (!groupedData[groupValue]) {
|
||||||
|
groupedData[groupValue] = []
|
||||||
|
}
|
||||||
|
groupedData[groupValue].push(record)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算需要生成的行数(根据固定列配置或分组内最大数据量)
|
||||||
|
let rowCount = 1
|
||||||
|
if (fixedFields.length > 0 && fixedFields[0].fixedColumnValue) {
|
||||||
|
rowCount = fixedFields[0].fixedColumnValue.split(',').length
|
||||||
|
} else {
|
||||||
|
// 如果没有固定列,取每个分组中数据最多的数量
|
||||||
|
rowCount = Math.max(...Object.values(groupedData).map((arr: any[]) => arr.length))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按行处理数据
|
||||||
|
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
||||||
|
const flatRecord = {}
|
||||||
|
|
||||||
|
// 处理固定列
|
||||||
|
fixedFields.forEach(field => {
|
||||||
|
if (field.fixedColumnValue) {
|
||||||
|
const fixedValues = field.fixedColumnValue.split(',')
|
||||||
|
flatRecord[field.fieldCode] = fixedValues[rowIndex] || ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理动态列数据(根据分组字段值获取对应数据)
|
||||||
|
groupValues.forEach(groupValue => {
|
||||||
|
const groupRecords = groupedData[groupValue] || []
|
||||||
|
const record = groupRecords[rowIndex]
|
||||||
|
|
||||||
|
if (record) {
|
||||||
|
const parentProp = `group_${groupValue}`
|
||||||
|
childFields.forEach(childField => {
|
||||||
|
flatRecord[`${parentProp}_${childField.fieldCode}`] = record[childField.fieldCode]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
processedData.push(flatRecord)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 没有分组字段,直接处理数据
|
||||||
|
processedData = data.records.map((record, recordIndex) => {
|
||||||
|
const flatRecord = { ...record }
|
||||||
|
|
||||||
|
// 处理固定列
|
||||||
|
fieldList.value.forEach(field => {
|
||||||
|
if (field.isFixedColumn === 'Y' && field.fixedColumnValue) {
|
||||||
|
const fixedValues = field.fixedColumnValue.split(',')
|
||||||
|
flatRecord[field.fieldCode] = fixedValues[recordIndex] || ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return flatRecord
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
tableData.value = processedData
|
||||||
// amountFieds.value={
|
// amountFieds.value={
|
||||||
// 'thissaqty_s':{
|
// 'thissaqty_s':{
|
||||||
// prop:'thissaqty',
|
// prop:'thissaqty',
|
||||||
|
|||||||
@@ -164,7 +164,21 @@ export const useRenderVxeColumn = (useType = 'table') => {
|
|||||||
multiple={multiple}
|
multiple={multiple}
|
||||||
filterable={filterable}
|
filterable={filterable}
|
||||||
allowCreate={allowCreate}
|
allowCreate={allowCreate}
|
||||||
onChange={() => renderOpts.events ? renderOpts.events.change(row, column.field, rowIndex) : ''}
|
clearable={true}
|
||||||
|
onChange={(value) => {
|
||||||
|
// 先更新行数据
|
||||||
|
row[column.field] = value
|
||||||
|
// 再触发自定义事件
|
||||||
|
if (renderOpts.events && renderOpts.events.change) {
|
||||||
|
renderOpts.events.change(row, column.field, rowIndex)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onClear={() => {
|
||||||
|
// 触发清空事件
|
||||||
|
if (renderOpts.events && renderOpts.events.clear) {
|
||||||
|
renderOpts.events.clear(row, column.field, rowIndex)
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -252,6 +266,32 @@ export const useRenderVxeColumn = (useType = 'table') => {
|
|||||||
</el-popover>
|
</el-popover>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
LowButton: {
|
||||||
|
default: (renderOpts, { row, column }) => {
|
||||||
|
const { buttonText, disabled } = renderOpts
|
||||||
|
const isDisabled = typeof disabled === 'function' ? disabled(row) : disabled
|
||||||
|
if (isDisabled) return <span style="color: #c0c4cc;">-</span>
|
||||||
|
return <span style="color: #409eff; cursor: pointer;">{buttonText || '操作'}</span>
|
||||||
|
},
|
||||||
|
edit: (renderOpts, { row, column }) => {
|
||||||
|
const { buttonText, buttonType, buttonSize, disabled } = renderOpts
|
||||||
|
const isDisabled = typeof disabled === 'function' ? disabled(row) : disabled
|
||||||
|
return (
|
||||||
|
<el-button
|
||||||
|
type={buttonType || 'primary'}
|
||||||
|
size={buttonSize || 'small'}
|
||||||
|
disabled={isDisabled}
|
||||||
|
onClick={() => {
|
||||||
|
if (renderOpts.events && renderOpts.events.click) {
|
||||||
|
renderOpts.events.click(row)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{buttonText || '操作'}
|
||||||
|
</el-button>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const key in lowControl) {
|
for (const key in lowControl) {
|
||||||
|
|||||||
@@ -40,15 +40,75 @@
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</DesignPopup>
|
</DesignPopup>
|
||||||
|
<!-- 固定列行配置弹窗 -->
|
||||||
|
<DesignPopup
|
||||||
|
v-model="fixedColumnDialog.visible"
|
||||||
|
title="配置固定列内容"
|
||||||
|
width="600px"
|
||||||
|
:is-footer="true"
|
||||||
|
:handleClose="handleFixedColumnClose"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<div style="padding: 20px;">
|
||||||
|
<el-alert
|
||||||
|
title="提示"
|
||||||
|
type="info"
|
||||||
|
:closable="false"
|
||||||
|
style="margin-bottom: 20px;"
|
||||||
|
>
|
||||||
|
为该固定列的每一行配置不同的显示内容。点击"添加行"按钮增加新行,输入内容后保存。
|
||||||
|
</el-alert>
|
||||||
|
|
||||||
|
<div style="margin-bottom: 15px;">
|
||||||
|
<ElButton type="primary" @click="addFixedColumnRow" size="small">
|
||||||
|
<Icon icon="ep:plus" />
|
||||||
|
添加行
|
||||||
|
</ElButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="fixedColumnDialog.rows.length === 0" style="text-align: center; padding: 40px; color: #909399;">
|
||||||
|
暂无配置,请点击"添加行"按钮添加内容
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else style="max-height: 400px; overflow-y: auto;">
|
||||||
|
<div
|
||||||
|
v-for="(row, index) in fixedColumnDialog.rows"
|
||||||
|
:key="index"
|
||||||
|
style="display: flex; align-items: center; margin-bottom: 10px;"
|
||||||
|
>
|
||||||
|
<span style="width: 80px; color: #606266;">第 {{ index + 1 }} 行:</span>
|
||||||
|
<ElInput
|
||||||
|
v-model="row.value"
|
||||||
|
placeholder="请输入该行显示的内容"
|
||||||
|
style="flex: 1; margin-right: 10px;"
|
||||||
|
/>
|
||||||
|
<ElButton
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
@click="removeFixedColumnRow(index)"
|
||||||
|
:icon="Delete"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</ElButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<ElButton @click="handleFixedColumnCancel">取 消</ElButton>
|
||||||
|
<ElButton type="primary" @click="handleFixedColumnSave">确 定</ElButton>
|
||||||
|
</template>
|
||||||
|
</DesignPopup>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SqlOption, InfoVxeTable, InfoVxeTopBtn } from '../../tableDesign/components'
|
import { SqlOption, InfoVxeTable, InfoVxeTopBtn } from '../../tableDesign/components'
|
||||||
import { MonacoEditor } from '@/components/MonacoEditor/index'
|
import { MonacoEditor } from '@/components/MonacoEditor/index'
|
||||||
import { tableInfoOption } from '../designData'
|
import { tableInfoOption, dicObj } from '../designData'
|
||||||
import { formattingLengStr } from '@/utils/lowDesign'
|
import { formattingLengStr } from '@/utils/lowDesign'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
import * as DictDataApi from '@/api/system/dict/dict.type'
|
import * as DictDataApi from '@/api/system/dict/dict.type'
|
||||||
|
import { Delete } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
defineOptions({ name: 'TableInfo' })
|
defineOptions({ name: 'TableInfo' })
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
@@ -83,6 +143,17 @@ const optionComponents = markRaw({
|
|||||||
const optionRef = ref({})
|
const optionRef = ref({})
|
||||||
const tabsRef = ref()
|
const tabsRef = ref()
|
||||||
|
|
||||||
|
// 父字段引用
|
||||||
|
const parentFieldMap = ref(new Map())
|
||||||
|
|
||||||
|
// 固定列行配置弹窗
|
||||||
|
const fixedColumnDialog = ref({
|
||||||
|
visible: false,
|
||||||
|
currentRow: null as any,
|
||||||
|
rows: [] as Array<{ value: string }>,
|
||||||
|
originalValue: '' // 保存原始值,用于取消时恢复
|
||||||
|
})
|
||||||
|
|
||||||
const fieldList = computed(() => {
|
const fieldList = computed(() => {
|
||||||
let dicData: Array<{ label: string; value: string; type: string }> = []
|
let dicData: Array<{ label: string; value: string; type: string }> = []
|
||||||
infoData.value.basics.forEach((item) => {
|
infoData.value.basics.forEach((item) => {
|
||||||
@@ -113,6 +184,7 @@ const dorpdownHandleCommand = (command) => {
|
|||||||
nextTick(() => infoData.value[dataKey].splice(type == 'up' ? index - 1 : index + 1, 0, delItem))
|
nextTick(() => infoData.value[dataKey].splice(type == 'up' ? index - 1 : index + 1, 0, delItem))
|
||||||
} else if (type == 'add') cellAddData(index + 1)
|
} else if (type == 'add') cellAddData(index + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const setInfoOrder = () => {
|
const setInfoOrder = () => {
|
||||||
let { dataKey } = tabsValue.value
|
let { dataKey } = tabsValue.value
|
||||||
if (!dataKey) return
|
if (!dataKey) return
|
||||||
@@ -182,16 +254,137 @@ const tableScrollIndex = (key, index, addIndex?) => {
|
|||||||
|
|
||||||
const cellClick = ({ rowIndex }) => {
|
const cellClick = ({ rowIndex }) => {
|
||||||
let { prop } = tabsValue.value
|
let { prop } = tabsValue.value
|
||||||
|
// 普通行点击进入编辑状态
|
||||||
tableRefObj.value[prop].vxeTableRef.setEditRow(
|
tableRefObj.value[prop].vxeTableRef.setEditRow(
|
||||||
tableRefObj.value[prop].vxeTableRef.getData(rowIndex)
|
tableRefObj.value[prop].vxeTableRef.getData(rowIndex)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加子字段行
|
||||||
|
const addSubFieldRow = (parentField, parentRowIndex) => {
|
||||||
|
let { key, dataKey } = tabsValue.value
|
||||||
|
if (!dataKey) return
|
||||||
|
|
||||||
|
// 创建子字段数据
|
||||||
|
let subFieldData = cloneDeep(tableInfoOption.infoDefaultData[dataKey]) || {}
|
||||||
|
subFieldData.parentFieldId = parentField._X_ROW_KEY
|
||||||
|
subFieldData.isSubField = true
|
||||||
|
subFieldData.parentFieldName = parentField.fieldName
|
||||||
|
|
||||||
|
parentField.hasChildren = 'Y'
|
||||||
|
// 确保子字段不能包含子字段
|
||||||
|
subFieldData.hasChildren = 'N'
|
||||||
|
|
||||||
|
// 在父字段下方插入子字段行
|
||||||
|
let insertIndex = parentRowIndex + 1
|
||||||
|
infoData.value[dataKey].splice(insertIndex, 0, subFieldData)
|
||||||
|
|
||||||
|
// 记录父子关系
|
||||||
|
parentFieldMap.value.set(subFieldData._X_ROW_KEY, parentField._X_ROW_KEY)
|
||||||
|
|
||||||
|
// 滚动到新添加的行并设置为编辑状态
|
||||||
|
tableScrollIndex(key, insertIndex, insertIndex)
|
||||||
|
|
||||||
|
// 给出成功提示
|
||||||
|
nextTick(() => {
|
||||||
|
message.success(`已为字段 "${parentField.fieldName}" 添加子字段`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开固定列行配置弹窗
|
||||||
|
const openFixedColumnDialog = (row) => {
|
||||||
|
fixedColumnDialog.value.currentRow = row
|
||||||
|
// 保存原始值
|
||||||
|
fixedColumnDialog.value.originalValue = row.fixedColumnValue || ''
|
||||||
|
|
||||||
|
// 将字符串转换为数组:按逗号分割
|
||||||
|
let rowsArray = []
|
||||||
|
if (row.fixedColumnValue && typeof row.fixedColumnValue === 'string' && row.fixedColumnValue.trim() !== '') {
|
||||||
|
rowsArray = row.fixedColumnValue.split(',').map(value => ({ value: value }))
|
||||||
|
}
|
||||||
|
fixedColumnDialog.value.rows = rowsArray
|
||||||
|
fixedColumnDialog.value.visible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加固定列行
|
||||||
|
const addFixedColumnRow = () => {
|
||||||
|
fixedColumnDialog.value.rows.push({ value: '' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除固定列行
|
||||||
|
const removeFixedColumnRow = (index) => {
|
||||||
|
fixedColumnDialog.value.rows.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消固定列配置
|
||||||
|
const handleFixedColumnCancel = () => {
|
||||||
|
// 恢复原始值
|
||||||
|
if (fixedColumnDialog.value.currentRow) {
|
||||||
|
fixedColumnDialog.value.currentRow.fixedColumnValue = fixedColumnDialog.value.originalValue
|
||||||
|
}
|
||||||
|
fixedColumnDialog.value.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理弹窗关闭(X按钮或遮罩层)
|
||||||
|
const handleFixedColumnClose = (done: () => void) => {
|
||||||
|
// 恢复原始值
|
||||||
|
if (fixedColumnDialog.value.currentRow) {
|
||||||
|
fixedColumnDialog.value.currentRow.fixedColumnValue = fixedColumnDialog.value.originalValue
|
||||||
|
}
|
||||||
|
done()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存固定列配置
|
||||||
|
const handleFixedColumnSave = () => {
|
||||||
|
if (fixedColumnDialog.value.currentRow) {
|
||||||
|
// 将数组转换为字符串:使用逗号拼接
|
||||||
|
const rowValues = fixedColumnDialog.value.rows.map(row => row.value)
|
||||||
|
fixedColumnDialog.value.currentRow.fixedColumnValue = rowValues.join(',')
|
||||||
|
|
||||||
|
message.success(`已保存固定列"${fixedColumnDialog.value.currentRow.fieldName}"的行配置(共${fixedColumnDialog.value.rows.length}行)`)
|
||||||
|
}
|
||||||
|
fixedColumnDialog.value.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
const initEditInfoData = () => {
|
const initEditInfoData = () => {
|
||||||
const data = tableInfoOption.formattingInitData(props.editInfoData)
|
const data = tableInfoOption.formattingInitData(props.editInfoData)
|
||||||
const fieldList: any[] = []
|
const fieldList: any[] = []
|
||||||
|
|
||||||
|
// 重建父子字段关系
|
||||||
|
const fieldCodeMap = new Map()
|
||||||
|
|
||||||
|
// 第一遍遍历:建立字段编码映射
|
||||||
|
data.infoData.forEach((item, index) => {
|
||||||
|
if (item.fieldCode) {
|
||||||
|
fieldCodeMap.set(item.fieldCode, { ...item, originalIndex: index })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 第二遍遍历:处理子字段关系
|
||||||
|
data.infoData.forEach((item) => {
|
||||||
|
const fieldItem = cloneDeep(item)
|
||||||
|
|
||||||
|
// 如果是子字段且有父字段编码
|
||||||
|
if (fieldItem.parentFieldCode && fieldCodeMap.has(fieldItem.parentFieldCode)) {
|
||||||
|
fieldItem.isSubField = true
|
||||||
|
fieldItem.parentFieldId = fieldCodeMap.get(fieldItem.parentFieldCode)._X_ROW_KEY
|
||||||
|
// 设置父字段显示名称(只显示字段名称)
|
||||||
|
const parentField = fieldCodeMap.get(fieldItem.parentFieldCode)
|
||||||
|
fieldItem.parentFieldName = parentField.fieldName
|
||||||
|
|
||||||
|
// 记录父子关系
|
||||||
|
parentFieldMap.value.set(fieldItem._X_ROW_KEY, fieldItem.parentFieldId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果字段包含子字段,设置相应标识
|
||||||
|
if (fieldItem.hasChildren === 'Y') {
|
||||||
|
fieldItem.hasChildren = 'Y'
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldList.push(fieldItem)
|
||||||
|
})
|
||||||
|
|
||||||
tableInfoDefault.value = data.infoData.filter((item) => {
|
tableInfoDefault.value = data.infoData.filter((item) => {
|
||||||
fieldList.push(cloneDeep(item))
|
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
infoData.value.basics = fieldList
|
infoData.value.basics = fieldList
|
||||||
@@ -201,8 +394,9 @@ onMounted(() => {
|
|||||||
tableInfoDefault.value = []
|
tableInfoDefault.value = []
|
||||||
infoData.value.basics = []
|
infoData.value.basics = []
|
||||||
if (props.formType != 'add') initEditInfoData()
|
if (props.formType != 'add') initEditInfoData()
|
||||||
const { fieldColumn } = tableInfoOption.infoColumn
|
|
||||||
fieldColumn.labelI18n.editRender.events = {
|
// 设置字段国际化配置的点击事件
|
||||||
|
tableInfoOption.infoColumn.fieldColumn.labelI18n.editRender.events = {
|
||||||
click: (row) => {
|
click: (row) => {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
tableRefObj.value['tab_field'].vxeTableRef.setRow(row, {
|
tableRefObj.value['tab_field'].vxeTableRef.setRow(row, {
|
||||||
@@ -211,14 +405,251 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置父字段下拉选项
|
||||||
|
const updateParentFieldOptions = () => {
|
||||||
|
// 获取所有parentFieldCode为空且非固定列的字段作为可选父字段
|
||||||
|
const parentFieldOptions = infoData.value.basics
|
||||||
|
.filter(field => !field.parentFieldCode && field.fieldCode && field.fieldName && field.isFixedColumn !== 'Y')
|
||||||
|
.map(field => ({
|
||||||
|
label: `${field.fieldName}`,
|
||||||
|
value: field.fieldCode
|
||||||
|
}))
|
||||||
|
|
||||||
|
// 更新父字段列的下拉选项
|
||||||
|
tableInfoOption.infoColumn.fieldColumn.parentFieldName.editRender.dicData = parentFieldOptions
|
||||||
|
}
|
||||||
|
// 用于跟踪上次选中的值,避免重复触发
|
||||||
|
let _lastSelectedValue = ''
|
||||||
|
|
||||||
|
// 父字段选择事件处理
|
||||||
|
tableInfoOption.infoColumn.fieldColumn.parentFieldName.editRender.events = {
|
||||||
|
// 简化的change事件处理
|
||||||
|
change: (row) => {
|
||||||
|
console.log('父字段选择change事件触发:', row.parentFieldName);
|
||||||
|
const selectdItem = row.parentFieldName.item;
|
||||||
|
|
||||||
|
if(!selectdItem) return;
|
||||||
|
|
||||||
|
// 获取选中的字段编码
|
||||||
|
let selectedParentCode = selectdItem.value;
|
||||||
|
console.log('选中的值:', selectedParentCode);
|
||||||
|
|
||||||
|
|
||||||
|
_lastSelectedValue = selectedParentCode;
|
||||||
|
|
||||||
|
if (selectedParentCode && selectedParentCode.trim() !== '') {
|
||||||
|
// 检查是否在有效选项中
|
||||||
|
const isValidOption = infoData.value.basics.some(field =>
|
||||||
|
field.fieldCode === selectedParentCode && !field.parentFieldCode
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isValidOption) {
|
||||||
|
handleParentFieldSelection(row, selectedParentCode);
|
||||||
|
} else {
|
||||||
|
console.log('无效的选项:', selectedParentCode);
|
||||||
|
// 重置无效选择
|
||||||
|
row.parentFieldName = '';
|
||||||
|
row.parentFieldCode = '';
|
||||||
|
row.parentFieldId = '';
|
||||||
|
row.isSubField = false;
|
||||||
|
_lastSelectedValue = '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 清空选择
|
||||||
|
handleParentFieldClear(row);
|
||||||
|
_lastSelectedValue = '';
|
||||||
|
}
|
||||||
|
// 更新父字段选项
|
||||||
|
updateParentFieldOptions();
|
||||||
|
},
|
||||||
|
// 添加clear事件专门处理清空操作
|
||||||
|
clear: (row) => {
|
||||||
|
console.log('父字段清空事件触发');
|
||||||
|
handleParentFieldClear(row);
|
||||||
|
_lastSelectedValue = '';
|
||||||
|
updateParentFieldOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理父字段选择
|
||||||
|
const handleParentFieldSelection = (row, selectedParentCode) => {
|
||||||
|
// 找到选中的父字段
|
||||||
|
const parentField = infoData.value.basics.find(field => field.fieldCode === selectedParentCode);
|
||||||
|
if (!parentField) return;
|
||||||
|
|
||||||
|
// 检查是否形成循环引用
|
||||||
|
if (checkCircularReference(row, parentField)) {
|
||||||
|
message.warning('不能形成循环引用!');
|
||||||
|
// 先清空显示值,再x用清空处理函数
|
||||||
|
handleParentFieldClear(row);
|
||||||
|
// 强制刷新表格以确保UI更新
|
||||||
|
nextTick(() => {
|
||||||
|
if (tableRefObj.value && tableRefObj.value['tab_field'] && tableRefObj.value['tab_field'].vxeTableRef) {
|
||||||
|
tableRefObj.value['tab_field'].vxeTableRef.refreshColumn();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存旧的父字段信息用于清理
|
||||||
|
const oldParentFieldCode = row.parentFieldCode;
|
||||||
|
|
||||||
|
// 设置当前字段的父子关系
|
||||||
|
row.parentFieldCode = selectedParentCode;
|
||||||
|
row.parentFieldId = parentField._X_ROW_KEY;
|
||||||
|
row.isSubField = true;
|
||||||
|
row.parentFieldName = parentField.fieldName; // 显示选中的字段名称
|
||||||
|
|
||||||
|
// 设置父字段的hasChildren为'Y'
|
||||||
|
parentField.hasChildren = 'Y';
|
||||||
|
|
||||||
|
// 清理旧父字段的关系
|
||||||
|
if (oldParentFieldCode && oldParentFieldCode !== selectedParentCode) {
|
||||||
|
const oldParentField = infoData.value.basics.find(field => field.fieldCode === oldParentFieldCode);
|
||||||
|
if (oldParentField) {
|
||||||
|
const hasOtherChildren = infoData.value.basics.some(child =>
|
||||||
|
child.parentFieldCode === oldParentFieldCode && child !== row
|
||||||
|
);
|
||||||
|
if (!hasOtherChildren) {
|
||||||
|
oldParentField.hasChildren = 'N';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message.success(`已将 "${row.fieldName}" 设置为 "${parentField.fieldName}" 的子字段`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理父字段清空
|
||||||
|
const handleParentFieldClear = (row) => {
|
||||||
|
const oldParentFieldCode = row.parentFieldCode;
|
||||||
|
|
||||||
|
// 清空所有父子关系相关字段
|
||||||
|
row.parentFieldCode = '';
|
||||||
|
row.parentFieldId = '';
|
||||||
|
row.parentFieldName = '';
|
||||||
|
row.isSubField = false;
|
||||||
|
|
||||||
|
// 清理旧父字段的关系
|
||||||
|
if (oldParentFieldCode) {
|
||||||
|
const oldParentField = infoData.value.basics.find(field => field.fieldCode === oldParentFieldCode);
|
||||||
|
if (oldParentField) {
|
||||||
|
const hasOtherChildren = infoData.value.basics.some(child =>
|
||||||
|
child.parentFieldCode === oldParentFieldCode && child !== row
|
||||||
|
);
|
||||||
|
if (!hasOtherChildren) {
|
||||||
|
oldParentField.hasChildren = 'N';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查循环引用
|
||||||
|
const checkCircularReference = (childField, parentField) => {
|
||||||
|
// 如果子字段本身就是父字段,则不允许
|
||||||
|
if (childField.fieldCode === parentField.fieldCode) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查父字段是否已经是该子字段的子字段
|
||||||
|
let currentParent = parentField
|
||||||
|
while (currentParent && currentParent.parentFieldCode) {
|
||||||
|
if (currentParent.parentFieldCode === childField.fieldCode) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
currentParent = infoData.value.basics.find(field => field.fieldCode === currentParent.parentFieldCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听数据变化,更新父字段选项
|
||||||
|
watch(() => infoData.value.basics, updateParentFieldOptions, { deep: true })
|
||||||
|
|
||||||
|
// 监听字段名称变化,同步更新父字段显示
|
||||||
|
watch(() => infoData.value.basics, (newBasics) => {
|
||||||
|
newBasics.forEach(field => {
|
||||||
|
if (field.parentFieldCode) {
|
||||||
|
const parentField = newBasics.find(f => f.fieldCode === field.parentFieldCode)
|
||||||
|
if (parentField) {
|
||||||
|
// 更新为被选择字段的fieldName
|
||||||
|
field.parentFieldName = parentField.fieldName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
updateParentFieldOptions()
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
// 初始化父字段选项
|
||||||
|
updateParentFieldOptions()
|
||||||
|
|
||||||
|
// 添加固定列选项的change事件处理
|
||||||
|
tableInfoOption.infoColumn.fieldColumn.isFixedColumn.editRender.events = {
|
||||||
|
change: (row) => {
|
||||||
|
if (row.isFixedColumn === 'Y') {
|
||||||
|
// 固定列不能有父字段
|
||||||
|
if (row.parentFieldCode) {
|
||||||
|
handleParentFieldClear(row)
|
||||||
|
}
|
||||||
|
// 固定列不能有子字段
|
||||||
|
if (row.hasChildren === 'Y') {
|
||||||
|
row.hasChildren = 'N'
|
||||||
|
// 清除所有子字段的父子关系
|
||||||
|
infoData.value.basics.forEach(field => {
|
||||||
|
if (field.parentFieldCode === row.fieldCode) {
|
||||||
|
handleParentFieldClear(field)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 取消固定列时清空固定列内容
|
||||||
|
row.fixedColumnValue = ''
|
||||||
|
}
|
||||||
|
updateParentFieldOptions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加固定列内容配置按钮的点击事件
|
||||||
|
tableInfoOption.infoColumn.fieldColumn.fixedColumnValue.editRender.events = {
|
||||||
|
click: (row) => {
|
||||||
|
if (row.isFixedColumn === 'Y') {
|
||||||
|
openFixedColumnDialog(row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置字典Code的下拉选项
|
||||||
DictDataApi.getSimpleDictTypeList().then((dicData) => {
|
DictDataApi.getSimpleDictTypeList().then((dicData) => {
|
||||||
const dicObj = {}
|
const dicObj = {}
|
||||||
dicData = dicData.map(({ type, name }) => {
|
dicData = dicData.map(({ type, name }) => {
|
||||||
dicObj[type] = `${type}(${name})`
|
dicObj[type] = `${type}(${name})`
|
||||||
return { label: dicObj[type], value: type }
|
return { label: dicObj[type], value: type }
|
||||||
})
|
})
|
||||||
Object.assign(fieldColumn.dictCode.editRender, { dicData, dicObj })
|
Object.assign(tableInfoOption.infoColumn.fieldColumn.dictCode.editRender, { dicData, dicObj })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 为主字段列添加点击事件处理添加子字段按钮
|
||||||
|
tableInfoOption.infoColumn.fieldColumn.hasChildren.editRender.events = {
|
||||||
|
click: (row) => {
|
||||||
|
// 子字段不显示按钮,这个检查主要是保险
|
||||||
|
if (row.isSubField === true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前行的索引
|
||||||
|
const currentIndex = infoData.value.basics.findIndex(item => item._X_ROW_KEY === row._X_ROW_KEY)
|
||||||
|
if (currentIndex !== -1) {
|
||||||
|
addSubFieldRow(row, currentIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态控制包含子字段选项的禁用状态
|
||||||
|
tableInfoOption.infoColumn.fieldColumn.hasChildren.editRender.disabled = (row) => {
|
||||||
|
// 子字段不能包含子字段
|
||||||
|
return row.isSubField === true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
@@ -228,7 +659,8 @@ defineExpose({
|
|||||||
tableRefObj,
|
tableRefObj,
|
||||||
setTabsValue,
|
setTabsValue,
|
||||||
tableScrollIndex,
|
tableScrollIndex,
|
||||||
initEditInfoData
|
initEditInfoData,
|
||||||
|
parentFieldMap
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -238,6 +670,22 @@ defineExpose({
|
|||||||
left: 20px !important;
|
left: 20px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 为子字段的子字段列添加特殊样式
|
||||||
|
::v-deep(.field-vxe-table) {
|
||||||
|
.vxe-body--column {
|
||||||
|
&[field="hasChildren"] {
|
||||||
|
.vxe-cell {
|
||||||
|
// 为子字段添加视觉提示
|
||||||
|
.is-sub-field {
|
||||||
|
text-align: center;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
::v-deep(.virtual-hide-row) {
|
::v-deep(.virtual-hide-row) {
|
||||||
|
|||||||
@@ -149,8 +149,11 @@ const infoColumn = {
|
|||||||
fieldColumn: {
|
fieldColumn: {
|
||||||
fieldCode: { title: '字段编码', minWidth: 120, editRender: { name: 'LowInput', verifyEdit: true } },
|
fieldCode: { title: '字段编码', minWidth: 120, editRender: { name: 'LowInput', verifyEdit: true } },
|
||||||
fieldName: { title: '字段名称', minWidth: 120, editRender: { name: 'LowInput' } },
|
fieldName: { title: '字段名称', minWidth: 120, editRender: { name: 'LowInput' } },
|
||||||
|
parentFieldName: { title: '父字段名称', width: 120, editRender: { name: 'LowSelect', dicData: [], filterable: true, clearable: true } },
|
||||||
labelI18n: { title: '国际化配置', width: 140, editRender: { name: 'LowMonacoEditorInput', events: {} } },
|
labelI18n: { title: '国际化配置', width: 140, editRender: { name: 'LowMonacoEditorInput', events: {} } },
|
||||||
fieldType: { title: '字段类型', minWidth: 100, editRender: { name: 'LowSelect', verifyEdit: true, dicData: dicObj.fieldType, dicObj: getDicObj('fieldType') } },
|
fieldType: { title: '字段类型', minWidth: 100, editRender: { name: 'LowSelect', verifyEdit: true, dicData: dicObj.fieldType, dicObj: getDicObj('fieldType') } },
|
||||||
|
isFixedColumn: { title: '固定列', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
||||||
|
fixedColumnValue: { title: '固定列内容', width: 110, align: "center", editRender: { name: 'LowButton', disabled: (row) => row.isFixedColumn !== 'Y', buttonText: '配置内容', buttonType: 'primary', buttonSize: 'small', events: {} } },
|
||||||
queryIsDb: { title: '接口查询', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
queryIsDb: { title: '接口查询', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
||||||
queryIsWeb: { title: '查询控件', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
queryIsWeb: { title: '查询控件', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
||||||
queryMode: { title: '查询模式', width: 130, editRender: { name: 'LowSelect', verifyEdit: true, dicData: dicObj.queryMode, dicObj: getDicObj('queryMode') } },
|
queryMode: { title: '查询模式', width: 130, editRender: { name: 'LowSelect', verifyEdit: true, dicData: dicObj.queryMode, dicObj: getDicObj('queryMode') } },
|
||||||
@@ -160,6 +163,8 @@ const infoColumn = {
|
|||||||
isDimension: { title: '是否维度', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
isDimension: { title: '是否维度', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
||||||
|
|
||||||
isShowSort: { title: '是否排序', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
isShowSort: { title: '是否排序', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
||||||
|
isDynamicGroup: { title: '动态分组', width: 75, align: "center", editRender: { name: 'LowCheckbox' } },
|
||||||
|
hasChildren: { title: '子字段', width: 90, align: "center", editRender: { name: 'LowButton', disabled: (row) => row.isSubField === true, buttonText: '添加子字段', buttonType: 'primary', buttonSize: 'small' } },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +173,20 @@ const apiKey = { fieldColumn: 'fieldList' }
|
|||||||
for (const key in infoColumn) {
|
for (const key in infoColumn) {
|
||||||
if (apiKey[key]) {
|
if (apiKey[key]) {
|
||||||
const keys = Object.keys(infoColumn[key])
|
const keys = Object.keys(infoColumn[key])
|
||||||
if (key == 'fieldColumn') keys.push('sortNum')
|
if (key == 'fieldColumn') {
|
||||||
|
keys.push('sortNum')
|
||||||
|
// 确保父子关系字段被包含
|
||||||
|
if (!keys.includes('parentFieldCode')) {
|
||||||
|
keys.push('parentFieldCode')
|
||||||
|
}
|
||||||
|
if (!keys.includes('hasChildren')) {
|
||||||
|
keys.push('hasChildren')
|
||||||
|
}
|
||||||
|
// 确保固定列内容字段被包含
|
||||||
|
if (!keys.includes('fixedColumnValue')) {
|
||||||
|
keys.push('fixedColumnValue')
|
||||||
|
}
|
||||||
|
}
|
||||||
infoApiKey[apiKey[key]] = keys
|
infoApiKey[apiKey[key]] = keys
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,7 +194,7 @@ for (const key in infoColumn) {
|
|||||||
//默认值
|
//默认值
|
||||||
const infoDefaultData = {
|
const infoDefaultData = {
|
||||||
basics: {
|
basics: {
|
||||||
fieldCode: '', fieldName: '', labelI18n: '', fieldType: 'String', queryIsDb: 'N', queryIsWeb: 'N', queryMode: 'LIKE', dictCode: '', isExport: 'Y', isShowSort: 'N',isAmount:'',isDimension:''
|
fieldCode: '', fieldName: '', parentFieldName: '', labelI18n: '', fieldType: 'String', isFixedColumn: 'N', fixedColumnValue: '', queryIsDb: 'N', queryIsWeb: 'N', queryMode: 'LIKE', dictCode: '', isExport: 'Y', isShowSort: 'N', isAmount: '', isDimension: '', isDynamicGroup: 'N', hasChildren: 'N', isSubField: false, parentFieldId: '', parentFieldCode: '',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -330,6 +330,21 @@ const tableFormVerify = (type) => {
|
|||||||
filedData.splice(item.sortNum || 999, 0, item)
|
filedData.splice(item.sortNum || 999, 0, item)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 先进行hasChildren一致性检查
|
||||||
|
filedData.forEach(currentItem => {
|
||||||
|
if (currentItem.hasChildren === 'Y') {
|
||||||
|
// 检查是否存在子字段(parentFieldCode等于当前字段的fieldCode)
|
||||||
|
const hasChildFields = filedData.some(childItem =>
|
||||||
|
childItem.parentFieldCode === currentItem.fieldCode
|
||||||
|
)
|
||||||
|
|
||||||
|
// 如果没有子字段,则将hasChildren设为'N'
|
||||||
|
if (!hasChildFields) {
|
||||||
|
currentItem.hasChildren = 'N'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
for (const i in filedData) {
|
for (const i in filedData) {
|
||||||
const index = Number(i)
|
const index = Number(i)
|
||||||
const item = filedData[index]
|
const item = filedData[index]
|
||||||
@@ -337,12 +352,31 @@ const tableFormVerify = (type) => {
|
|||||||
|
|
||||||
let messageText = ''
|
let messageText = ''
|
||||||
let tabKey = 'mysql'
|
let tabKey = 'mysql'
|
||||||
if (!item.fieldCode || !item.fieldName) {
|
// 子字段不能再包含子字段
|
||||||
|
if (item.isSubField && item.hasChildren === 'Y') {
|
||||||
|
debugger
|
||||||
messageText = `<div style="line-height:24px">
|
messageText = `<div style="line-height:24px">
|
||||||
<div>${!item.fieldCode ? '字段编码' : '字段名称'}必须填写</div>
|
<div>子字段不能包含子字段</div>
|
||||||
<div>序号:${index + 1}</div>
|
<div>序号:${index + 1}</div>
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
// 当不包含子字段时,字段编码和字段名称必须填写
|
||||||
|
else if (item.hasChildren !== 'Y') {
|
||||||
|
if (!item.fieldCode || !item.fieldName) {
|
||||||
|
messageText = `<div style="line-height:24px">
|
||||||
|
<div>${!item.fieldCode ? '字段编码' : '字段名称'}必须填写</div>
|
||||||
|
<div>序号:${index + 1}</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 包含子字段时,字段名称必须填写
|
||||||
|
if (!item.fieldName) {
|
||||||
|
messageText = `<div style="line-height:24px">
|
||||||
|
<div>字段名称必须填写</div>
|
||||||
|
<div>序号:${index + 1}</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
}
|
||||||
if (fieldCodeArr.includes(item.fieldCode)) {
|
if (fieldCodeArr.includes(item.fieldCode)) {
|
||||||
messageText = `<div style="line-height:24px">
|
messageText = `<div style="line-height:24px">
|
||||||
<div>
|
<div>
|
||||||
@@ -353,15 +387,18 @@ const tableFormVerify = (type) => {
|
|||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
fieldCodeArr.push(item.fieldCode)
|
fieldCodeArr.push(item.fieldCode)
|
||||||
if (!/(^[a-zA-Z]{2}(_?[a-zA-Z0-9])*_?$)/.test(item.fieldCode)) {
|
// 当不包含子字段时才验证字段编码格式
|
||||||
messageText = `<div style="line-height:24px">
|
if (item.hasChildren !== 'Y' && item.fieldCode) {
|
||||||
<div>
|
if (!/(^[a-zA-Z]{2}(_?[a-zA-Z0-9])*_?$)/.test(item.fieldCode)) {
|
||||||
<span>字段编码不符合规范</span>
|
messageText = `<div style="line-height:24px">
|
||||||
<span style="color:red">${item.fieldCode}</span>
|
<div>
|
||||||
</div>
|
<span>字段编码不符合规范</span>
|
||||||
<div>命名规则:只能由字母、数字、下划线组成;必须以字母开头;不能以单个字母加下滑线开头</div>
|
<span style="color:red">${item.fieldCode}</span>
|
||||||
<div>序号:${index + 1}</div>
|
</div>
|
||||||
</div>`
|
<div>命名规则:只能由字母、数字、下划线组成;必须以字母开头;不能以单个字母加下滑线开头</div>
|
||||||
|
<div>序号:${index + 1}</div>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageText) {
|
if (messageText) {
|
||||||
@@ -379,6 +416,20 @@ const tableFormVerify = (type) => {
|
|||||||
})
|
})
|
||||||
if (key == 'fieldList') {
|
if (key == 'fieldList') {
|
||||||
itemObj.labelI18n = formattingLengStr(itemObj.labelI18n, itemObj.fieldName)
|
itemObj.labelI18n = formattingLengStr(itemObj.labelI18n, itemObj.fieldName)
|
||||||
|
// 为子字段添加父字段编码信息
|
||||||
|
if (item.isSubField && item.parentFieldId) {
|
||||||
|
// 查找父字段的编码
|
||||||
|
const parentField = filedData.find(field => field._X_ROW_KEY === item.parentFieldId)
|
||||||
|
if (parentField && parentField.fieldCode) {
|
||||||
|
itemObj.parentFieldCode = parentField.fieldCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 为父字段添加是否包含子字段的标识
|
||||||
|
if (item.hasChildren === 'Y') {
|
||||||
|
itemObj.hasChildren = 'Y'
|
||||||
|
} else {
|
||||||
|
itemObj.hasChildren = 'N'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (type == 'edit' && item[`${key}_id`]) itemObj['id'] = item[`${key}_id`]
|
if (type == 'edit' && item[`${key}_id`]) itemObj['id'] = item[`${key}_id`]
|
||||||
infoData[key].push(itemObj)
|
infoData[key].push(itemObj)
|
||||||
|
|||||||
@@ -46,7 +46,22 @@
|
|||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
<vxe-column v-for="(item, key) in column" :key="key" :field="key" v-bind="item"></vxe-column>
|
<vxe-column v-for="(item, key) in column" :key="key" :field="key" v-bind="item">
|
||||||
|
<template #default="{ row }" v-if="key === 'hasChildren'">
|
||||||
|
<div :class="{ 'is-sub-field': row.isSubField }">
|
||||||
|
<el-button
|
||||||
|
v-if="!row.isSubField"
|
||||||
|
:type="item.editRender?.buttonType || 'primary'"
|
||||||
|
:size="item.editRender?.buttonSize || 'small'"
|
||||||
|
:disabled="item.editRender?.disabled ? item.editRender.disabled(row) : false"
|
||||||
|
@click.stop="handleButtonClick(item, row)"
|
||||||
|
>
|
||||||
|
{{ item.editRender?.buttonText || '添加子字段' }}
|
||||||
|
</el-button>
|
||||||
|
<span v-else>-</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
</vxe-table>
|
</vxe-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -65,6 +80,33 @@ const emit = defineEmits(['selection-change', 'cell-click', 'dropdown-command'])
|
|||||||
|
|
||||||
const vxeTableRef = ref()
|
const vxeTableRef = ref()
|
||||||
|
|
||||||
|
// 处理按钮点击事件
|
||||||
|
const handleButtonClick = (item, row) => {
|
||||||
|
// 检查editRender是否存在
|
||||||
|
if (!item.editRender) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查events是否存在
|
||||||
|
if (!item.editRender.events) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查click事件是否存在
|
||||||
|
if (!item.editRender.events.click) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行自定义点击事件
|
||||||
|
item.editRender.events.click(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试点击方法
|
||||||
|
const testClick = (row) => {
|
||||||
|
console.log('测试按钮被点击:', row)
|
||||||
|
alert('测试按钮工作正常!')
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({ vxeTableRef })
|
defineExpose({ vxeTableRef })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user