|
|
|
@ -262,9 +262,55 @@ |
|
|
|
</el-alert> |
|
|
|
</el-alert> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 人工查重:复用现有姓名、身份证、电话精确 OR 查询 --> |
|
|
|
|
|
|
|
<div class="manual-search-panel"> |
|
|
|
|
|
|
|
<div class="manual-search-header"> |
|
|
|
|
|
|
|
<div> |
|
|
|
|
|
|
|
<div class="manual-search-title">没有找到要合并的记录?</div> |
|
|
|
|
|
|
|
<div class="manual-search-description"> |
|
|
|
|
|
|
|
可输入已登记来件人的完整姓名、完整身份证号或完整联系电话继续查找 |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
<el-tag type="info" effect="plain">精确匹配</el-tag> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="manual-search-bar"> |
|
|
|
|
|
|
|
<el-input |
|
|
|
|
|
|
|
v-model="manualSearchKeyword" |
|
|
|
|
|
|
|
placeholder="例如:张三、完整身份证号或完整联系电话" |
|
|
|
|
|
|
|
clearable |
|
|
|
|
|
|
|
:disabled="duplicateLoading" |
|
|
|
|
|
|
|
@keyup.enter="handleManualSearch" |
|
|
|
|
|
|
|
@clear="handleClearManualSearch" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<template #prepend>查找历史来件</template> |
|
|
|
|
|
|
|
</el-input> |
|
|
|
|
|
|
|
<el-button type="primary" :loading="duplicateLoading" @click="handleManualSearch"> |
|
|
|
|
|
|
|
查找可合并记录 |
|
|
|
|
|
|
|
</el-button> |
|
|
|
|
|
|
|
<el-button v-if="isManualSearch" :disabled="duplicateLoading" @click="handleClearManualSearch"> |
|
|
|
|
|
|
|
恢复自动匹配结果 |
|
|
|
|
|
|
|
</el-button> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="duplicate-result-header"> |
|
|
|
|
|
|
|
<span>{{ isManualSearch ? '人工查找结果' : '系统自动匹配结果' }}</span> |
|
|
|
|
|
|
|
<span v-if="isManualSearch" class="search-keyword">查询条件:{{ activeManualSearchKeyword }}</span> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 重复记录列表 --> |
|
|
|
<!-- 重复记录列表 --> |
|
|
|
<div class="duplicate-list" v-loading="duplicateLoading"> |
|
|
|
<div class="duplicate-list" v-loading="duplicateLoading"> |
|
|
|
<el-empty v-if="duplicateList.length === 0 && !duplicateLoading" description="未发现重复记录,您可以继续添加" /> |
|
|
|
<el-result |
|
|
|
|
|
|
|
v-if="duplicateLoadFailed && duplicateList.length === 0 && !duplicateLoading" |
|
|
|
|
|
|
|
icon="error" |
|
|
|
|
|
|
|
title="查询失败" |
|
|
|
|
|
|
|
sub-title="请重试查重" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
<el-empty |
|
|
|
|
|
|
|
v-else-if="duplicateList.length === 0 && !duplicateLoading" |
|
|
|
|
|
|
|
:description="isManualSearch ? '未搜索到匹配记录' : '未发现重复记录,您可以继续添加'" |
|
|
|
|
|
|
|
/> |
|
|
|
<el-result v-else-if="duplicateList.length > 0 && !selectedCardId" icon="warning" title="发现疑似重复记录"> |
|
|
|
<el-result v-else-if="duplicateList.length > 0 && !selectedCardId" icon="warning" title="发现疑似重复记录"> |
|
|
|
<template #sub-title> |
|
|
|
<template #sub-title> |
|
|
|
<p style="color: #909399;">请从下方列表选择一条记录进行合并,或选择"不合并,继续添加"</p> |
|
|
|
<p style="color: #909399;">请从下方列表选择一条记录进行合并,或选择"不合并,继续添加"</p> |
|
|
|
@ -854,6 +900,13 @@ const handleNextStep = async () => { |
|
|
|
feedback.msgWarning("请完善必填信息") |
|
|
|
feedback.msgWarning("请完善必填信息") |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
manualSearchKeyword.value = '' |
|
|
|
|
|
|
|
activeManualSearchKeyword.value = '' |
|
|
|
|
|
|
|
isManualSearch.value = false |
|
|
|
|
|
|
|
selectedCardId.value = null |
|
|
|
|
|
|
|
selectedCard.value = null |
|
|
|
|
|
|
|
duplicateList.value = [] |
|
|
|
|
|
|
|
duplicateLoadFailed.value = false |
|
|
|
currentStep.value = 1 |
|
|
|
currentStep.value = 1 |
|
|
|
await fetchDuplicateList() |
|
|
|
await fetchDuplicateList() |
|
|
|
} |
|
|
|
} |
|
|
|
@ -904,23 +957,71 @@ const handleConfirmMerge = async () => { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 获取查重列表 |
|
|
|
// 获取查重列表 |
|
|
|
const fetchDuplicateList = async () => { |
|
|
|
const fetchDuplicateList = async (query) => { |
|
|
|
duplicateLoading.value = true |
|
|
|
duplicateLoading.value = true |
|
|
|
|
|
|
|
duplicateLoadFailed.value = false |
|
|
|
try { |
|
|
|
try { |
|
|
|
const body = { |
|
|
|
const body = query || { |
|
|
|
responderIdCode: formData.value.responderIdCode, |
|
|
|
responderIdCode: formData.value.responderIdCode, |
|
|
|
responderName: formData.value.responderName, |
|
|
|
responderName: formData.value.responderName, |
|
|
|
responderPhone: formData.value.responderPhone, |
|
|
|
responderPhone: formData.value.responderPhone, |
|
|
|
} |
|
|
|
} |
|
|
|
const res = await maileRepeatt(body) |
|
|
|
const res = await maileRepeatt(body) |
|
|
|
duplicateList.value = res?.complaintCollectionRepeatDTOS || [] |
|
|
|
duplicateList.value = res?.complaintCollectionRepeatDTOS || [] |
|
|
|
|
|
|
|
return true |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
console.error("查重失败", e) |
|
|
|
console.error("查重失败", e) |
|
|
|
|
|
|
|
duplicateLoadFailed.value = true |
|
|
|
|
|
|
|
feedback.notifyError("查询失败,请重试") |
|
|
|
|
|
|
|
return false |
|
|
|
} finally { |
|
|
|
} finally { |
|
|
|
duplicateLoading.value = false |
|
|
|
duplicateLoading.value = false |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 人工搜索使用同一个关键词精确匹配姓名、身份证或电话 |
|
|
|
|
|
|
|
const handleManualSearch = async () => { |
|
|
|
|
|
|
|
if (duplicateLoading.value) return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const keyword = manualSearchKeyword.value.trim() |
|
|
|
|
|
|
|
if (!keyword) { |
|
|
|
|
|
|
|
feedback.msgWarning("请输入完整姓名、身份证号或联系电话") |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
manualSearchKeyword.value = keyword |
|
|
|
|
|
|
|
selectedCardId.value = null |
|
|
|
|
|
|
|
selectedCard.value = null |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const success = await fetchDuplicateList({ |
|
|
|
|
|
|
|
responderIdCode: keyword, |
|
|
|
|
|
|
|
responderName: keyword, |
|
|
|
|
|
|
|
responderPhone: keyword, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
if (success) { |
|
|
|
|
|
|
|
activeManualSearchKeyword.value = keyword |
|
|
|
|
|
|
|
isManualSearch.value = true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 清空人工搜索并恢复当前来件人的自动查重结果 |
|
|
|
|
|
|
|
const handleClearManualSearch = async () => { |
|
|
|
|
|
|
|
if (duplicateLoading.value || (!manualSearchKeyword.value && !isManualSearch.value)) return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const previousKeyword = activeManualSearchKeyword.value |
|
|
|
|
|
|
|
manualSearchKeyword.value = '' |
|
|
|
|
|
|
|
selectedCardId.value = null |
|
|
|
|
|
|
|
selectedCard.value = null |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const success = await fetchDuplicateList() |
|
|
|
|
|
|
|
if (success) { |
|
|
|
|
|
|
|
activeManualSearchKeyword.value = '' |
|
|
|
|
|
|
|
isManualSearch.value = false |
|
|
|
|
|
|
|
} else if (isManualSearch.value) { |
|
|
|
|
|
|
|
manualSearchKeyword.value = previousKeyword |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 选择卡片 |
|
|
|
// 选择卡片 |
|
|
|
const handleSelectCard = (item) => { |
|
|
|
const handleSelectCard = (item) => { |
|
|
|
const id = item.complaintId || item.negativeId |
|
|
|
const id = item.complaintId || item.negativeId |
|
|
|
@ -983,6 +1084,10 @@ watch( |
|
|
|
|
|
|
|
|
|
|
|
duplicateDrawerVisible.value = false |
|
|
|
duplicateDrawerVisible.value = false |
|
|
|
duplicateLoading.value = false |
|
|
|
duplicateLoading.value = false |
|
|
|
|
|
|
|
duplicateLoadFailed.value = false |
|
|
|
|
|
|
|
manualSearchKeyword.value = '' |
|
|
|
|
|
|
|
activeManualSearchKeyword.value = '' |
|
|
|
|
|
|
|
isManualSearch.value = false |
|
|
|
autoDuplicateLoading.value = false |
|
|
|
autoDuplicateLoading.value = false |
|
|
|
duplicateHintVisible.value = false |
|
|
|
duplicateHintVisible.value = false |
|
|
|
duplicateCount.value = 0 |
|
|
|
duplicateCount.value = 0 |
|
|
|
@ -1180,6 +1285,10 @@ async function onSubmit() { |
|
|
|
const duplicateDrawerVisible = ref(false) |
|
|
|
const duplicateDrawerVisible = ref(false) |
|
|
|
const duplicateList = ref([]) |
|
|
|
const duplicateList = ref([]) |
|
|
|
const duplicateLoading = ref(false) |
|
|
|
const duplicateLoading = ref(false) |
|
|
|
|
|
|
|
const duplicateLoadFailed = ref(false) |
|
|
|
|
|
|
|
const manualSearchKeyword = ref('') |
|
|
|
|
|
|
|
const activeManualSearchKeyword = ref('') |
|
|
|
|
|
|
|
const isManualSearch = ref(false) |
|
|
|
|
|
|
|
|
|
|
|
const onCheckDuplicate = async () => { |
|
|
|
const onCheckDuplicate = async () => { |
|
|
|
duplicateDrawerVisible.value = true |
|
|
|
duplicateDrawerVisible.value = true |
|
|
|
@ -1366,6 +1475,65 @@ h2 { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.manual-search-panel { |
|
|
|
|
|
|
|
margin: 0 20px 18px; |
|
|
|
|
|
|
|
padding: 16px; |
|
|
|
|
|
|
|
border: 1px solid #d9ecff; |
|
|
|
|
|
|
|
border-radius: 8px; |
|
|
|
|
|
|
|
background: #f5faff; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.manual-search-header { |
|
|
|
|
|
|
|
display: flex; |
|
|
|
|
|
|
|
align-items: center; |
|
|
|
|
|
|
|
justify-content: space-between; |
|
|
|
|
|
|
|
gap: 16px; |
|
|
|
|
|
|
|
margin-bottom: 12px; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.manual-search-title { |
|
|
|
|
|
|
|
color: #303133; |
|
|
|
|
|
|
|
font-size: 15px; |
|
|
|
|
|
|
|
font-weight: 600; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.manual-search-description { |
|
|
|
|
|
|
|
margin-top: 4px; |
|
|
|
|
|
|
|
color: #606266; |
|
|
|
|
|
|
|
font-size: 13px; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.manual-search-bar { |
|
|
|
|
|
|
|
display: flex; |
|
|
|
|
|
|
|
flex-wrap: wrap; |
|
|
|
|
|
|
|
gap: 10px; |
|
|
|
|
|
|
|
align-items: center; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.el-input { |
|
|
|
|
|
|
|
flex: 1; |
|
|
|
|
|
|
|
min-width: 320px; |
|
|
|
|
|
|
|
max-width: 520px; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.duplicate-result-header { |
|
|
|
|
|
|
|
display: flex; |
|
|
|
|
|
|
|
align-items: center; |
|
|
|
|
|
|
|
justify-content: space-between; |
|
|
|
|
|
|
|
margin: 0 20px 12px; |
|
|
|
|
|
|
|
padding-bottom: 8px; |
|
|
|
|
|
|
|
border-bottom: 1px solid #ebeef5; |
|
|
|
|
|
|
|
color: #303133; |
|
|
|
|
|
|
|
font-size: 15px; |
|
|
|
|
|
|
|
font-weight: 600; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.search-keyword { |
|
|
|
|
|
|
|
color: #409eff; |
|
|
|
|
|
|
|
font-size: 13px; |
|
|
|
|
|
|
|
font-weight: 400; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.duplicate-list { |
|
|
|
.duplicate-list { |
|
|
|
min-height: 200px; |
|
|
|
min-height: 200px; |
|
|
|
} |
|
|
|
} |
|
|
|
|