Commit df8d349a by Sweet Zhang

页面对接

parent 8fd3df19
......@@ -256,7 +256,7 @@ export function expectedFortuneStatistics(data) {
data: data
})
}
// 入账记录查询
// 入账比对记录查询
export function commissionEntryRecord(data) {
return request({
url: '/csf/api/commission/compare/records',
......@@ -300,3 +300,12 @@ export function exportReceivedFortune(data) {
responseType: 'blob'
})
}
// 入账记录查询
export function commissionExpectedRecord(data) {
return request({
url: '/csf/api/commission/pageByCommissionexpectedBizId',
method: 'post',
data: data
})
}
......@@ -14,6 +14,7 @@
:headers="headers"
class="upload-file-uploader"
ref="fileUpload"
:drag="drag"
v-if="!disabled"
>
<!-- 上传按钮 -->
......
......@@ -54,8 +54,8 @@
<el-col :xs="24" :sm="12" :md="6" :lg="6" v-else-if="item.type === 'date'">
<el-form-item :label="item.label" :prop="item.prop">
<el-date-picker v-model="formModel[item.prop]" type="date"
:placeholder="item.placeholder || `请选择${item.label}`" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" style="width: 100%" clearable />
:placeholder="item.placeholder || `请选择${item.label}`" :format="item.format || 'YYYY-MM-DD'"
:value-format="item.valueFormat || 'YYYY-MM-DD'" style="width: 100%" clearable />
</el-form-item>
</el-col>
......@@ -69,6 +69,7 @@
value-format="YYYY-MM-DD" clearable />
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
......
<template>
<div class="financial-billing-page app-container">
<!-- 查询区域 -->
<el-card class="search-card">
<el-form :model="queryParams" label-width="80px">
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="保单号">
<el-input v-model="queryParams.policyNo" placeholder="请输入保单号" clearable />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="出账日期">
<el-date-picker
v-model="queryParams.billingDate"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<!-- 数据表格 -->
<el-card>
<el-row :gutter="20">
<el-text class="mx-1" type="danger" style="margin-right: 20px"
>勾选出账记录,点击“下载选中项”按钮,下载导入模版</el-text
>
</el-row>
<div class="button-row" style="display: flex; gap: 1rem; justify-content: end">
<el-button type="primary" :disabled="selectedRows.length === 0" @click="downloadSelected">
下载选中项
</el-button>
<FileUpload
:fileType="['xlsx', 'xls']"
:action="'/csf/api/fortune/upload/excel'"
:uploadBtnText="'批量导入'"
:isShowTip="false"
@uploadEnd="getUploadFileFunc"
:responseType="'onlyStatus'"
/>
<el-button
type="success"
:disabled="selectedRows.length === 0"
@click="generateBillingList"
>
生成出账清单
</el-button>
</div>
<div class="totalData" v-if="getAllSelectedRows().length > 0 || isSearch">
<span v-for="(item, index) in statisticList">
<span :style="{ marginLeft: index == 0 ? ' 0' : '20px' }">{{ item.name }}</span>
<span>{{ item.format ? formatCurrency(item.value) : item.value }}</span>
</span>
</div>
<el-table
:data="tableData"
@selection-change="handleSelectionChange"
v-loading="loading"
row-key="fortuneBizId"
:reserve-selection="true"
ref="tableRef"
>
<el-table-column type="selection" width="55" :reserve-selection="true" />
<el-table-column prop="policyNo" label="保单号" min-width="120" />
<el-table-column prop="commissionAmount" label="本次已来佣金额" width="150">
<template #default="{ row }">
{{ formatCurrency(row.commissionAmount) }}
</template>
</el-table-column>
<el-table-column prop="fortunePeriod" label="出账期数" width="100" />
<el-table-column prop="fortuneTotalPeriod" label="预计总期数" width="100" />
<el-table-column prop="fortuneName" label="出账项目" min-width="120" />
<el-table-column prop="broker" label="转介人" min-width="100" />
<el-table-column prop="team" label="所属团队" min-width="120" />
<el-table-column prop="amount" label="出账金额" width="120">
<template #default="{ row }">
{{ formatCurrency(row.amount) }}
</template>
</el-table-column>
<el-table-column prop="currency" label="出账币种" width="100" />
<el-table-column prop="status" label="出账状态" width="100">
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)">
{{ convertStatusToDict(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip />
<!-- <el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="handleEdit(row)">修改</el-button>
<el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
<el-button size="small" type="info" @click="handleView(row)">查看</el-button>
</template>
</el-table-column> -->
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="queryParams.pageNum"
v-model:page-size="queryParams.pageSize"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="getList"
@current-change="getList"
/>
</el-card>
<!-- 新建/编辑对话框 -->
<el-dialog :title="dialogTitle" v-model="dialogVisible" width="600px">
<el-form :model="formData" label-width="100px">
<el-form-item label="保单号" required>
<el-input v-model="formData.policyNo" />
</el-form-item>
<el-form-item label="对账公司" required>
<el-select v-model="formData.company">
<el-option
v-for="item in companyOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="出账期数" required>
<el-input-number v-model="formData.billingPeriod" :min="1" />
</el-form-item>
<el-form-item label="预计总期数" required>
<el-input-number v-model="formData.totalPeriods" :min="1" />
</el-form-item>
<el-form-item label="出账项目" required>
<el-input v-model="formData.billingItem" />
</el-form-item>
<el-form-item label="转介人">
<el-input v-model="formData.referrer" />
</el-form-item>
<el-form-item label="所属团队">
<el-input v-model="formData.team" />
</el-form-item>
<el-form-item label="出账金额" required>
<el-input-number v-model="formData.amount" :min="0" :precision="2" />
</el-form-item>
<el-form-item label="出账币种" required>
<el-select v-model="formData.currency">
<el-option label="人民币" value="CNY" />
<el-option label="美元" value="USD" />
<el-option label="港币" value="HKD" />
</el-select>
</el-form-item>
<el-form-item label="出账状态" required>
<el-select v-model="formData.status">
<el-option label="待出账" value="pending" />
<el-option label="已出账" value="completed" />
<el-option label="已取消" value="cancelled" />
</el-select>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="formData.remark" type="textarea" :rows="3" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确认</el-button>
<div class='container'>
<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>
<!-- 统计信息卡片 -->
<div class="statistics-container" v-if="statisticsData.totalPolicyCount > 0">
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">入账金额</div>
<div class="card-value">{{ statisticsData.totalInAmount }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">总保费数</div>
<div class="card-value">{{ formatCurrency(statisticsData.totalPremiumAmount) }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">总保费(HKD)</div>
<div class="card-value">{{ statisticsData.reconciliationCompanyCount }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">待出账金额</div>
<div class="card-value">{{ statisticsData.reconciliationRecordCount }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">可出账金额</div>
<div class="card-value">{{ statisticsData.reconciliationSuccessCount }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">差额(估)</div>
<div class="card-value">{{ formatCurrency(statisticsData.reconciliationFailureAmount) }}</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
<el-table :data="tableData" height="400" border highlight-current-row style="width: 100%" v-loading="loading">
<el-table-column prop="policyNo" label="保单号" width="120" sortable />
<el-table-column prop="reconciliationCompany" label="保险公司" width="120" sortable />
<el-table-column prop="payableNo" label="累积已入账金额" width="120" sortable />
<el-table-column prop="payableNo" label="累积已入账比例" width="120" sortable />
<el-table-column prop="payableNo" label="出账项目" width="130" sortable />
<el-table-column prop="payableNo" label="出账期数" width="130" sortable />
<el-table-column prop="payableNo" label="总期数" width="120" sortable />
<el-table-column prop="payableNo" label="转介人" width="130" sortable />
<el-table-column prop="currency" label="所属团队" width="120" sortable />
<el-table-column prop="payableNo" label="应出账金额" width="140" sortable />
<el-table-column prop="commissionPeriod" label="出账币种" width="130" sortable />
<el-table-column prop="totalPeriod" label="已出账金额" width="120" sortable />
<el-table-column prop="commissionName" label="剩余出账金额" width="120" sortable />
<el-table-column prop="premium" label="本期出账金额" width="120" sortable />
<el-table-column prop="remark" label="剩余出账比例" width="120" sortable />
<el-table-column prop="status" label="出账状态" width="120" sortable />
<el-table-column prop="status" label="期交保费" width="120" sortable />
<el-table-column prop="status" label="出账日(实)" width="120" sortable />
<el-table-column prop="status" label="备注" width="120" sortable />
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="{ row }">
<el-popover placement="right" :width="200" trigger="click">
<template #reference>
<el-icon>
<MoreFilled />
</el-icon>
</template>
<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>
<script setup>
import { ref, reactive, onMounted, nextTick } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
// 引入API
import {
getPolicyFortuneList,
downloadPolicyFortune,
downloadPolicyFortuneAccount,
billStatistics
} from '@/api/financial/commission'
// 添加表格引用
const tableRef = ref()
// 存储所有选中的行数据(用于跨页保持选择)
const allSelectedRows = ref(new Map())
const isSearch = ref(false)
const statisticList = ref([
{ name: '总出账金额', value: '0', key: 'totalOutAmount', format: true },
{ name: '总入账金额', value: '0', key: 'totalInAmount', format: true },
{ name: '总保单数', value: '0', key: 'totalPolicyCount', format: false }
])
// 查询参数
const queryParams = reactive({
policyNo: '',
company: '',
billingDate: [],
pageNum: 1,
pageSize: 100
// pageSize: 10
})
// 表格数据
const tableData = ref([])
const total = ref(0)
import { ref, reactive } from 'vue'
import CommonPage from '@/components/commonPage'
import CommonDialog from '@/components/commonDialog'
import SearchForm from '@/components/SearchForm/SearchForm.vue'
import { ElMessage } from 'element-plus'
import { formatCurrency } from '@/utils/number'
// 接口
import { getPolicyFortuneList } from '@/api/financial/commission'
// 分页相关
const currentPage = ref(1)
const pageSize = ref(10)
const pageTotal = ref(0)
const loading = ref(false)
const selectedRows = ref([])
// 对话框相关
const dialogVisible = ref(false)
const dialogTitle = ref('')
const formData = reactive({
policyNo: '',
company: '',
billingPeriod: 1,
totalPeriods: 1,
billingItem: '',
referrer: '',
team: '',
amount: 0,
currency: 'CNY',
status: 'pending',
remark: ''
})
// 设置当前页的选中状态
const setCurrentPageSelection = () => {
if (!tableRef.value) return
// 清除当前页的选择
// tableRef.value.clearSelection()
// 设置当前页应该选中的行
tableData.value.forEach(row => {
if (allSelectedRows.value.has(row.fortuneBizId)) {
tableRef.value.toggleRowSelection(row, true)
const searchFormRef = ref(null)
const searchParams = ref({})
const searchConfig = ref([
{
type: 'input',
prop: 'policyNo',
label: '保单号'
}, {
type: 'select',
prop: 'status',
label: '入账状态',
multiple: true,
dictType: 'csf_expected_commission_status'
}, {
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',
transform: (res) => {
console.log(res)
return res?.data.records || []
}
})
}
// 获取所有选中的行(包含跨页选择的)
const getAllSelectedRows = () => {
return Array.from(allSelectedRows.value.values())
}
// 更新全局选中状态
const updateAllSelectedRows = () => {
// 获取当前页的所有行的 key(fortuneBizId)
const currentPageKeys = tableData.value.map(row => row.fortuneBizId)
// 从全局选中中移除当前页不再存在的行
// for (const key of allSelectedRows.value.keys()) {
// if (!currentPageKeys.includes(key)) {
// allSelectedRows.value.delete(key)
// }
// }
// 更新当前页的选中状态
tableData.value.forEach(row => {
const isSelected = selectedRows.value.some(
selectedRow => selectedRow.fortuneBizId === row.fortuneBizId
)
if (isSelected) {
allSelectedRows.value.set(row.fortuneBizId, row)
} else {
allSelectedRows.value.delete(row.fortuneBizId)
}, {
type: 'select',
prop: 'productLaunchBizIdList',
label: '产品计划',
api: '/product/api/relProjectProductLaunch/parameter/page',
keywordField: 'productName',
requestParams: { fieldBizId: 'field_olk1qZe81qHHKXbw', fieldValueBizId: 'field_value_uOfJH5ucA2YwJpbn', pageNo: 1, pageSize: 20 },
placeholder: '输入产品计划名称搜索',
debounceWait: 500, // 自定义防抖时间
valueKey: 'productLaunchBizId',
labelKey: 'productName',
transform: (res) => {
return res?.data.records || []
}
})
// 当勾选项发生变化的时候,拿到最新的统计数据
getStatistics()
}, {
type: 'daterange',
prop: 'payoutDate',
label: '出账日(估)',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间'
}, {
type: 'select',
prop: 'status',
label: '出账状态',
multiple: true,
dictType: 'csf_fortune_status'
},
])
// 表格操作菜单
const dropdownItems = [
{ label: '设置本期出账金额', value: 'setPayRoll' },
{ label: '更新', value: 'editRecord' },
{ label: '查看记录', value: 'viewRecord' }
]
// 统计信息
const statisticsData = ref({})
// 弹窗相关
const dialogFlag = ref(false)
// 按钮事件处理
const handleAdd = () => {
ElMessage.info('点击新增按钮')
}
const getStatistics = async () => {
try {
let fortuneIdList = getAllSelectedRows().map(item => item.id)
if (fortuneIdList.length > 0) {
// 调用接口获取来佣列表
const res = await billStatistics({
fortuneIdList: fortuneIdList
})
if (res.data) {
statisticList.value.forEach(item => {
item.value = res.data[item.key]
})
}
} else {
isSearch.value = false
}
} catch (error) {
console.error('获取数据失败:', error)
ElMessage.error('统计失败')
}
const handleImport = () => {
ElMessage.info('点击导入按钮')
}
// 清空所有选择
const clearAllSelection = () => {
allSelectedRows.value.clear()
selectedRows.value = []
if (tableRef.value) {
tableRef.value.clearSelection()
}
const handleExport = () => {
ElMessage.info('点击导出按钮')
}
// 下载选中项
const downloadSelected = async () => {
if (selectedRows.value.length === 0) {
ElMessage.warning('请选择要下载的项')
return
}
try {
// API调用
const response = await downloadPolicyFortune({
fortuneBizIdList: selectedRows.value.map(row => row.fortuneBizId)
})
if (response) {
ElMessage.success('下载成功')
// 触发文件下载
// 处理下载响应
const blob =
response instanceof Blob
? response
: new Blob([response], { type: 'application/vnd.ms-excel;charset=utf-8' })
// 创建Blob对象,指定正确的MIME类型
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
// 不需要指定文件名,浏览器会自动使用默认文件名
link.download = `出账管理_${new Date().getTime()}.xlsx`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
} else {
ElMessage.error('下载失败')
}
} catch (error) {
ElMessage.error('下载失败')
}
const handleReset = () => {
// 重置搜索表单
searchFormRef.value.resetForm()
searchParams.value = {}
console.log('表单已重置')
}
const getUploadFileFunc = data => {
console.log(data)
if (data === 200) {
ElMessage.success('上传成功')
getList()
} else {
ElMessage.error('上传失败')
}
const handleQuery = async () => {
const params = searchFormRef.value.getSearchParams()
console.log('父组件发起查询:', params)
loadTableData(params)
}
// 获取数据列表
const getList = async () => {
const visibleDefaultButtons = ref(['add', 'import', 'export', 'reset', 'query'])
// 按钮配置
const operationBtnList = ref([
{
key: 'add',
direction: 'left',
label: '新增出账',
click: handleAdd
}, {
key: 'import',
direction: 'left',
label: '导入出账',
click: handleImport
},
{
key: 'export',
direction: 'right',
click: handleExport
},
{
key: 'reset',
direction: 'right',
click: handleReset
},
{
key: 'query',
direction: 'right',
click: handleQuery
}
])
// 加载表格数据
const loadTableData = async (searchParams = {}) => {
loading.value = true
try {
// API调用
const response = await getPolicyFortuneList(queryParams)
if (response.data.page) {
tableData.value = response.data.page.records
total.value = response.data.page.total
loading.value = false
}
if (response.data.statisticsVO && isSearch.value) {
statisticList.value.forEach(item => {
item.value = response.data.statisticsVO[item.key]
})
const params = {
pageNo: currentPage.value,
pageSize: pageSize.value,
...searchParams,
payoutDateStart: searchParams.payoutDate?.[0] || undefined,
payoutDateEnd: searchParams.payoutDate?.[1] || undefined,
payoutDate: undefined
}
// 数据加载完成后,设置当前页的选中状态
nextTick(() => {
setCurrentPageSelection()
})
const res = await getPolicyFortuneList(params)
tableData.value = res.data.page.records || []
pageTotal.value = res.data.page.total || 0
pageSize.value = res.data.page.size || 0
// 统计信息
statisticsData.value = res.data.statisticsVO || {}
} catch (error) {
console.error('加载数据失败:', error)
ElMessage.error(error.message || '加载数据失败')
} finally {
loading.value = false
tableData.value = []
console.log('获取列表失败', error)
// ElMessage.error('获取数据失败')
}
}
// 查询
const handleQuery = () => {
queryParams.pageNum = 1
Object.values(queryParams).some(value => {
if (Array.isArray(value) && value.length > 0) {
isSearch.value = true
}
if (value !== '' && value != null) {
isSearch.value = true
}
})
clearAllSelection()
getList()
}
// 重置查询
const resetQuery = () => {
Object.assign(queryParams, {
policyNo: '',
company: '',
billingDate: [],
pageNum: 1,
pageSize: 100
})
isSearch.value = false
// 清空选择
clearAllSelection()
getList()
}
// 选择行变化
const handleSelectionChange = selection => {
selectedRows.value = selection
updateAllSelectedRows()
}
// 新建出账记录
const handleCreate = () => {
dialogTitle.value = '新建出账记录'
Object.assign(formData, {
policyNo: '',
company: '',
billingPeriod: 1,
totalPeriods: 1,
billingItem: '',
referrer: '',
team: '',
amount: 0,
currency: 'CNY',
status: 'pending',
remark: ''
})
dialogVisible.value = true
}
// 编辑出账记录
const handleEdit = row => {
dialogTitle.value = '编辑出账记录'
Object.assign(formData, { ...row })
dialogVisible.value = true
}
// 删除出账记录
const handleDelete = async row => {
try {
await ElMessageBox.confirm('确认删除这条出账记录吗?', '提示', {
type: 'warning'
})
// await api.deleteBilling(row.id)
ElMessage.success('删除成功')
getList()
} catch (error) {
if (error !== 'cancel') {
ElMessage.error('删除失败')
}
}
}
// 查看详情
const handleView = row => {
// 这里可以跳转到详情页面或者打开详情对话框
ElMessage.info(`查看保单号:${row.policyNo}`)
loadTableData()
// 分页事件
const handleSizeChange = (val) => {
pageSize.value = val
loadTableData()
}
const generateBillingList = async () => {
if (selectedRows.value.length === 0) {
ElMessage.warning('请先选择要生成清单的记录')
return
}
ElMessageBox.confirm(`确认生成 ${selectedRows.value.length} 条记录的出账清单吗?`, '提示', {
type: 'warning'
})
.then(async () => {
console.log('开始生成出账清单')
const response = await downloadPolicyFortuneAccount({
fortuneBizIdList: selectedRows.value.map(item => item.fortuneBizId)
})
console.log(response)
// 调用下载API
if (response) {
// 处理下载响应
const blob =
response instanceof Blob
? response
: new Blob([response], { type: 'application/vnd.ms-excel;charset=utf-8' })
// 创建Blob对象,指定正确的MIME类型
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
// 不需要指定文件名,浏览器会自动使用默认文件名
link.download = `出账清单_${new Date().getTime()}.xlsx`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
} else {
ElMessage.error('下载失败')
}
selectedRows.value = []
})
.catch(error => {
if (error !== 'cancel') {
console.log('生成出账清单出错:', error)
}
})
const handleCurrentChange = (val) => {
currentPage.value = val
loadTableData()
}
// 表格数据
const tableData = ref([])
// 提交表单
const submitForm = async () => {
try {
// 表单验证
if (!formData.policyNo || !formData.company || !formData.billingItem) {
ElMessage.warning('请填写必填字段')
return
}
// 调用保存API
// if (formData.id) {
// await api.updateBilling(formData)
// } else {
// await api.createBilling(formData)
// }
ElMessage.success('保存成功')
dialogVisible.value = false
getList()
} catch (error) {
ElMessage.error('保存失败')
}
const handleSelect = (row) => {
console.log('选中行:', row)
}
// 格式化金额
const formatCurrency = amount => {
return new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: 'CNY'
}).format(amount)
}
// 获取状态标签类型
const getStatusType = status => {
const types = {
0: 'warning',
1: 'success',
2: 'info'
}
return types[status] || 'info'
}
import { listType } from '@/api/system/dict/type'
const dictLists = ref([])
// 获取出账状态字典值
const getDictLists = () => {
return new Promise((resolve, reject) => {
listType({ typeList: ['csf_fortune_status'] })
.then(res => {
if (res.code === 200 && res.data) {
const dictData = res.data.find(item => item.dictType === 'csf_fortune_status')
dictLists.value = dictData?.dictItemList || []
console.log('获取到的字典数据:', dictLists.value)
resolve(dictLists.value)
} else {
dictLists.value = []
resolve([])
}
})
.catch(error => {
console.error('获取状态列表失败:', error)
dictLists.value = []
reject(error)
})
})
}
// 返回数据中状态需要转换为字典值
const convertStatusToDict = status => {
const dictItem = dictLists.value.find(item => item.itemValue == status)
return dictItem?.itemLabel ?? status
}
// 初始化
onMounted(() => {
getDictLists()
getList()
})
</script>
<style scoped>
.totalData {
margin-bottom: 10px;
font-size: 14px;
color: #000;
}
.financial-billing-page {
padding: 20px;
}
.search-card {
margin-bottom: 20px;
}
.operation-card {
margin-bottom: 20px;
}
.el-table {
margin-bottom: 20px;
}
.el-pagination {
justify-content: flex-end;
margin-top: 20px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.financial-billing-page {
padding: 10px;
}
.search-card {
margin-bottom: 15px;
}
.operation-card {
margin-bottom: 15px;
}
.el-col {
margin-bottom: 10px;
}
}
</style>
<style scoped></style>
\ No newline at end of file
<template>
<div class='container'>
<CommonPage :operationBtnList='operationBtnList' :showSearchForm='true' :show-pagination='true' :total='pageTotal'
:current-page='currentPage' :page-size='pageSize' @size-change='handleSizeChange'
@current-change='handleCurrentChange'>
<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" v-model="searchFormData" :fields="searchFields" label-position="top"
:label-width="null" :inline="false" :gutter="20" class="custom-search-form" />
<SearchForm ref="searchFormRef" :config="searchConfig" />
</template>
<!-- 列表区域 -->
<template #table>
<!-- 统计信息卡片 -->
<div class="statistics-container" v-if="statisticsData.totalPolicyCount > 0">
<el-row :gutter="20">
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">总保单数</div>
<div class="card-value">{{ statisticsData.totalPolicyCount }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">总保费(HKD)</div>
<div class="card-value">{{ formatCurrency(statisticsData.totalPremium) }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">对账公司数</div>
<div class="card-value">{{ statisticsData.reconciliationCompanyCount }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">比对记录总条数</div>
<div class="card-value">{{ statisticsData.totalCompareCommissionCount }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">比对成功数</div>
<div class="card-value">{{ statisticsData.successCompareCommissionCount }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">比对失败数</div>
<div class="card-value">{{ statisticsData.failedCompareCommissionCount }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">入账金额(实)</div>
<div class="card-value">{{ formatCurrency(statisticsData.totalPaidAmount) }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">入账金额(估)</div>
<div class="card-value">{{ formatCurrency(statisticsData.expectePaidAmount) }}</div>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="12" :md="4" :lg="4">
<el-card shadow="hover" class="statistics-card">
<div class="card-content">
<div class="card-label">差额(估)</div>
<div class="card-value">{{ formatCurrency(statisticsData.differenceAmount) }}</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
<el-table :data="tableData" ref="multipleTableRef" height="400" row-key="id" border highlight-current-row
style="width: 100%" v-loading="loading" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="40" />
<el-table-column prop="reconciliationYearMonth" label="检核年月" width="120" sortable />
<el-table-column prop="policyNo" label="保单号" width="120" sortable />
<el-table-column prop="reconciliationCompany" label="对账公司" width="120" sortable />
<el-table-column prop="commissionDate" label="入账日" width="120" sortable />
<el-table-column prop="status" label="比对状态" width="120" sortable />
<el-table-column prop="currentCommissionRatio" label="本次入账比例" width="130" sortable />
<el-table-column prop="periodPaidRatio" label="累积入账比例" width="130" sortable />
<el-table-column prop="periodPendingRatio" label="待入账比例" width="120" sortable />
<el-table-column prop="paidAmount" label="本次入账金额" width="130" sortable />
<el-table-column prop="currency" label="入账币种" width="120" sortable />
<el-table-column prop="exchangeRate" label="结算汇率(实)" width="140" sortable />
<el-table-column prop="commissionPeriod" label="本次入账期数" width="130" sortable />
<el-table-column prop="totalPeriod" label="总期数" width="120" sortable />
<el-table-column prop="commissionName" label="入账项目" width="120" sortable />
<el-table-column prop="premium" label="期交保费" width="120" sortable />
<el-table-column prop="remark" label="备注" width="120" sortable />
<el-table-column prop="status" label="记录状态" width="120" sortable />
<el-table-column fixed="right" label="操作" min-width="120">
<template #default="{ row }">
<el-popover placement="right" :width="200" trigger="click">
<template #reference>
<el-icon>
<MoreFilled />
</el-icon>
</template>
<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>
<!-- 表格操作菜单 -->
<div class="tableOptionContainer">
<el-button type="primary" :icon="Select">生成可出账记录</el-button>
</div>
</template>
</CommonPage>
<!-- 弹窗-->
<CommonDialog dialogTitle='弹窗' dialogWidth='80%' :openDialog=dialogFlag :showAction='false' :showClose='true'
<!-- 开始检核弹窗-->
<CommonDialog dialogTitle='开始检核' dialogWidth='80%' :openDialog=dialogFlag :showAction='true' :showClose='true'
@close='dialogFlag = false'>
<el-row>
<el-col :xs="24" :sm="24" :md="24" :lg="24">
<SearchForm ref="checkFormRef" :config="checkConfig" />
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :xs="24" :sm="12" :md="3" :lg="3">
<el-button type="primary" :icon="Plus" :disabled="!checkFormRef?.getSearchParams().reconciliationYearMonth"
@click="addCheckRecordDialogFlag = true">新增</el-button>
</el-col>
<el-col :xs="24" :sm="24" :md="3" :lg="3">
<el-button type="primary" :icon="Upload" :disabled="!checkFormRef?.getSearchParams().reconciliationYearMonth"
@click="fileUploadDialogFlag = true">导入</el-button>
</el-col>
<el-col :xs="24" :sm="24" :md="3" :lg="3">
<el-button link type="primary">下载导入模板 </el-button>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :xs="24" :sm="24" :md="24" :lg="24">
<el-table :data="checkRecordTableData" style="width: 100%">
<el-table-column prop="name" label="应收款类型" width="120" />
<el-table-column prop="state" label="应收款编号" width="120" />
<el-table-column prop="city" label="关联保单号" width="120" />
<el-table-column prop="address" label="佣金期数" width="120" />
<el-table-column prop="zip" label="总期数" width="120" />
<el-table-column prop="zip" label="入账日(估)" width="120" />
<el-table-column prop="zip" label="入账日(实)" width="120" />
<el-table-column prop="zip" label="入账金额" width="120" />
<el-table-column prop="zip" label="入账币种" width="120" />
<el-table-column prop="zip" label="入账项目" width="120" />
<el-table-column prop="zip" label="对账公司" width="120" />
<el-table-column prop="zip" label="入账状态" width="120" />
<el-table-column fixed="right" label="操作" min-width="120">
<template #default>
<el-button link type="primary" size="small" @click="checkRecordEdit(row)">
修改
</el-button>
<el-button link type="primary" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</CommonDialog>
<!-- 新增检核记录弹窗 -->
<CommonDialog dialogTitle='新增检核记录' dialogWidth='80%' :openDialog=addCheckRecordDialogFlag :showAction='true'
:showClose='true' @close='addCheckRecordDialogFlag = false'>
<el-row>
<el-col :xs="24" :sm="24" :md="24" :lg="24">
<SearchForm ref="addCheckRecordFormRef" :config="addCheckRecordConfig" />
</el-col>
</el-row>
</CommonDialog>
<CommonDialog dialogTitle='文件导入' dialogWidth='80%' :openDialog=fileUploadDialogFlag :showAction='true'
:showClose='true' @close='fileUploadDialogFlag = false'>
<FileUpload
v-model="files"
:data="{ reconciliationYearMonth: checkFormRef?.getSearchParams().reconciliationYearMonth }" :file-type="['xlsx','xls']"
:action="'/csf/api/commission/upload/excel'" :limit="1"
/>
</CommonDialog>
</div>
</template>
......@@ -25,26 +216,227 @@
import { ref, reactive } from 'vue'
import CommonPage from '@/components/commonPage'
import CommonDialog from '@/components/commonDialog'
import SearchForm from '@/components/searchForm'
import SearchForm from '@/components/SearchForm/SearchForm.vue'
import { ElMessage } from 'element-plus'
import { formatCurrency } from '@/utils/number'
// 接口
import { getPolicyCommissionList } from '@/api/financial/commission'
import { Plus, Upload } from '@element-plus/icons-vue'
import FileUpload from '@/components/FileUpload/index.vue'
// 分页相关
const currentPage = ref(1)
const pageSize = ref(10)
const pageTotal = ref(0)
const loading = ref(false)
// 搜索表单数据
const searchFormData = reactive({
const searchFormRef = ref(null)
const searchParams = ref({})
const searchConfig = ref([
{
type: 'input',
prop: 'policyNo',
label: '保单号'
}, {
type: 'select',
prop: 'statusList',
label: '比对状态',
multiple: true,
dictType: 'csf_commission_status'
}, {
type: 'select',
prop: 'reconciliationCompanyBizIdList',
label: '对账公司',
api: '/insurance/base/api/insuranceReconciliationCompany/page',
keywordField: 'name',
requestParams: { pageNo: 1, pageSize: 20 },
placeholder: '输入对账公司名称搜索',
debounceWait: 500, // 自定义防抖时间
multiple: true,
valueKey: 'reconciliationCompanyBizId',
labelKey: 'name',
transform: (res) => {
console.log(res)
return res?.data.records || []
}
}, {
type: 'date',
prop: 'expectedDate',
label: '入账日(估)',
placeholder: '请选择'
}, {
type: 'daterange',
prop: 'commissionDate',
label: '入账日(实)',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间'
}, {
type: 'select',
prop: 'insurerBizId',
label: '保险公司',
api: '/insurance/base/api/insuranceCompany/page',
keywordField: 'queryContent',
requestParams: { pageNo: 1, pageSize: 20 },
placeholder: '输入保险公司名称搜索',
debounceWait: 500, // 自定义防抖时间
valueKey: 'insuranceCompanyBizId',
labelKey: 'abbreviation',
transform: (res) => {
console.log(res)
return res?.data.records || []
}
}, {
type: 'date',
prop: 'reconciliationYearMonth',
label: '检核年月',
placeholder: '检核年月',
format: 'YYYY-MM',
valueFormat: 'YYYY-MM'
}
])
const fileUploadDialogFlag = ref(false)
const checkRecordTableData = ref([])
// 检核表单
const checkFormRef = ref(null)
const checkConfig = ref([
{
type: 'date',
prop: 'reconciliationYearMonth',
label: '检核年月',
placeholder: '检核年月',
format: 'YYYY-MM',
valueFormat: 'YYYY-MM',
rules: [{ required: true, message: '请选择检核年月', trigger: 'blur' }]
}
])
const checkRecordEdit = (row) => {
console.log(row)
}
// 应收单类型
const commissionBizTypeOptions = [
{ value: 'R', label: '关联保单应收单' },
{ value: 'U', label: '非关联保单应收单' }
]
// 应收单类型通过value转成label
const getCommissionBizTypeLabel = (value) => {
const item = commissionBizTypeOptions.find(item => item.value === value)
return item?.label || ''
}
// 新增检核记录表单
const addCheckRecordFormRef = ref(null)
const addCheckRecordConfig = ref([
{
type: 'select',
prop: 'reconciliationYearMonth',
label: '应收单类型',
placeholder: '应收单类型',
options: commissionBizTypeOptions
},
{
type: 'input',
prop: 'policyNo',
label: '保单号'
},
{
type: 'input',
prop: 'fortunePeriod',
label: '佣金期数',
inputType: 'decimal',
rules: [
{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }
]
}, {
type: 'input',
prop: 'fortunePeriod',
label: '总期数',
inputType: 'decimal',
rules: [
{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }
]
}, {
type: 'date',
prop: 'expectedDate',
label: '入账日(估)',
placeholder: '请选择'
}, {
type: 'date',
prop: 'expectedDate',
label: '入账日(实)',
placeholder: '请选择'
}, {
type: 'input',
prop: 'fortunePeriod',
label: '入账金额',
inputType: 'decimal',
rules: [
{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }
]
}, {
type: 'select',
prop: 'statusList',
label: '入账币种',
multiple: true,
dictType: 'csf_expected_fortune_status'
}, {
type: 'select',
prop: 'fortuneName',
label: '入账项目',
dictType: 'csf_commission_type'
}, {
type: 'select',
prop: 'reconciliationCompanyBizIdList',
label: '对账公司',
api: '/insurance/base/api/insuranceReconciliationCompany/page',
keywordField: 'name',
requestParams: { pageNo: 1, pageSize: 20 },
placeholder: '输入对账公司名称搜索',
debounceWait: 500, // 自定义防抖时间
multiple: true,
valueKey: 'reconciliationCompanyBizId',
labelKey: 'name',
transform: (res) => {
console.log(res)
return res?.data.records || []
}
}, {
type: 'select',
prop: 'statusList',
label: '入账状态',
multiple: true,
dictType: 'csf_expected_commission_status'
},
])
const addCheckRecordDialogFlag = ref(false)
// 表格操作菜单
const dropdownItems = [
{ label: '设置比对状态', value: 'setStatus' },
{ label: '更新', value: 'editRecord' },
{ label: '查看记录', value: 'viewRecord' },
{ label: '更新数据', value: 'updateData' },
]
// 统计信息
const statisticsData = ref({
paidAmountRatio: 0,
pendingPaidAmount: 0,
totalAmount: 0,
totalPaidAmount: 0,
totalPolicyCount: 0
})
// 弹窗相关
const dialogFlag = ref(false)
// 按钮事件处理
const handleAdd = () => {
ElMessage.info('点击新增按钮')
// ElMessage.info('点击新增按钮')
dialogFlag.value = true
}
const handleImport = () => {
ElMessage.info('点击导入按钮')
......@@ -54,33 +446,31 @@ const handleExport = () => {
}
const handleReset = () => {
// 重置搜索表单
Object.keys(searchFormData).forEach(key => {
if (Array.isArray(searchFormData[key])) {
searchFormData[key] = []
} else {
searchFormData[key] = ''
}
})
ElMessage.success('搜索条件已重置')
// 重新加载数据
loadTableData()
searchFormRef.value.resetForm()
searchParams.value = {}
console.log('表单已重置')
}
const handleQuery = async () => {
loadTableData()
const params = searchFormRef.value.getSearchParams()
console.log('父组件发起查询:', params)
loadTableData(params)
}
const multipleSelection = ref([])
const handleSelectionChange = (val) => {
multipleSelection.value = val
console.log('全选:', val)
}
const visibleDefaultButtons = ref(['add', 'export', 'reset', 'query'])
// 按钮配置
const operationBtnList = ref([
{
key: 'add',
direction: 'left',
label: '开始检核',
click: handleAdd
},
{
key: 'import',
direction: 'left',
click: handleImport
},
{
key: 'export',
direction: 'right',
click: handleExport
......@@ -98,27 +488,30 @@ const operationBtnList = ref([
])
// 加载表格数据
const loadTableData = async () => {
const loadTableData = async (searchParams = {}) => {
loading.value = true
try {
const res = await getPolicyCommissionList({
const params = {
pageNo: currentPage.value,
pageSize: pageSize.value,
...searchFormData
})
if (res.code === 200) {
tableData.value = res.data.records || []
pageTotal.value = res.data.total || 0
} else {
ElMessage.error(res.msg || '加载数据失败')
...searchParams,
commissionDateStart: searchParams.commissionDate?.[0] || undefined,
commissionDateEnd: searchParams.commissionDate?.[1] || undefined
}
const res = await getPolicyCommissionList(params)
tableData.value = res.data.page.records || []
pageTotal.value = res.data.page.total || 0
pageSize.value = res.data.page.size || 0
// 统计信息
statisticsData.value = res.data.commissionStatisticsVO || {}
} catch (error) {
console.error('加载数据失败:', error)
ElMessage.error(error.message || '加载数据失败')
} finally {
loading.value = false
}
}
loadTableData()
// 分页事件
const handleSizeChange = (val) => {
pageSize.value = val
......@@ -131,67 +524,21 @@ const handleCurrentChange = (val) => {
// 表格数据
const tableData = ref([])
// 搜索表单字段
const searchFields = ref([
{
type: 'input',
field: 'policyNo',
label: '保单号',
placeholder: '请输入保单号',
colSpan: 6,
clearable: true,
rules: [
{ max: 50, message: '保单号长度不能超过50个字符', trigger: 'blur' }
]
},
{
type: 'select',
field: 'status',
label: '比对状态',
placeholder: '请选择比对状态',
colSpan: 6,
options: [
{ label: '已比对', value: '1' },
{ label: '部分来佣', value: '0' },
{ label: '部分入账', value: '2' }
]
},
{
type: 'select',
field: 'reconciliationCompany',
label: '对账公司',
placeholder: '请输入关键词搜索',
colSpan: 6,
remoteConfig: {
type: 'company',
defaultOptions: []
}
},
{
type: 'date',
field: 'expectedDate',
label: '预计入账日',
placeholder: '请选择预计入账日',
colSpan: 6,
},
{
type: 'input',
field: 'insurerBizId',
label: '保险公司',
placeholder: '请输入关键词搜索保险公司',
colSpan: 6,
},
{
type: 'date',
field: 'productLaunchBizId',
label: '检核年月',
placeholder: '请选择检核年月',
colSpan: 6,
}
])
const handleSelect = (row) => {
console.log('选中行:', row)
}
</script>
<style scoped></style>
\ No newline at end of file
<style scoped>
.tableOptionContainer {
display: flex;
justify-content: flex-end;
margin-top: 10px;
}
.el-row {
margin-bottom: 10px;
}
</style>
\ No newline at end of file
......@@ -163,7 +163,7 @@ import CommonDialog from '@/components/commonDialog'
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { MoreFilled } from '@element-plus/icons-vue'
import { receivedFortuneList, commissionEntryRecord, commissionEntryEditRecords, exportReceivedFortune } from '@/api/financial/commission'
import { receivedFortuneList, commissionEntryRecord, commissionEntryEditRecords, exportReceivedFortune, commissionExpectedRecord } from '@/api/financial/commission'
import { numberWithCommas } from '@/utils/index'
import SearchForm from '@/components/SearchForm/SearchForm.vue'
import { getDictLabel } from '@/utils/useDict';
......@@ -417,8 +417,8 @@ const loadTableData = async (searchParams = {}) => {
const loadEntryRecordData = async (cbd) => {
loading.value = true
try {
const params = { commissionBizId: cbd }
const response = await commissionEntryRecord(params)
const params = { commissionExpectedBizId: cbd }
const response = await commissionExpectedRecord(params)
return response.data.records || []
} catch (error) {
console.error('加载入账记录失败:', error)
......@@ -451,27 +451,19 @@ const handleSelect = async (e, row) => {
if (e === 'entryRecord') {
entryRecordDialogTableVisible.value = true
entryRecordDialogTableColumns.value = [
{ property: 'reconciliationYearMonth', label: '检核年月', width: '100' },
{ property: 'commissionPeriod', label: '佣金期数', width: '100' },
{ property: 'totalPeriod', label: '总期数', width: '150' },
{ property: 'exchangeRate', label: '结算汇率(实)', width: '150' },
{ property: 'currency', label: '入账币种', width: '150' },
{ property: 'amount', label: '入账金额', width: '150' },
{ property: 'commissionRatio', label: '入账比例', width: '150' },
{ property: 'currentCommissionRatio', label: '入账比例', width: '150' },
{ property: 'commissionDate', label: '入账日', width: '150' },
{ property: 'status', label: '入账状态', width: '150' }
]
// 加载真实数据
const records = await loadEntryRecordData(row.commissionExpectedBizId)
entryRecordDialogTableData.value = records.length ? records : [{
commissionPeriod: '2023-08',
totalPeriod: '10',
exchangeRate: '1.2345',
currency: 'CNY',
amount: '10000.00',
commissionRatio: '10%',
commissionDate: '2023-08-01',
status: '已入账'
}]
entryRecordDialogTableData.value = records.length ? records : []
} else if (e === 'setStatus') {
// 回显当前行状态
form.status = row.status
......
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