Commit 352e73d1 by Sweet Zhang

新单跟进对接

parent b3a13b17
......@@ -162,7 +162,8 @@ const searchConfig = ref([
type: 'input',
prop: 'policyNo',
label: '保单号'
}, {
},
{
type: 'select',
prop: 'statusList',
label: '出账状态',
......@@ -209,13 +210,13 @@ const searchConfig = ref([
startPlaceholder: '开始时间',
endPlaceholder: '结束时间'
},
// {
// type: 'select',
// prop: 'status',
// label: '入账状态',
// multiple: true,
// dictType: 'csf_expected_commission_status'
// },
{
type: 'select',
prop: 'commissionStatusList',
label: '入账状态',
multiple: true,
dictType: 'csf_expected_commission_status'
},
])
// 表格操作菜单
const dropdownItems = [
......@@ -370,7 +371,7 @@ const handleQuery = async () => {
const params = searchFormRef.value.getFormData()
loadTableData(params)
}
const visibleDefaultButtons = ref(['add', 'import', 'export', 'reset', 'query'])
const visibleDefaultButtons = ref(['add', 'export', 'reset', 'query'])
// 按钮配置
const operationBtnList = ref([
{
......@@ -378,12 +379,13 @@ const operationBtnList = ref([
direction: 'left',
label: '新增出账',
click: handleAdd
}, {
key: 'import',
direction: 'left',
label: '导入出账',
click: handleImport
},
},
// {
// key: 'import',
// direction: 'left',
// label: '导入出账',
// click: handleImport
// },
{
key: 'export',
direction: 'right',
......
......@@ -304,6 +304,8 @@ const searchConfig = ref([
}
},
])
const payRecordDialogTableVisible = ref(false)
// 新增出账记录
const addPayRecordFormModel = ref({
......
......@@ -69,9 +69,9 @@
{{ (row.pendingRatio || 0) + '%' }}
</template>
</el-table-column>
<el-table-column prop="pendingPaidAmount" label="待入账金额(估)" width="160" sortable>
<el-table-column prop="pendingAmount" label="待入账金额(估)" width="160" sortable>
<template #default="{ row }">
{{ numberWithCommas(row.pendingPaidAmount) }}
{{ numberWithCommas(row.pendingAmount) }}
</template>
</el-table-column>
<el-table-column prop="currency" label="入账币种" width="100" />
......
<template>
<div class="data-management-page">
<!-- 查询区域 -->
<el-card class="search-card">
<!-- 第一行筛选条件 -->
<el-row :gutter="20" class="search-row">
<el-col :span="8">
<div class="form-item">
<label class="form-label">保单号</label>
<el-input
v-model="searchForm.policyNo"
placeholder="请输入"
clearable
size="default"
@keyup.enter="handleSearch"
/>
</div>
</el-col>
<el-col :span="8">
<div class="form-item">
<label class="form-label">客户姓名</label>
<el-input
v-model="searchForm.customerName"
placeholder="请输入"
clearable
size="default"
@keyup.enter="handleSearch"
/>
</div>
</el-col>
<el-col :span="8">
<div class="form-item">
<label class="form-label">新单状态</label>
<el-select v-model="searchForm.status" placeholder="请选择" clearable size="default">
<!-- 增加全部,默认传空字符串 -->
<el-option label="全部" value=" " />
<el-option
v-for="item in policyFollowStatusList"
:key="item.itemValue"
:label="item.itemLabel"
:value="item.itemValue"
/>
</el-select>
</div>
</el-col>
</el-row>
<!-- 第二行筛选条件 -->
<el-row :gutter="20" class="search-row">
<el-col :span="8">
<div class="form-item">
<label class="form-label">签单时间</label>
<el-date-picker
v-model="searchForm.signDateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
size="default"
/>
</div>
</el-col>
<!-- :icon="Search" -->
<el-col :span="8" class="search-buttons">
<el-button type="primary" @click="handleSearch" size="default" class="search-btn">
查询
</el-button>
<!-- :icon="RefreshLeft" -->
<el-button @click="resetForm" size="default"> 重置 </el-button>
</el-col>
</el-row>
</el-card>
<!-- Excel导入区域 -->
<div class="import-area">
<el-card class="import-card">
<div class="import-content">
<div class="import-actions">
<el-upload
class="upload-excel"
:auto-upload="false"
:on-change="handleFileChange"
:show-file-list="false"
accept=".xlsx, .xls"
>
<el-button type="success" size="default"> 上传Excel文件 </el-button>
</el-upload>
<el-button text @click="downloadTemplate" size="default" class="download-template-btn">
下载模板
</el-button>
</div>
<!-- 文件信息显示 -->
<div v-if="selectedFile" class="file-info">
<div class="file-info-content">
<el-icon><document /></el-icon>
<span class="file-name">{{ selectedFile.name }}</span>
<span class="file-size">({{ formatFileSize(selectedFile.size) }})</span>
</div>
<el-button
type="primary"
@click="handleImport"
size="default"
:loading="importLoading"
class="confirm-import-btn"
>
确认导入
</el-button>
</div>
</div>
</el-card>
</div>
<!-- 列表区域 -->
<el-card class="table-card">
<div class="table-actions">
<el-button type="primary" @click="handleUpdateToPolicyLib">更新至保单库</el-button>
<!-- <el-text class="mx-1" size="large">新单首期保费缴费完成后,勾选并点击更新至保单库,可前往保单中心查询</el-text> -->
</div>
<el-table
v-loading="tableLoading"
:data="tableData"
border
style="width: 100%"
height="350"
@selection-change="handleSelectionChange"
@sort-change="handleSortChange"
:row-class-name="tableRowClassName"
>
<el-table-column type="selection" width="55" align="center" />
<!-- 新单状态需要通过policyFollowStatusList和value匹配,显示label -->
<el-table-column prop="status" label="新单状态" width="100" align="center" sortable>
<template #default="scope">
<span>{{ convertStatusToDict(1, scope.row.status) }}</span>
</template>
</el-table-column>
<el-table-column prop="coolingOffEndDate" label="冷静期结束日期" width="150" align="center">
<template #default="scope">
<span>{{
scope.row.coolingOffEndDate ? parseTime(scope.row.coolingOffEndDate) : '--'
}}</span>
</template>
</el-table-column>
<el-table-column prop="coolingOffDays" label="冷静期天数" width="150" align="center">
</el-table-column>
<el-table-column prop="policyNo" label="保单号" width="150" align="center" sortable />
<el-table-column prop="customerName" label="客户名称" width="100" align="center" sortable />
<el-table-column prop="signDate" label="签单日期" width="150" align="center" sortable>
<template #default="scope">
<span>{{ parseTime(scope.row.signDate) }}</span>
</template>
</el-table-column>
<el-table-column prop="signer" label="签单人" width="100" align="center" sortable />
<el-table-column prop="paymentTerm" label="供款年期" width="100" align="center" sortable />
<el-table-column prop="productName" label="产品名称" width="150" align="center" sortable />
<el-table-column prop="insurer" label="保险公司" width="150" align="center" sortable />
<el-table-column
prop="reconciliationCompany"
label="对账公司"
width="150"
align="center"
sortable
/>
<el-table-column
prop="policyHolder"
label="保单持有人"
width="150"
align="center"
sortable
/>
<el-table-column prop="insured" label="受保人" width="100" align="center" sortable />
<el-table-column prop="currency" label="币种" width="100" align="center" sortable>
<template #default="scope">
<dict-tag :options="currencyTypeOptions" :value="scope.row.currency" />
</template>
</el-table-column>
<el-table-column prop="initialPremium" label="首期保费" width="150" align="center" sortable>
<template #default="scope">
{{ numberWithCommas(scope.row.initialPremium) }}
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="200"
class-name="small-padding fixed-width"
fixed="right"
>
<template #default="scope">
<div class="btnCon">
<el-button link type="primary" size="small" @click="handleReport(scope.row)">
生成签约单完成报告
</el-button>
<el-dropdown placement="bottom" style="margin-left: 10px">
<el-button type="primary" link size="small">
更多 <el-icon><ArrowDown /></el-icon
></el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleView(scope.row)">查看</el-dropdown-item>
<el-dropdown-item @click="handleStatus(scope.row)">跟进</el-dropdown-item>
<el-dropdown-item @click="handleEditStatus(scope.row)"
>修改状态</el-dropdown-item
>
</el-dropdown-menu>
<div>
<CommonPage :operationBtnList='operationBtnList' :visibleDefaultButtons="visibleDefaultButtons"
:showSearchForm='true' :show-pagination='true' :total='pageTotal' :current-page='currentPage'
:page-size='pageSize' @size-change='handleSizeChange' @current-change='handleCurrentChange'>
<!-- 搜索区域 -->
<template #searchForm>
<SearchForm ref="searchFormRef" :config="searchConfig" />
</template>
<!-- 列表区域 -->
<template #table>
<el-table :data="tableData" height="400" border highlight-current-row style="width: 100%" v-loading="loading">
<el-table-column prop="policyNo" label="保单号" width="120" fixed="left" sortable />
<el-table-column prop="policyNo" label="新单状态" width="120" fixed="left" sortable />
<el-table-column prop="appointmentNo" label="预约编号" width="150" fixed="left" sortable />
<el-table-column prop="signDate" label="签单日" width="150" fixed="left" sortable />
<el-table-column prop="policyBizId" label="最晚缴费日" width="150" fixed="left" sortable />
<el-table-column prop="policyHolder" label="投保人" width="150" fixed="left" sortable />
<el-table-column prop="policyNo" label="受保人" width="150" fixed="left" sortable />
<el-table-column prop="insuranceCompany" label="保险公司" width="150" fixed="left" sortable />
<el-table-column prop="productName" label="产品计划" width="150" fixed="left" sortable />
<el-table-column prop="paymentNumber" label="缴费年期" width="150" fixed="left" sortable />
<el-table-column fixed="right" label="操作" min-width="80">
<template #default="{ row }">
<el-popover placement="right" :width="200" trigger="click">
<template #reference>
<el-icon>
<MoreFilled />
</el-icon>
</template>
</el-dropdown>
</div>
<!-- <el-button text size="primary" @click="handleView(scope.row)"> 查看 </el-button> -->
<!-- <el-button text size="primary" @click="handleStatus(scope.row)"> 跟进 </el-button>
<el-button text type="warning" @click="handleEditStatus(scope.row)">
修改状态
</el-button> -->
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination">
<el-pagination
v-model:current-page="pagination.currentPage"
v-model:page-size="pagination.pageSize"
:page-sizes="[10, 20, 50, 100]"
:total="pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</el-card>
<!-- 使用查看数据详情组件 -->
<PolicyDetailDialog
:visible="viewDialogVisible"
:detail-data="currentRow"
:policy-follow-status-list="policyFollowStatusList"
title="新单跟进详情"
:expected-commission-list="expectedCommissionList"
:policy-fortune-list="policyFortuneList"
@close="handleDetailClose"
/>
<el-dialog title="修改新单状态" v-model="editStatus" width="500px" append-to-body>
<div style="height: 10vh">
<el-form>
<el-row>
<el-col :span="12">
<el-form-item label="状态">
<el-select v-model="form.status" placeholder="请选择">
<el-option
v-for="item in currentPolicyRow.nextStatusList"
:label="item.itemLabel"
:value="item.itemValue"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="canelEdit">取 消</el-button>
</div>
<el-menu @select="handleSelect($event, row)" popper-class="custom-menu">
<el-menu-item :index="item.value" v-for="item in dropdownItems" :key="item.value">{{
item.label
}}</el-menu-item>
</el-menu>
</el-popover>
</template>
</el-table-column>
</el-table>
</template>
</el-dialog>
</CommonPage>
<!-- 弹窗-->
<CommonDialog dialogTitle='弹窗' dialogWidth='80%' :openDialog=dialogFlag :showAction='false' :showClose='true'
@close='dialogFlag = false'>
内容
</CommonDialog>
</div>
</template>
<!-- {
"code": 200,
"msg": "生成预计发佣正在处理....,稍后查看预计发佣列表",
"data": null
} -->
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ref, reactive, computed, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import axios from 'axios'
import CommonPage from '@/components/commonPage'
import SearchForm from '@/components/SearchForm/SearchForm.vue'
import CommonDialog from '@/components/commonDialog'
import { loadDicts, getDictLabel } from '@/utils/useDict'
import useUserStore from '@/store/modules/user'
import { safeDownload } from '@/utils/safeDownload'
import {
getPolicyFollowList,
getExpectedCommissionList,
changePolicyStatus,
policyFollowReport
} from '@/api/sign/underwritingMain'
import { getToken } from '@/utils/auth'
import { listType } from '@/api/system/dict/type'
import date from '@/utils/date'
import PolicyDetailDialog from '@/components/PolicyDetailDialog/index.vue'
import { numberWithCommas } from '@/utils/index.js'
import { getPolicyFortuneList } from '@/api/financial/commission'
const { proxy } = getCurrentInstance()
const router = useRouter()
// 通过dictType=csf_policy_follow_status获取新单状态字典值,获取对象中的dictItemList
const policyFollowStatusList = ref([])
const commissionStatusList = ref([])
const fortuneStatusList = ref([])
const currencyTypeOptions = ref([])
const currentPolicyRow = ref({}) //当前保单
const editStatus = ref(false) //新单信息状态
const data = reactive({
form: {}
})
const { form } = toRefs(data)
const canelEdit = () => {
editStatus.value = false
form.value = {}
}
// 修改新单状态
const submitForm = () => {
let obj = {
policyBizId: currentPolicyRow.value.policyBizId,
status: form.value.status
}
changePolicyStatus(obj).then(response => {
if (response.code == 200) {
proxy.$modal.msgSuccess('新单状态修改成功')
editStatus.value = false
form.value = {}
fetchTableData()
}
})
}
const getLists = () => {
listType({
typeList: [
'csf_policy_follow_status',
'csf_expected_commission_status',
'csf_fortune_status',
'bx_currency_type'
]
})
.then(res => {
if (res.code === 200 && res.data) {
const statusData = res.data.find(item => item.dictType === 'csf_policy_follow_status')
policyFollowStatusList.value = statusData?.dictItemList || []
const commissionStatusData = res.data.find(
item => item.dictType === 'csf_expected_commission_status'
)
commissionStatusList.value = commissionStatusData?.dictItemList || []
const fortuneStatusData = res.data.find(item => item.dictType === 'csf_fortune_status')
fortuneStatusList.value = fortuneStatusData?.dictItemList || []
// 处理币种字典值
const currencyData = res.data.find(item => item.dictType === 'bx_currency_type')
if (currencyData) {
currencyData?.dictItemList.forEach(item => {
item.value = item.itemValue
item.label = item.itemLabel
})
}
currencyTypeOptions.value = currencyData?.dictItemList || []
} else {
policyFollowStatusList.value = []
commissionStatusList.value = []
fortuneStatusList.value = []
currencyTypeOptions.value = []
}
})
.catch(error => {
console.error('获取状态列表失败:', error)
policyFollowStatusList.value = []
})
}
// 返回数据中状态需要转换为字典值
const convertStatusToDict = (type = 1, status) => {
const arr =
type === 1 ? policyFollowStatusList : type === 2 ? commissionStatusList : fortuneStatusList
const dictItem = arr.value.find(item => item.itemValue == status)
return dictItem?.itemLabel ?? status
}
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + '/csf/api/policy_follow/upload/excel')
// 搜索表单数据
const searchForm = reactive({
policyBizId: '', // 新单编号(对应接口的policyBizId)
policyNo: '', // 保单编号
customerName: '', // 客户姓名
customerBizId: '', // 客户编号(对应接口的customerBizId)
signDateRange: [], // 签单时间范围
status: '', // 新单状态(对应接口的status)
// 高级筛选字段
insurer: '', // 保险公司
productCode: '' // 产品代码(对应接口的productCode)
})
// 预计来佣列表
const expectedCommissionList = ref([])
const policyFortuneList = ref([])
const getPolicyFortuneLists = async policyNo => {
const userStore = useUserStore()
// 分页相关
const currentPage = ref(1)
const pageSize = ref(10)
const pageTotal = ref(0)
const loading = ref(false)
// 搜索表单数据
const searchFormData = reactive({})
const selectedRow = ref(null)
// 弹窗相关
const dialogFlag = ref(false)
// 获取新单状态,字典值转化方法
onMounted(async () => {
try {
const response = await getPolicyFortuneList({ policyNo })
if (response.code === 200 && response.data) {
policyFortuneList.value = response.data.records || []
policyFortuneList.value.forEach(item => {
item.fortuneStatusLabel = convertStatusToDict(3, item.status)
})
} else {
policyFortuneList.value = []
}
await loadDicts(['csf_policy_follow_status'])
} catch (error) {
console.error('获取预计来佣列表失败:', error)
policyFortuneList.value = []
console.error('字典加载失败', error)
} finally {
loading.value = false
}
}
// 表格数据
const tableData = ref([])
const tableLoading = ref(false)
const selectedRows = ref([])
// 查看详情弹窗相关
const viewDialogVisible = ref(false)
const currentRow = ref({})
// 分页数据
const pagination = reactive({
currentPage: 1, // 当前页码(对应接口的pageNo)
pageSize: 10, // 每页条数(对应接口的pageSize)
total: 0, // 总条数
sortField: '', // 排序字段
sortOrder: '' // 排序方向
})
// 处理查看
const handleView = async row => {
console.log('查看详情:', row)
currentRow.value = { ...row }
viewDialogVisible.value = true
fetchExpectedCommissionList(row.policyNo)
getPolicyFortuneLists(row.policyNo)
}
const handleReport = async row => {
try {
const res = await policyFollowReport(row.policyBizId)
console.log('pdf请求', res)
// 创建 Blob 对象
const blob = new Blob([res], { type: 'application/pdf' })
// 创建对象 URL
const url = window.URL.createObjectURL(blob)
// 在新窗口打开
window.open(url, '_blank')
//下载得方式
// const blob = new Blob([res], { type: 'application/pdf' })
// const url = window.URL.createObjectURL(blob)
// // 创建下载链接
// const link = document.createElement('a')
// link.href = url
// link.download = '签约单.pdf' // 设置文件名
// link.click()
// // 清理 URL 对象
// window.URL.revokeObjectURL(url)
} catch (error) {
console.error('导出失败:', error)
// 按钮事件处理
const handleAdd = () => {
ElMessage.info('点击新增按钮')
}
const handleImport = () => {
ElMessage.info('点击导入按钮')
}
const handleExport = () => {
ElMessage.info('点击导出按钮')
}
const handleReset = () => {
// 重置搜索表单
searchFormRef.value.resetForm()
searchParams.value = {}
console.log('表单已重置')
// 重新加载数据
loadTableData()
}
const handleQuery = async () => {
loadTableData()
}
const visibleDefaultButtons = ref(['reset', 'query'])
// 按钮配置
const operationBtnList = ref([
{
key: 'reset',
direction: 'right',
click: handleReset
},
{
key: 'query',
direction: 'right',
click: handleQuery
}
])
// 分页事件
const handleSizeChange = (val) => {
pageSize.value = val
loadTableData()
}
// 处理详情弹窗关闭
const handleDetailClose = () => {
viewDialogVisible.value = false
console.log('详情弹窗已关闭')
const handleCurrentChange = (val) => {
currentPage.value = val
loadTableData()
}
// Excel导入相关
const selectedFile = ref(null)
const importLoading = ref(false)
// 页面加载时获取数据
onMounted(() => {
fetchTableData()
getLists()
})
// 获取列表数据
const fetchTableData = async () => {
tableLoading.value = true
try {
// 构造接口请求参数
const params = {
pageNo: pagination.currentPage, // 注意:如果后端是从0开始的页码,需要减1
pageSize: pagination.pageSize,
sortField: pagination.sortField,
sortOrder: pagination.sortOrder,
status: searchForm.status,
policyBizId: searchForm.policyBizId,
policyNo: searchForm.policyNo,
customerName: searchForm.customerName,
customerBizId: searchForm.customerBizId,
insurer: searchForm.insurer,
productCode: searchForm.productCode,
// 签单时间范围需要根据后端要求的参数名进行调整
// 例如:如果后端需要startSignDate和endSignDate
...(searchForm.signDateRange &&
searchForm.signDateRange.length === 2 && {
startSignDate: date.formatToDate(searchForm.signDateRange[0]) + ' 00:00:00',
endSignDate: date.formatToDate(searchForm.signDateRange[1]) + ' 23:59:59'
})
// 表格数据
const tableData = ref([])
const searchFormRef = ref(null)
const searchParams = ref({})
const searchConfig = ref([
{
type: 'input',
prop: 'policyNo',
label: '保单号'
},
{
type: 'select',
prop: 'status',
label: '新单状态',
dictType: 'csf_policy_follow_status'
},
{
type: 'input',
prop: 'appointmentNo',
label: '预约编号'
}, {
type: 'daterange',
prop: 'signDate',
label: '签单日',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间'
},
{
type: 'date',
prop: 'latestPaymentDate',
label: '最晚缴费日',
placeholder: '请选择'
},
{
type: 'select',
prop: 'insuranceCompanyBizIdList',
label: '保险公司',
api: '/insurance/base/api/insuranceCompany/page',
keywordField: 'queryContent',
requestParams: { pageNo: 1, pageSize: 20 },
placeholder: '输入保险公司名称搜索',
debounceWait: 500, // 自定义防抖时间
valueKey: 'insuranceCompanyBizId',
labelKey: 'abbreviation',
multiple: true,
transform: (res) => {
console.log(res)
return res?.data.records || []
}
// 调用后台接口
const response = await getPolicyFollowList(params)
// 处理接口响应
if (response.code === 200) {
const result = response.data
// 将接口返回的数据映射到表格
tableData.value = result.records.map(record => ({
...record
}))
// console.log('tableData',tableData.value)
// 更新分页信息
pagination.total = result.total
pagination.currentPage = result.current || pagination.currentPage
pagination.pageSize = result.size || pagination.pageSize
} else {
// 接口返回错误信息
ElMessage.error(`获取数据失败: ${response.data.msg || '未知错误'}`)
tableData.value = []
pagination.total = 0
}, {
type: 'select',
prop: 'productLaunchBizIdList',
label: '产品计划',
api: '/product/api/relProjectProductLaunch/parameter/page',
keywordField: 'productName',
requestParams: {
tenantBizId: userStore.projectInfo.tenantBizId || '',
projectBizId: userStore.projectInfo.projectBizId || '', fieldBizId: 'field_olk1qZe81qHHKXbw', fieldValueBizId: 'field_value_uOfJH5ucA2YwJpbn', pageNo: 1, pageSize: 20
},
placeholder: '输入产品计划名称搜索',
debounceWait: 500, // 自定义防抖时间
valueKey: 'productLaunchBizId',
labelKey: 'productName',
multiple: true,
transform: (res) => {
return res?.data.records || []
}
} catch (error) {
// 捕获网络或其他异常
console.error('请求失败:', error)
ElMessage.error('网络异常,请稍后重试')
tableData.value = []
pagination.total = 0
} finally {
tableLoading.value = false
}, {
type: 'input',
prop: 'paymentTerm',
label: '缴费年期',
inputType: 'decimal',
rules: [
{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }
]
}
} // 获取预计来佣列表
const fetchExpectedCommissionList = async (policyNo, pageNo = 1, pageSize = 100) => {
])
const loadTableData = async () => {
loading.value = true
const searchParams = searchFormRef.value.getFormData() || {}
try {
// 构造接口请求参数
const params = {
pageNo: pageNo, // 注意:如果后端是从0开始的页码,需要减1
pageSize: pageSize,
policyNo: policyNo
}
// 调用后台接口
const response = await getExpectedCommissionList(params)
// 处理接口响应
if (response.code === 200) {
const result = response.data
// 将接口返回的数据映射到表格
expectedCommissionList.value = result.records.map(record => ({
...record,
commissionStatusLabel: convertStatusToDict(2, record.status)
}))
} else {
// 接口返回错误信息
ElMessage.error(`获取数据失败: ${response.data.msg || '未知错误'}`)
expectedCommissionList.value = []
...searchParams.value,
signDateStart: searchParams.value?.signDate[0] || undefined,
signDateEnd: searchParams.value?.signDate[1] || undefined,
signDate: undefined,
pageNo: currentPage.value,
pageSize: pageSize.value
}
const response = await getPolicyFollowList(params)
tableData.value = response.data.records
pageTotal.value = response.data.total
pageSize.value = response.data.size
} catch (error) {
// 捕获网络或其他异常
console.error('请求失败:', error)
ElMessage.error('网络异常,请稍后重试')
expectedCommissionList.value = []
ElMessage.error(error.message || '查询失败')
} finally {
loading.value = false
}
}
// 增加通过表格排序,排序字段sortField,升降序sortOrder
const handleSortChange = column => {
pagination.sortField = column.prop
pagination.sortOrder = column.order === 'ascending' ? 'ascend' : 'descend'
fetchTableData()
}
// 处理查询
const handleSearch = () => {
pagination.currentPage = 1
fetchTableData()
ElMessage.success('查询成功')
}
// 重置表单
const resetForm = () => {
searchForm.name = ''
searchForm.status = ''
searchForm.policyBizId = ''
searchForm.policyNo = ''
searchForm.customerName = ''
searchForm.customerBizId = ''
searchForm.insurer = ''
searchForm.productCode = ''
searchForm.signDateRange = []
}
// 处理分页大小变化
const handleSizeChange = val => {
pagination.pageSize = val
fetchTableData()
}
// 处理分页页码变化
const handleCurrentChange = val => {
pagination.currentPage = val
fetchTableData()
}
// 处理表格选择变化
const handleSelectionChange = rows => {
selectedRows.value = rows
}
// 表格行样式
const tableRowClassName = ({ row }) => {
return row.status === 'inactive' ? 'row-inactive' : ''
}
// 处理文件选择
const handleFileChange = file => {
selectedFile.value = file.raw
}
// 处理导入 - 调整为multipart/form-data格式
const handleImport = async () => {
if (!selectedFile.value) {
ElMessage.warning('请先选择文件')
return
// 表格操作菜单
const dropdownItems = [
{ label: '查看详情', value: 'viewDetail' },
{ label: '更新数据', value: 'updateData' },
{ label: '设置新单状态', value: 'setNewSingleStatus' },
{ label: '查看关联', value: 'viewRelated' },
{ label: '生成签单报告', value: 'generateReport' },
{ label: '更新记录', value: 'updateRecord' },
]
const handleSelect = async (e, row) => {
selectedRow.value = { ...row }
console.log(e, row)
switch (e) {
case 'viewDetail':
ElMessage.info('查看详情')
break
case 'updateData':
ElMessage.info('更新数据')
break
case 'setNewSingleStatus':
ElMessage.info('设置新单状态')
break
case 'viewRelated':
ElMessage.info('查看关联')
break
case 'generateReport':
ElMessage.info('生成签单报告')
break
case 'updateRecord':
ElMessage.info('更新记录')
break
default:
break
}
// 二次确认
ElMessageBox.confirm(`确定要导入"${selectedFile.value.name}"吗?`, '导入确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info'
})
.then(async () => {
importLoading.value = true
try {
// 创建FormData对象,用于multipart/form-data格式
const formData = new FormData()
// 将文件添加到FormData,注意参数名要与后端保持一致
formData.append('file', selectedFile.value)
// 可以添加其他参数(如果后端需要)
// formData.append('otherParam', 'value')
// 调用上传接口
const response = await axios.post(uploadUrl.value, formData, {
headers: {
'Content-Type': 'multipart/form-data', // 指定内容类型,
Authorization: 'Bearer ' + getToken()
}
})
// 处理接口响应
if (response.data.code === 200) {
ElMessage.success('导入成功')
selectedFile.value = null
// 重新获取表格数据
fetchTableData()
} else {
ElMessage.error(`导入失败: ${response.data.msg || '未知错误'}`)
// 如果有错误详情,可以展示
if (response.data.msg) {
console.error('导入错误详情:', response.data.msg)
}
}
} catch (error) {
console.error('上传失败:', error)
ElMessage.error('文件上传失败,请稍后重试')
} finally {
importLoading.value = false
}
})
.catch(() => {
// 用户取消导入
ElMessage.info('已取消导入')
})
}
// 下载模板
const downloadTemplate = () => {
// 下载地址
const templateUrl =
'https://yd-ali-oss.oss-cn-shanghai-finance-1-pub.aliyuncs.com/xlsx/2025/10/14/54ce715eabab4f1abd8652ba0fca0c51.xlsx'
// 修改下载文件名
const fileName = '保单导入模板.xlsx'
// 下载文件
window.open(templateUrl, '_blank', `download=${fileName}-${new Date().getTime()}`)
}
import { updateToPolicyLib } from '@/api/sign/underwritingMain'
// 处理更新至保单库
const handleUpdateToPolicyLib = () => {
ElMessageBox.confirm(
`确定要更新选中的 ${selectedRows.value.length} 条数据至保单库吗?`,
'更新确认',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
.then(() => {
// 调用更新至保单库接口
updateToPolicyLib({
policyNoList: selectedRows.value.map(row => row.policyNo)
}).then(response => {
if (response.code === 200) {
ElMessage.success('更新成功')
} else {
ElMessage.error(`更新失败: ${response.msg || '未知错误'}`)
}
})
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消更新至保单库'
})
})
}
// 格式化文件大小
const formatFileSize = bytes => {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}
// 新单跟进详情
const handleStatus = row => {
router.push({
path: '/sign/underwritingMain/followUpDetail',
query: {
policyBizId: row.policyBizId,
policyNo: row.policyNo,
type: 'edit',
source: 'policyList',
embed: true,
appointmentNo: row.appointmentNo,
appointmentBizId: row.appointmentBizId
}
})
}
const handleEditStatus = row => {
currentPolicyRow.value = JSON.parse(JSON.stringify(row))
editStatus.value = true
}
</script>
<style scoped>
.btnCon {
display: flex;
align-items: center;
justify-content: center;
}
.data-management-page {
padding: 20px;
/* max-width: 1600px; */
margin: 0 auto;
}
.page-header {
margin-bottom: 20px;
}
.search-card {
margin-bottom: 20px;
padding: 15px 20px;
}
.search-buttons {
display: flex;
gap: 10px;
}
.import-area {
margin-bottom: 20px;
}
.import-card {
padding: 10px;
background-color: #f6ffed;
border: 1px solid #b7eb8f;
}
.import-content {
display: flex;
flex-direction: column;
gap: 15px;
}
.import-actions {
display: flex;
align-items: center;
gap: 10px;
}
.upload-excel {
display: inline-block;
}
/* 文件信息显示样式 */
.file-info {
margin-top: 15px;
padding: 12px 16px;
background-color: #f5f7fa;
border-radius: 4px;
border: 1px solid #e4e7ed;
display: flex;
align-items: center;
justify-content: space-between;
}
.file-info-content {
display: flex;
align-items: center;
gap: 8px;
}
.file-info-content .el-icon {
color: #409eff;
font-size: 16px;
}
.file-name {
font-weight: 500;
color: #303133;
}
.file-size {
color: #909399;
font-size: 12px;
}
.confirm-import-btn {
margin-left: 12px;
}
/* 下载模板按钮样式 */
.download-template-btn {
color: #409eff;
font-size: 12px;
padding: 8px 12px;
}
.download-template-btn:hover {
background-color: #ecf5ff;
}
.table-card {
padding: 15px 20px;
}
.table-actions {
margin-bottom: 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.pagination {
margin-top: 15px;
text-align: right;
}
/* 禁用状态行样式 */
::v-deep .row-inactive {
background-color: #f5f5f5;
color: #9e9e9e;
}
.form-item {
display: flex;
flex-direction: column;
gap: 6px;
}
.form-label {
font-size: 14px;
color: #4e5969;
font-weight: 500;
line-height: 1;
padding-left: 2px;
}
.search-row {
margin-bottom: 18px;
}
.search-row:last-child {
margin-bottom: 0;
}
.search-buttons {
display: flex;
gap: 10px;
justify-content: flex-start;
align-items: flex-end;
padding-bottom: 2px;
}
.advanced-search {
margin-top: 18px;
border-top: 1px dashed #e5e7eb;
padding-top: 18px;
}
.el-collapse-item__content {
padding-top: 15px !important;
}
/* 转介人详情样式 */
.broker-details {
max-height: 200px;
overflow-y: auto;
}
.broker-item {
padding: 8px 0;
}
.broker-item p {
margin: 4px 0;
font-size: 12px;
line-height: 1.4;
}
.broker-item strong {
color: #606266;
}
.no-broker {
color: #909399;
font-size: 12px;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.import-actions {
flex-wrap: wrap;
}
.download-template-btn {
margin-top: 10px;
}
.file-info {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.confirm-import-btn {
margin-left: 0;
align-self: flex-end;
}
}
@media (max-width: 992px) {
.search-card .el-row {
row-gap: 15px;
}
.search-card .el-col {
flex: 0 0 50%;
max-width: 50%;
}
.search-buttons {
justify-content: flex-start;
}
}
@media (max-width: 768px) {
.search-card .el-col {
flex: 0 0 100%;
max-width: 100%;
}
.table-actions {
flex-direction: column;
align-items: flex-start;
gap: 10px;
}
.import-actions {
flex-direction: column;
align-items: flex-start;
}
.download-template-btn {
margin-top: 10px;
}
}
/* 防止表头换行 */
::v-deep .el-table .el-table__header-wrapper .el-table__cell {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</script>
/* 表头单元格内容不换行 */
::v-deep .el-table .el-table__header-wrapper .el-table__cell .cell {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
<style scoped></style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment