6 changed files with 624 additions and 21 deletions
@ -0,0 +1,589 @@
|
||||
<template> |
||||
<div class="container"> |
||||
<header> |
||||
<el-form :label-width="114"> |
||||
<el-row> |
||||
<el-col :span="6"> |
||||
<el-form-item label="问题来源"> |
||||
<el-select |
||||
v-model="query.sourceTableSubOneList" |
||||
clearable |
||||
filterable |
||||
multiple |
||||
collapse-tags |
||||
placeholder="请选择来源" |
||||
style="width: 100%" |
||||
> |
||||
<el-option |
||||
v-for="item in dict.sourceTableSubOneList" |
||||
:key="item.value" |
||||
:value="item.value" |
||||
:label="item.label" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="信件编号"> |
||||
<el-input |
||||
placeholder="请输入编号" |
||||
v-model="query.originId" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="登记/受理时间"> |
||||
<date-time-range-picker-ext |
||||
v-model="query.discoveryTimeList" |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="来件人"> |
||||
<el-input |
||||
placeholder="来件人姓名、身份证号码、联系电话" |
||||
v-model="query.personInfo" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row> |
||||
<el-col :span="6"> |
||||
<el-form-item label="涉及二级机构" prop="secondDepartName"> |
||||
<depart-tree-select |
||||
v-model="query.secondDepartId" |
||||
:check-strictly="true" |
||||
@node-click="(row) => (query.secondDepartName = row.shortName)" |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="涉及三级机构" prop="thirdDepartId"> |
||||
<depart-tree-select |
||||
v-model="query.thirdDepartId" |
||||
:check-strictly="true" |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="办理方式"> |
||||
<el-select |
||||
v-model="query.handleMethod" |
||||
placeholder="全部" |
||||
clearable |
||||
> |
||||
<el-option value="0" label="自办"/> |
||||
<el-option value="1" label="下发"/> |
||||
</el-select> |
||||
|
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="办理状态"> |
||||
<el-select |
||||
v-model="query.processingStatus" |
||||
clearable |
||||
multiple |
||||
collapse-tags |
||||
placeholder="办理状态" |
||||
> |
||||
<el-option |
||||
v-for="item in dict.processingStatus" |
||||
:key="item.id" |
||||
:label="item.dictLabel" |
||||
:value="item.dictValue" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
<el-row> |
||||
<el-col :span="6"> |
||||
<el-form-item label="来件内容"> |
||||
<el-input |
||||
placeholder="请输入来件内容" |
||||
v-model="query.thingDesc" |
||||
clearable |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="是否重复件"> |
||||
<el-select |
||||
v-model="query.repeatt" |
||||
placeholder="全部" |
||||
clearable |
||||
> |
||||
<el-option value="0" label="否"/> |
||||
<el-option value="1" label="是"/> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="核查结论" > |
||||
<el-select v-model="query.checkStatusList" clearable multiple |
||||
style="width: 280px"> |
||||
<el-option v-for="item in dict.checkStatus" :value="item.dictValue" :label="item.dictLabel"></el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="初核材料"> |
||||
<el-select |
||||
v-model="query.initialReviewFileList" |
||||
placeholder="全部" |
||||
clearable |
||||
multiple |
||||
> |
||||
<el-option value="0" label="未上传"/> |
||||
<el-option value="1" label="已上传"/> |
||||
<el-option value="2" label="超时上传"/> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="涉嫌问题" prop="involveProblemIdList"> |
||||
<el-select |
||||
v-model="query.involveProblemIdList" |
||||
multiple |
||||
clearable |
||||
collapse-tags |
||||
style="width: 100%" |
||||
placeholder="请选择涉嫌问题" |
||||
> |
||||
<el-option |
||||
v-for="item in dict.suspectProblem" |
||||
:key="item.dictValue" |
||||
:value="item.dictValue" |
||||
:label="item.dictLabel" |
||||
> |
||||
<el-checkbox :model-value="(query.involveProblemIdList || []).includes(item.dictValue)"> |
||||
{{ item.dictLabel }} |
||||
</el-checkbox> |
||||
</el-option> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="标签"> |
||||
<el-select |
||||
placeholder="全部" |
||||
clearable |
||||
v-model="query.tags" |
||||
multiple |
||||
collapse-tags |
||||
> |
||||
<el-option |
||||
v-for="item in dict.sfssTags" |
||||
:key="item.id" |
||||
:value="item.dictValue" |
||||
:label="item.dictLabel" |
||||
/> |
||||
</el-select> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="录入时间"> |
||||
<date-time-range-picker-ext |
||||
v-model="query.createTimeList" |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
<el-col :span="6"> |
||||
<el-form-item label="办理单位" prop="handleDepartId"> |
||||
<depart-tree-select |
||||
v-model="query.handleDepartId" |
||||
placeholder="办理单位" |
||||
/> |
||||
</el-form-item> |
||||
</el-col> |
||||
</el-row> |
||||
</el-form> |
||||
<div class="mb-25 flex between"> |
||||
<div> |
||||
<el-button type="primary" @click="handleExport">数据导出</el-button> |
||||
</div> |
||||
<div> |
||||
<el-button type="primary" @click="getList"> |
||||
<template #icon> |
||||
<icon name="el-icon-Search"/> |
||||
</template> |
||||
查询 |
||||
</el-button> |
||||
<el-button @click="reset">重置</el-button> |
||||
</div> |
||||
</div> |
||||
</header> |
||||
<div class="table-container" v-loading="loading"> |
||||
<el-table :data="list"> |
||||
<el-table-column label="信件编号" width="130" prop="originId" show-overflow-tooltip/> |
||||
<el-table-column label="来源" width="100" show-overflow-tooltip> |
||||
<template #default="{ row }"> |
||||
{{ row.sourceTablePath }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column |
||||
label="登记/受理时间" |
||||
width="170" |
||||
prop="discoveryTime" |
||||
:formatter="(_, __, v) => v ? timeFormat(v, 'yyyy-mm-dd hh:MM:ss') : '/'" |
||||
show-overflow-tooltip |
||||
/> |
||||
<el-table-column label="来件人姓名" width="100" prop="responderName" |
||||
:formatter="row => row.responderName ? row.responderName : '匿名'"/> |
||||
<el-table-column label="身份证号" width="100" prop="responderIdCode" |
||||
:formatter="row => row.responderIdCode ? row.responderIdCode : '无'" show-overflow-tooltip/> |
||||
<el-table-column label="联系电话" width="100" prop="responderPhone" |
||||
:formatter="row => row.responderPhone ? row.responderPhone : '无'" show-overflow-tooltip/> |
||||
<el-table-column label="被投诉机构" width="130" show-overflow-tooltip> |
||||
<template #default="{ row }"> |
||||
<span>{{ row.secondDepartName }}</span> |
||||
<span v-if="row.thirdDepartName"> {{ row.thirdDepartName }}</span> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="办理单位" width="160" show-overflow-tooltip> |
||||
<template #default="{ row }"> |
||||
{{ row.handleSecondDepartName || '' }}{{ row.handleThreeDepartName ? '/' + row.handleThreeDepartName : '' }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="来信内容" width="100" prop="thingDesc" show-overflow-tooltip/> |
||||
<el-table-column label="涉嫌问题" width="100" prop="involveProblemStr" show-overflow-tooltip/> |
||||
<el-table-column label="是否重复件" width="100"> |
||||
<template #default="{ row }"> |
||||
{{ getDictLabel(dict.yesNo, row.repeatt) }} |
||||
</template> |
||||
</el-table-column> |
||||
|
||||
<el-table-column label="初核限时" width="150" align="center"> |
||||
<template #default="{ row }"> |
||||
<el-tag v-if="row.gwf3>=1" :type="row.gwf3 === '2' ? 'danger' : 'success'"> |
||||
{{ row.gwf3 === '2' ? '超时完成初核' : '按时完成初核' }} |
||||
</el-tag> |
||||
<countdown v-else :time="Number(row.remainingDuration || 0)"/> |
||||
</template> |
||||
</el-table-column> |
||||
|
||||
<el-table-column |
||||
label="录入时间" |
||||
width="170" |
||||
prop="createTime" |
||||
:formatter="(_, __, v) => v ? timeFormat(v, 'yyyy-mm-dd hh:MM:ss') : '/'" |
||||
show-overflow-tooltip |
||||
/> |
||||
<el-table-column label="标签" width="100" show-overflow-tooltip> |
||||
<template #default="{ row }"> |
||||
{{ getDictLabel(dict.sfssTags, row.tag) }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="办结情况" width="100" prop="completionStatus"> |
||||
<template #default="{ row }"> |
||||
{{ |
||||
row.completionStatus === '1' ? '程序办结' : |
||||
row.completionStatus === '2' ? '已解决合理诉求' : |
||||
'/' |
||||
}} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="群众认可" width="100" prop="publicRecognition"> |
||||
<template #default="{ row }"> |
||||
{{ |
||||
row.publicRecognition === '1' ? '认可' : |
||||
row.publicRecognition === '2' ? '不认可' : |
||||
row.publicRecognition === '3' ? '不接电话' : |
||||
'/' |
||||
}} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="办理方式" width="100"> |
||||
<template #default="{ row }"> |
||||
{{ getDictLabel(dict.handleMethodType, row.handleMethod) }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="业务类别" width="100" prop="businessTypeName"/> |
||||
<el-table-column label="核查结论" width="140" prop="checkStatus" show-overflow-tooltip> |
||||
<template #default="{ row }"> |
||||
{{ getDictLabel(dict.checkStatus, row.checkStatusCode) }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="办理状态" prop="processingStatus" width="100"> |
||||
<template #default="{ row }"> |
||||
<el-tag |
||||
:type="row.processingStatus === 'completed' ? 'success' : 'primary'" |
||||
v-if="row.processingStatus" |
||||
> |
||||
{{ getDictLabel(dict.processingStatus, row.processingStatus) }} |
||||
</el-tag> |
||||
<span v-else>-</span> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column label="操作" width="120" fixed="right"> |
||||
<template #default="{ row }"> |
||||
<el-button type="primary" link @click="handleActionDetail(row)">办理详情</el-button> |
||||
</template> |
||||
</el-table-column> |
||||
</el-table> |
||||
</div> |
||||
<div class="flex end mt-8"> |
||||
<el-pagination |
||||
@size-change="getList" |
||||
@current-change="getList" |
||||
:page-sizes="[10, 20, 50]" |
||||
v-model:page-size="query.size" |
||||
v-model:current-page="query.current" |
||||
layout="total, sizes, prev, pager, next" |
||||
:total="total" |
||||
> |
||||
</el-pagination> |
||||
</div> |
||||
</div> |
||||
|
||||
<negative-dialog |
||||
v-model="show" |
||||
:id="activeNegativeId" |
||||
@close="show = false" |
||||
ref="negativeDialogRef" |
||||
/> |
||||
|
||||
<negative-mailbox-dialog |
||||
v-model="mailboxShow" |
||||
:id="activeNegativeId" |
||||
@close="mailboxShow = false" |
||||
/> |
||||
|
||||
</template> |
||||
|
||||
|
||||
<script setup> |
||||
import { ref, computed, onMounted, watch } from 'vue'; |
||||
import { useRoute } from 'vue-router'; |
||||
import { timeFormat } from "@/utils/util"; |
||||
import useCatchStore from "@/stores/modules/catch"; |
||||
import { exportData, getComplaintCollectionPage } from "@/api/data/complaintCollection.ts"; |
||||
|
||||
const route = useRoute(); |
||||
const catchStore = useCatchStore(); |
||||
const show = ref(false); |
||||
const mailboxShow = ref(false); |
||||
const activeNegativeId = ref(""); |
||||
const isReady = ref(false); |
||||
|
||||
// 从URL参数获取数据源 - 兼容hash路由模式 |
||||
const getQueryParam = (key) => { |
||||
const hash = window.location.hash; |
||||
const queryString = hash.split('?')[1] || ''; |
||||
const params = new URLSearchParams(queryString); |
||||
return params.get(key) || ''; |
||||
}; |
||||
|
||||
// 从URL参数获取数据源 |
||||
const sourceParam = computed(() => { |
||||
// 先尝试 route.query,如果为空则从 window.location 解析 |
||||
return route.query.source || getQueryParam('source'); |
||||
}); |
||||
|
||||
// 根据 source 参数动态设置 sourceTableList |
||||
const dynamicSourceTableList = computed(() => { |
||||
const source = sourceParam.value; |
||||
if (!source) return []; |
||||
return [source]; |
||||
}); |
||||
|
||||
const query = ref({ |
||||
size: 10, |
||||
current: 1, |
||||
sourceTableList: [], |
||||
sourceTableSubOneList: [], |
||||
secondDepartId: null, |
||||
thirdDepartId: null, |
||||
handleDepartId: null, |
||||
initialReviewFileList: [], |
||||
createTimeList: [], |
||||
personInfo: '', |
||||
}); |
||||
|
||||
const list = ref([]); |
||||
const total = ref(0); |
||||
const loading = ref(false) |
||||
|
||||
const getList = async () => { |
||||
loading.value = true; |
||||
|
||||
// 确保 sourceTableList 包含动态的 source |
||||
let finalSourceTableList = [...dynamicSourceTableList.value]; |
||||
if (query.value.sourceTableSubOneList && query.value.sourceTableSubOneList.length > 0) { |
||||
finalSourceTableList = [...finalSourceTableList, ...query.value.sourceTableSubOneList]; |
||||
} |
||||
|
||||
const params = { |
||||
...query.value, |
||||
sourceTableList: finalSourceTableList, |
||||
} |
||||
debugger |
||||
let res = await getComplaintCollectionPage(params); |
||||
list.value = res.records; |
||||
total.value = res.total; |
||||
loading.value = false; |
||||
} |
||||
|
||||
function reset() { |
||||
query.value = { |
||||
size: 10, |
||||
current: 1, |
||||
sourceTableList: [], |
||||
sourceTableSubOneList: [], |
||||
secondDepartId: null, |
||||
thirdDepartId: null, |
||||
handleDepartId: null, |
||||
initialReviewFileList: [], |
||||
createTimeList: [], |
||||
personInfo: '', |
||||
}; |
||||
getList(); |
||||
} |
||||
|
||||
onMounted(() => { |
||||
// 等待 nextTick 确保路由参数已经准备好 |
||||
setTimeout(() => { |
||||
isReady.value = true; |
||||
console.log('sourceParam:', sourceParam.value); |
||||
console.log('route.fullPath:', route.fullPath); |
||||
console.log('route.query:', JSON.stringify(route.query)); |
||||
getList(); |
||||
}, 100); |
||||
}); |
||||
|
||||
// 监听路由参数变化 |
||||
watch(() => getQueryParam('source'), () => { |
||||
if (isReady.value) { |
||||
console.log('source changed:', getQueryParam('source')); |
||||
getList(); |
||||
} |
||||
}); |
||||
|
||||
const storeDict = computed(() => |
||||
catchStore.getDicts([ |
||||
"businessType", |
||||
"suspectProblem", |
||||
"policeType", |
||||
"hostLevel", |
||||
"timeLimit", |
||||
"approvalFlow", |
||||
"specialSupervision", |
||||
"checkStatus", |
||||
"sfssSourceTable", |
||||
"sfssTags", |
||||
"accountabilityTarget", |
||||
"processingStatus", |
||||
"handleMethodType" |
||||
]) || {} |
||||
); |
||||
|
||||
// 根据source过滤二级来源选项 |
||||
const sourceTableSubOneList = computed(() => { |
||||
const list = storeDict.value.sfssSourceTable || []; |
||||
const source = sourceParam.value; |
||||
|
||||
const children = list |
||||
.filter(d => d.remark === source) |
||||
.sort((a, b) => (a.dictSort ?? 0) - (b.dictSort ?? 0)) |
||||
|
||||
return children.map(c => ({ |
||||
label: c.dictLabel, |
||||
value: String(c.dictValue), |
||||
})); |
||||
}) |
||||
|
||||
const localDict = { |
||||
yesNo: [ |
||||
{id: 1, dictLabel: "是", dictValue: "1"}, |
||||
{id: 2, dictLabel: "否", dictValue: "0"}, |
||||
], |
||||
handleMethodType: [ |
||||
{id: 1, dictLabel: "自办", dictValue: "0"}, |
||||
{id: 2, dictLabel: "下发", dictValue: "1"}, |
||||
], |
||||
}; |
||||
|
||||
const dict = computed(() => ({ |
||||
...storeDict.value, |
||||
...localDict, |
||||
sourceTableSubOneList: sourceTableSubOneList.value, |
||||
})); |
||||
|
||||
function getDictLabel(list, value) { |
||||
if (!Array.isArray(list)) return '/' |
||||
|
||||
if (value === null || value === undefined || value === '') return '/' |
||||
|
||||
let values = [] |
||||
|
||||
if (Array.isArray(value)) { |
||||
values = value |
||||
} |
||||
else if (typeof value === 'string' && value.includes(',')) { |
||||
values = value.split(',').map(v => v.trim()) |
||||
} |
||||
else { |
||||
values = [value] |
||||
} |
||||
|
||||
const labels = values |
||||
.map(v => { |
||||
const item = list.find(d => d.dictValue == v) |
||||
return item?.dictLabel |
||||
}) |
||||
.filter(Boolean) |
||||
|
||||
return labels.length ? labels.join(',') : '/' |
||||
} |
||||
|
||||
function handleActionDetail(row) { |
||||
if (row.problemSources === '局长信箱') { |
||||
mailboxShow.value = true; |
||||
activeNegativeId.value = row.originId; |
||||
} else { |
||||
show.value = true; |
||||
activeNegativeId.value = row.negativeId; |
||||
} |
||||
} |
||||
|
||||
const handleExport = async () => { |
||||
let finalSourceTableList = [...dynamicSourceTableList.value]; |
||||
if (query.value.sourceTableSubOneList && query.value.sourceTableSubOneList.length > 0) { |
||||
finalSourceTableList = [...finalSourceTableList, ...query.value.sourceTableSubOneList]; |
||||
} |
||||
|
||||
const body = { |
||||
...query.value, |
||||
sourceTableList: finalSourceTableList, |
||||
}; |
||||
await exportData(body); |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.el-form-item .el-form-item { |
||||
margin-bottom: 18px; |
||||
} |
||||
|
||||
:deep() { |
||||
.el-form-item--label-right .el-form-item__label { |
||||
text-align: right; |
||||
line-height: 32px; |
||||
margin-bottom: 0; |
||||
} |
||||
} |
||||
|
||||
p { |
||||
margin: 0; |
||||
line-height: 1.4; |
||||
} |
||||
|
||||
.dialog-footer { |
||||
display: flex; |
||||
justify-content: flex-end; |
||||
padding: 0 24px 16px; |
||||
} |
||||
</style> |
||||
Loading…
Reference in new issue