mps-platform/cds-fontend-2025.V1/src/views/mps/market/index.vue
2025-08-25 18:47:19 +08:00

608 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 {onMounted,ref, watch} from "vue";
import { NButton,NDivider } from 'naive-ui';
import { fetchBatchDeleteMarket, fetchGetMarketList } from '@/service/api/mps/market';
import { fetchGetSubcategorySelect } from '@/service/api/business/subcategory';
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 {useDict} from "@/hooks/business/dict";
import DictTag from '@/components/custom/dict-tag.vue';
import { $t } from '@/locales';
import ButtonIcon from '@/components/custom/button-icon.vue';
import MarketOperateDrawer from './modules/market-operate-drawer.vue';
import MarketSearch from './modules/market-search.vue';
import MarketImportModal from './modules/market-import-modal.vue';
import {useBoolean,useLoading} from "~/packages/hooks";
// 在组件的setup或适当位置
const { options: mps_cust_type } = useDict('mps_cust_type');
console.log('mps_check_status dictionary:', mps_cust_type);
defineOptions({
name: 'MarketList'
});
const appStore = useAppStore();
const { download } = useDownload();
const { hasAuth } = useAuth();
const { bool: importVisible, setTrue: openImportModal } = useBoolean();
// 添加用于显示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: fetchGetMarketList,
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: 'jbName',
title: '经办人员名称',
align: 'center',
minWidth: 120,
ellipsis: true,
resizable: true
},
{
key: 'yxId',
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
},
{
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
},
{
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: 'checkFlag',
title: '核对标志',
align: 'center',
minWidth: 120,
ellipsis: true,
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
},
{
key: 'operate',
title: $t('common.operate'),
fixed: 'right',
width: 130,
render: row => {
const divider = () => {
if (!hasAuth('mps:market:edit') || !hasAuth('mps:market:remove')) {
return null;
}
return <NDivider vertical />;
};
const editBtn = () => {
if (!hasAuth('mps:market: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:market:remove')) {
return null;
}
return (
<ButtonIcon
text
type="error"
local-icon="delete-outline"
tooltipContent={$t('common.delete')}
popconfirmContent={$t('common.confirmDelete')}
onPositiveClick={() => handleDelete(row.dataId!)}
/>
);
};
// 只有当checkType为'9'时才显示编辑按钮
// if (row.checkFlag !== '9') {
// return null;
// }
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 fetchBatchDeleteMarket(checkedRowKeys.value);
if (error) return;
onBatchDeleted();
}
async function handleDelete(dataId: CommonType.IdType) {
// request
const { error } = await fetchBatchDeleteMarket([dataId]);
if (error) return;
onDeleted();
}
function edit(dataId: CommonType.IdType) {
handleEdit('dataId', dataId);
}
function handleImport() {
openImportModal();
}
function handleExport() {
download('/mps/market/export', searchParams, `营销数据管理_${new Date().getTime()}.xlsx`);
}
//获取子类目下拉框
const { startLoading, endLoading } = useLoading();
const subcategoryIdOptions = ref<CommonType.Option<CommonType.IdType>[]>([]);
onMounted(() => {
getSubcategoryOptions();
});
async function getSubcategoryOptions() {
startLoading();
const { error, data } = await fetchGetSubcategorySelect();
if (!error) {
subcategoryIdOptions.value = data.map(item => ({
label: item.name,
value: item.id
}));
}
endLoading();
}
</script>
<template>
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
<MarketSearch v-model:model="searchParams" :subcategoryId-options="subcategoryIdOptions" @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="hasAuth('mps:market:add')"
:show-delete="hasAuth('mps:market:remove')"
:show-export="hasAuth('mps:market:export')"
@add="handleAdd"
@delete="handleBatchDelete"
@export="handleExport"
@refresh="getData"
>
<template #after>
<NButton v-if="hasAuth('mps:market:export')" size="small" ghost @click="handleImport">
<template #icon>
<SvgIcon local-icon="upload-rounded" class="text-icon"/>
</template>
{{ $t('common.import') }}
</NButton>
</template>
</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()"
/>
<MarketImportModal v-model:visible="importVisible" @submitted="getDataByPage"/>
<MarketOperateDrawer
v-model:visible="drawerVisible"
:operate-type="operateType"
:row-data="editingData"
:subcategoryIdOptions="subcategoryIdOptions"
@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>