mps-platform/cds-fontend-2025.V1/src/views/report/detail-entry/index.vue

598 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="tsx">
import { NDivider } from 'naive-ui';
import { fetchBatchDeleteDetailEntry, fetchGetDetailEntryList } from '@/service/api/mps/detail-entry';
import { useAppStore } from '@/store/modules/app';
import { useAuth } from '@/hooks/business/auth';
import { useDownload } from '@/hooks/business/download';
import { useTable, useTableOperate } from '@/hooks/common/table';
import { $t } from '@/locales';
import ButtonIcon from '@/components/custom/button-icon.vue';
import DetailEntryOperateDrawer from './modules/detail-entry-operate-drawer.vue';
import DetailEntrySearch from './modules/detail-entry-search.vue';
import {computed, ref, watch} from "vue";
import DictTag from '@/components/custom/dict-tag.vue';
import {useBoolean} from "~/packages/hooks";
import DetailEntryImportModal from './modules/detail-entry-import-modal.vue';
import {useDict} from "@/hooks/business/dict";
defineOptions({
name: 'DetailEntryList'
});
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
const { bool: importVisible, setTrue: openImportModal } = useBoolean();
// const { options: mps_cust_type } = useDict('mps_cust_type');
const { options: mps_check_status } = useDict('mps_check_status');
// 添加用于显示trafficList的模态框相关状态
const trafficListModalVisible = ref(false);
const currentTrafficList = ref<{ trafficNo?: string; trafficAmt?: number }[]>([]);
// 添加用于显示magneticCardList的模态框相关状态
const magneticCardListModalVisible = ref(false);
const currentMagneticCardList = ref<{ oldCardNo?: string; newCardNo?: string }[]>([]);
const {
columns,
columnChecks,
data,
getData,
getDataByPage,
loading,
mobilePagination,
searchParams,
resetSearchParams
} = useTable({
apiFn: fetchGetDetailEntryList,
apiParams: {
pageNum: 1,
pageSize: 10,
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
// the value can not be undefined, otherwise the property in Form will not be reactive
subcategoryId: null,
subcategoryName: null,
yxName: null,
jbName: null,
yxId: null,
jbId: null,
date: null,
deptName: null,
deptId: null,
custType: null,
custId: null,
custName: null,
custAcctNo: null,
custPhoneNo: null,
magneticCardId: null,
acquiringName: null,
acquiringId: null,
internetChannel: null,
trafficId: null,
workplace: null,
surplusAccountName: null,
heatingNo: null,
checkFlag: null,
checkTime: null,
checkUser: null,
checkType: null,
checkMsg: null,
params: {}
},
columns: () => [
{
type: 'selection',
align: 'center',
width: 48
},
{
key: 'index',
title: $t('common.index'),
align: 'center',
width: 64,
resizable: true
},
// {
// key: 'dataId',
// title: '主键',
// align: 'center',
// minWidth: 120,
// ellipsis: true,
// resizable: true
// },
// {
// key: 'subcategoryId',
// title: '业务类型id',
// align: 'center',
// minWidth: 120,
// ellipsis: true,
// resizable: true
// },
{
key: 'subcategoryName',
title: '业务类型名称',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'yxName',
title: '营销人员名称',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'yxId',
title: '营销人员营销号',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'jbName',
title: '经办人员名称',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'jbId',
title: '经办人员营销号',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'date',
title: '数据日期',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'deptName',
title: '部门名称',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
// {
// key: 'deptId',
// title: '部门id',
// align: 'center',
// minWidth: 120,
// ellipsis: true,
// resizable: true
// },
{
key: 'custType',
title: '客户类型',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true,
render(row) {
return <DictTag size="small" value={row.custType} dictCode="mps_cust_type" />;
}
},
{
key: 'custId',
title: '客户身份证号',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true,
render(row) {
// 身份证号脱敏显示前6位和后4位中间用星号替代
if (row.custId && row.custId.length === 18) {
return row.custId.replace(/^(\d{6})\d+([\dXx]{4})$/, "$1********$2")
}
return row.custId || '';
}
},
{
key: 'custName',
title: '客户姓名',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'custAcctNo',
title: '客户账号/卡号',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'custPhoneNo',
title: '客户联系电话',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true,
render(row) {
// 手机号脱敏保留前3位和后4位
if (row.phone) {
return row.phone.replace(/^(\d{3})\d+(\d{4})$/, "$1****$2")
}
return row.phone || '';
}
},
{
key: 'magneticCardId',
title: '磁条卡更换登记id',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true,
render(row) {
// 如果有magneticCardList数据则显示可点击查看的链接
if (row.magneticCardList && row.magneticCardList.length > 0) {
return (
<NButton
text
type="primary"
onClick={() => showMagneticCardList(row.magneticCardList)}
>
查看详情
</NButton>
);
}
// 如果只有magneticCardId但没有magneticCardList则显示magneticCardId
return row.magneticCardId || '';
}
},
{
key: 'acquiringName',
title: '综合收单商户名',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'acquiringId',
title: '综合收单商户号',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'internetChannel',
title: '网上支付开通渠道',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'trafficId',
title: '交警处罚决定书',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true,
render(row) {
// 如果有trafficList数据则显示可点击查看的链接
if (row.trafficList && row.trafficList.length > 0) {
return (
<NButton
text
type="primary"
onClick={() => showTrafficList(row.trafficList)}
>
查看详情
</NButton>
);
}
// 如果只有trafficId但没有trafficList则显示trafficId
return row.trafficId || '';
}
},
{
key: 'workplace',
title: '职工所属单位',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'surplusAccountName',
title: '公积金缴纳账户名称',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'heatingNo',
title: '户号',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'checkMsg',
title: '核对结果',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true,
fixed: 'right'
},
{
key: 'checkFlag',
title: '核对标志',
align: 'center',
minWidth: 120,
ellipsis: true,
fixed: 'right',
resizable: true,
render(row) {
return <DictTag size="small" value={row.checkFlag} dictCode="mps_check_status" />;
},
},
// {
// key: 'checkTime',
// title: '核对时间',
// align: 'center',
// minWidth: 120,
// ellipsis: true,
// resizable: true
// },
// {
// key: 'checkUser',
// title: '核对人员(人工核对时)',
// align: 'center',
// minWidth: 120,
// ellipsis: true,
// resizable: true
// },
// {
// key: 'checkType',
// title: '核对方式0系统 1人工 2其他1 3其他2 4其他3',
// align: 'center',
// minWidth: 120,
// ellipsis: true,
// resizable: true
// },
// {
// key: 'checkMsg',
// title: '核对结果',
// align: 'center',
// minWidth: 120,
// ellipsis: true,
// resizable: true,
// fixed: 'right'
// }
// {
// key: 'operate',
// title: $t('common.operate'),
// fixed: 'right',
// width: 130,
// render: row => {
// const divider = () => {
// if (!hasAuth('mps:detailEntry:edit') || !hasAuth('mps:detailEntry:remove')) {
// return null;
// }
// return <NDivider vertical />;
// };
//
// const editBtn = () => {
// if (!hasAuth('mps:detailEntry:edit')) {
// return null;
// }
// return (
// <ButtonIcon
// text
// type="primary"
// local-icon="drive-file-rename-outline-outline"
// tooltipContent={$t('common.edit')}
// onClick={() => edit(row.dataId!)}
// />
// );
// };
//
// const deleteBtn = () => {
// if (!hasAuth('mps:detailEntry:remove')) {
// return null;
// }
// return (
// <ButtonIcon
// text
// type="error"
// local-icon="delete-outline"
// tooltipContent={$t('common.delete')}
// popconfirmContent={$t('common.confirmDelete')}
// onPositiveClick={() => handleDelete(row.dataId!)}
// />
// );
// };
//
// return (
// <div class="flex-center gap-8px">
// {editBtn()}
// {divider()}
// {deleteBtn()}
// </div>
// );
// }
// }
]
});
// 显示trafficList的函数
function showTrafficList(trafficList: { trafficNo?: string; trafficAmt?: number }[]) {
currentTrafficList.value = trafficList;
trafficListModalVisible.value = true;
}
// 显示magneticCardList的函数
function showMagneticCardList(magneticCardList: { oldCardNo?: string; newCardNo?: string }[]) {
currentMagneticCardList.value = magneticCardList;
magneticCardListModalVisible.value = true;
}
const scrollX = ref(0);
// 计算总宽度函数
const calculateTotalWidth = () => {
let totalWidth = 0;
const visibleColumns = columns.value;
for (let i = 0; i < visibleColumns.length; i++) {
const column = visibleColumns[i];
// 获取列的实际渲染宽度
// 注意:调整大小时会更新 column.width
let width = column.width;
// 如果没有显式宽度则使用minWidth或默认值
if (!width) {
width = column.minWidth || 120;
}
// 转换为数字类型
width = typeof width === 'string' ? parseInt(width) : width;
totalWidth += width;
}
// 添加额外的50px余量防止边缘裁剪
return totalWidth + 50;
};
// 监听列变化并计算宽度
watch(columns, (newColumns) => {
scrollX.value = calculateTotalWidth();
}, { deep: true });
const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
useTableOperate(data, getData);
async function handleBatchDelete() {
// request
const { error } = await fetchBatchDeleteDetailEntry(checkedRowKeys.value);
if (error) return;
onBatchDeleted();
}
async function handleDelete(dataId: CommonType.IdType) {
// request
const { error } = await fetchBatchDeleteDetailEntry([dataId]);
if (error) return;
onDeleted();
}
function edit(dataId: CommonType.IdType) {
handleEdit('dataId', dataId);
}
function handleImport() {
openImportModal();
}
function handleExport() {
download('/mps/detailEntry/export', searchParams, `每日录入明细_${new Date().getTime()}.xlsx`);
}
</script>
<template>
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
<DetailEntrySearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
<NCard title="每日录入明细列表" :bordered="false" size="small" class="sm:flex-1-hidden card-wrapper">
<template #header-extra>
<TableHeaderOperation
v-model:columns="columnChecks"
:disabled-delete="checkedRowKeys.length === 0"
:loading="loading"
:show-add="false"
:show-delete="false"
:show-export="hasAuth('mps:detailEntry:export')"
@add="handleAdd"
@delete="handleBatchDelete"
@export="handleExport"
@refresh="getData"
>
</TableHeaderOperation>
</template>
<!--scroll-x : 所有表格列宽度之和(包含操作列)+操作列宽度-->
<NDataTable
v-model:checked-row-keys="checkedRowKeys"
:columns="columns"
:data="data"
size="small"
:flex-height="!appStore.isMobile"
:scroll-x="scrollX"
:loading="loading"
remote
:row-key="row => row.dataId"
:pagination="mobilePagination"
class="sm:h-full"
@update-resize-widths="scrollX = calculateTotalWidth()"
/>
<DetailEntryImportModal v-model:visible="importVisible" @submitted="getDataByPage"/>
<DetailEntryOperateDrawer
v-model:visible="drawerVisible"
:operate-type="operateType"
:row-data="editingData"
@submitted="getDataByPage"
/>
</NCard>
<!-- 用于显示trafficList详情的模态框 -->
<NModal v-model:show="trafficListModalVisible" preset="card" style="width: 600px;" title="交警处罚决定书详情">
<NTable :bordered="true" :single-line="false">
<thead>
<tr>
<th>决定书编号</th>
<th>处罚金额</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in currentTrafficList" :key="index">
<td>{{ item.trafficNo }}</td>
<td>{{ item.trafficAmt }}</td>
</tr>
<tr v-if="currentTrafficList.length === 0">
<td colspan="2" style="text-align: center;">暂无数据</td>
</tr>
</tbody>
</NTable>
</NModal>
<!-- 用于显示magneticCardList详情的模态框 -->
<NModal v-model:show="magneticCardListModalVisible" preset="card" style="width: 600px;" title="磁条卡更换记录详情">
<NTable :bordered="true" :single-line="false">
<thead>
<tr>
<th>老卡号</th>
<th>新卡号</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in currentMagneticCardList" :key="index">
<td>{{ item.oldCardNo }}</td>
<td>{{ item.newCardNo }}</td>
</tr>
<tr v-if="currentMagneticCardList.length === 0">
<td colspan="2" style="text-align: center;">暂无数据</td>
</tr>
</tbody>
</NTable>
</NModal>
</div>
</template>
<style scoped></style>