fix: 人员数据治理迁移4

This commit is contained in:
2026-11-09 17:39:59 +08:00
parent bd7857a5c8
commit 0da369366a
2 changed files with 87 additions and 4 deletions
@@ -509,8 +509,8 @@
} }
.person-governance-task-cron { .person-governance-task-cron {
flex: 0 1 420px; flex: 0 1 340px;
max-width: 420px; max-width: 340px;
} }
.person-governance-cron-hint, .person-governance-cron-hint,
@@ -579,7 +579,11 @@
} }
/* 两种数据来源共用右侧清空入口,窄屏换行后仍靠右,不挤压周期控件。 */ /* 两种数据来源共用右侧清空入口,窄屏换行后仍靠右,不挤压周期控件。 */
.person-governance-mapping-toolbar > .person-governance-clear-mappings { .person-governance-mapping-toolbar > .person-governance-mapping-actions {
display: flex;
align-items: center;
flex-wrap: nowrap;
white-space: nowrap;
flex: none; flex: none;
margin-left: auto; margin-left: auto;
} }
@@ -133,11 +133,14 @@
<el-form-item label="是否匹配会员规则" class="person-governance-system-member-match"> <el-form-item label="是否匹配会员规则" class="person-governance-system-member-match">
<el-switch v-model="form.matchMemberRules" :disabled="formLoading"></el-switch> <el-switch v-model="form.matchMemberRules" :disabled="formLoading"></el-switch>
</el-form-item> </el-form-item>
<div class="person-governance-mapping-actions">
<el-button <el-button
class="person-governance-clear-mappings" class="person-governance-clear-mappings"
:disabled="!mappings.length||formLoading||mappingsClearConfirming" :disabled="!mappings.length||formLoading||mappingsClearConfirming"
@click="clearMappings" @click="clearMappings"
>清空</el-button> >清空</el-button>
<el-button :disabled="!form.targetTable||!targetColumns.length||formLoading" @click="openQuickMapping">快捷映射</el-button>
</div>
</el-form> </el-form>
<div v-else class="person-governance-mapping-toolbar"> <div v-else class="person-governance-mapping-toolbar">
<div class="person-governance-mapping-toolbar-item person-governance-mapping-table-select"> <div class="person-governance-mapping-toolbar-item person-governance-mapping-table-select">
@@ -158,7 +161,7 @@
</el-select> </el-select>
</div> </div>
<div class="person-governance-mapping-toolbar-item"> <div class="person-governance-mapping-toolbar-item">
<el-select v-model="form.syncMode" clearable filterable placeholder="请选择同步类型" style="width: 220px"> <el-select v-model="form.syncMode" clearable filterable placeholder="请选择同步类型" style="width: 200px">
<el-option label="全量同步" value="APPEND"></el-option> <el-option label="全量同步" value="APPEND"></el-option>
<el-option label="全量同步(存在即修改)" value="UPSERT"></el-option> <el-option label="全量同步(存在即修改)" value="UPSERT"></el-option>
<el-option label="同步新数据" value="INSERT_NEW"></el-option> <el-option label="同步新数据" value="INSERT_NEW"></el-option>
@@ -178,11 +181,14 @@
<label>是否匹配会员规则</label> <label>是否匹配会员规则</label>
<el-switch v-model="form.matchMemberRules" :disabled="formLoading"></el-switch> <el-switch v-model="form.matchMemberRules" :disabled="formLoading"></el-switch>
</div> </div>
<div class="person-governance-mapping-actions">
<el-button <el-button
class="person-governance-clear-mappings" class="person-governance-clear-mappings"
:disabled="!mappings.length||formLoading||mappingsClearConfirming" :disabled="!mappings.length||formLoading||mappingsClearConfirming"
@click="clearMappings" @click="clearMappings"
>清空</el-button> >清空</el-button>
<el-button :disabled="!form.targetTable||!targetColumns.length||formLoading" @click="openQuickMapping">快捷映射</el-button>
</div>
</div> </div>
<div class="person-governance-mapping-table-wrap"> <div class="person-governance-mapping-table-wrap">
<el-table <el-table
@@ -412,6 +418,16 @@
@click="save" @click="save"
>保存配置</el-button> >保存配置</el-button>
</div> </div>
<el-dialog title="快捷映射" :visible.sync="quickMappingVisible" append-to-body
width="720px" :close-on-click-modal="false" custom-class="person-governance-dialog">
<el-alert title="输入 JSON 数组,以系统字段名为键。仅更新填写的字段,确认后回填,保存配置后生效。"
type="info" :closable="false"></el-alert>
<el-input v-model="quickMappingText" type="textarea" :rows="12" :placeholder="quickMappingExample"></el-input>
<div slot="footer">
<el-button @click="quickMappingVisible=false">取消</el-button>
<el-button type="primary" :disabled="formLoading" @click="applyQuickMapping">确认填充</el-button>
</div>
</el-dialog>
<el-dialog <el-dialog
title="选择同步周期" title="选择同步周期"
:visible="cronDialogVisible" :visible="cronDialogVisible"
@@ -469,6 +485,9 @@
testCases: [], testCases: [],
identityRow: null, identityRow: null,
mappingsClearConfirming: false, mappingsClearConfirming: false,
quickMappingVisible: false,
quickMappingText: '',
quickMappingExample: '[{"loginname":{"id":"gh","sourceComment":"工号"}},\n {"username":{"id":"xm","sourceComment":"姓名"}}]',
testResults: { TOKEN: '', DATA: '' }, testResults: { TOKEN: '', DATA: '' },
responseWarnings: { TOKEN: '', DATA: '' }, responseWarnings: { TOKEN: '', DATA: '' },
queryLoading: { TOKEN: false, DATA: false }, queryLoading: { TOKEN: false, DATA: false },
@@ -577,6 +596,66 @@
}, },
}, },
methods: { methods: {
openQuickMapping() {
this.$set(this, 'quickMappingText', '')
this.$set(this, 'quickMappingVisible', true)
},
applyQuickMapping() {
if (this.formLoading) return
let updates
try {
const entries = JSON.parse(this.quickMappingText)
if (!Array.isArray(entries) || !entries.length) throw new Error('请输入非空 JSON 数组')
const seen = new Set()
updates = []
entries.forEach((entry) => {
if (!entry || typeof entry !== 'object' || Array.isArray(entry) || !Object.keys(entry).length) {
throw new Error('数组中的每项必须是以系统字段名为键的对象')
}
Object.keys(entry).forEach((targetField) => {
const column = this.targetColumns.find((item) => item.columnName === targetField)
if (!column) throw new Error('目标表不存在系统字段:' + targetField)
if (seen.has(targetField)) throw new Error('系统字段重复:' + targetField)
seen.add(targetField)
const value = entry[targetField]
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw new Error(targetField + ' 的映射必须为对象')
}
const sourceField = value.sourceField === undefined ? value.id : value.sourceField
const sourceComment = value.sourceComment === undefined ? value['来源字段说明'] : value.sourceComment
if (typeof sourceField !== 'string' || !sourceField.trim()) {
throw new Error(targetField + ' 缺少来源字段 id 或 sourceField')
}
if (sourceComment !== undefined && typeof sourceComment !== 'string') {
throw new Error(targetField + ' 的来源字段说明必须为字符串')
}
const source = this.sourceColumns.find((item) => item.columnName === sourceField.trim())
if (this.form.sourceType === 'SYSTEM_TABLE' && !source) {
throw new Error('来源表不存在字段:' + sourceField)
}
updates.push({ column, sourceField: sourceField.trim(), sourceComment,
defaultComment: source ? source.columnComment || '' : '' })
})
})
} catch (error) {
this.notifyWarning(error instanceof SyntaxError ? 'JSON 格式不正确,请使用双引号并参考示例填写' : error.message)
return
}
updates.forEach((update) => {
let row = this.mappings.find((item) => item.targetField === update.column.columnName)
if (!row) {
row = { sourceField: '', sourceComment: '', targetField: update.column.columnName,
targetComment: update.column.columnComment || '', required: update.column.isNullable === 'NO', identityFlag: false }
this.mappings.push(row)
}
this.$set(row, 'sourceField', update.sourceField)
this.$set(row, 'sourceComment', update.sourceComment === undefined
? row.sourceComment || update.defaultComment : update.sourceComment)
})
this.$set(this, 'quickMappingVisible', false)
this.layoutTable('mappingTable')
this.notifySuccess('已填充 ' + updates.length + ' 条字段映射')
},
isIdentityMapping(row) { isIdentityMapping(row) {
return Boolean(row && row.sourceField && row.sourceField.trim() return Boolean(row && row.sourceField && row.sourceField.trim()
&& row.targetField && row.targetField.trim() && row.targetField && row.targetField.trim()