Commit 8fd3df19 by Sweet Zhang

对接接口,封装搜索组件

parent f97f6052
......@@ -290,3 +290,13 @@ export function policyNoCommissionPayRecord(data) {
data: data
})
}
// 应收款导出
export function exportReceivedFortune(data) {
return request({
url: '/csf/api/CommissionExpected/export',
method: 'post',
data: data,
responseType: 'blob'
})
}
......@@ -52,24 +52,3 @@ export function useDictLists(typeLists) {
})
})()
}
\ No newline at end of file
// /**
// * 获取字典数据
// */
// export function useDict(...args) {
// const res = ref({})
// return (() => {
// args.forEach((dictType, index) => {
// res.value[dictType] = []
// const dicts = useDictStore().getDict(dictType)
// if (dicts) {
// res.value[dictType] = dicts
// } else {
// getDicts(dictType).then(resp => {
// res.value[dictType] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass }))
// useDictStore().setDict(dictType, res.value[dictType])
// })
// }
// })
// return toRefs(res.value)
// })()
// }
......@@ -149,6 +149,7 @@ service.interceptors.response.use(
// 通用下载方法
export function download(url, params, filename, config) {
console.log(url, params, filename, config)
downloadLoadingInstance = ElLoading.service({
text: '正在下载数据,请稍候',
background: 'rgba(0, 0, 0, 0.7)'
......@@ -160,7 +161,7 @@ export function download(url, params, filename, config) {
return tansParams(params)
}
],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
headers: { 'Content-Type': 'application/json' },
responseType: 'blob',
...config
})
......
// utils/safeDownload.js
import { ElMessage } from 'element-plus'
/**
* 安全下载函数:适用于后端返回 Blob 文件流 或 JSON 错误 的场景
* @param {Blob} blobData - 接口返回的响应数据(必须是 responseType: 'blob')
* @param {string} defaultFilename - 默认文件名(如 'data.xlsx')
* @param {string} [mimeType] - MIME 类型(用于兜底创建 Blob)
*/
export async function safeDownload(blobData, defaultFilename, mimeType = 'application/octet-stream') {
if (!(blobData instanceof Blob)) {
ElMessage.error('无效的下载数据')
return
}
try {
// 👇 关键:先 peek 前 100 字节,判断是否是 JSON 错误
const firstChunk = await blobData.slice(0, 100).text()
const trimmed = firstChunk.trim()
// 如果看起来像 JSON(以 { 或 [ 开头),尝试解析
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
const fullText = await blobData.text()
let parsed
try {
parsed = JSON.parse(fullText)
} catch (e) {
// 解析失败,当作正常文件(比如内容就是纯文本)
parsed = null
}
// 如果解析成功,且包含错误字段(根据你后端约定)
if (parsed && (parsed.code !== undefined || parsed.msg || parsed.message)) {
const errorMsg = parsed.msg || parsed.message || '导出失败'
ElMessage.error(errorMsg)
return
}
}
// ✅ 是合法文件流,执行下载(使用你已验证的逻辑)
const url = window.URL.createObjectURL(blobData)
const link = document.createElement('a')
link.href = url
link.download = defaultFilename
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
window.URL.revokeObjectURL(url)
ElMessage.success('下载成功')
} catch (error) {
console.error('safeDownload error:', error)
ElMessage.error('下载过程中发生错误')
}
}
\ No newline at end of file
// dictUtils.js
import request from '@/utils/request'
// 全局缓存:key 为 dictType,value 为 { label: value } 映射对象
const dictCache = new Map()
// 批量加载字典(支持多个 type)
export async function loadDicts(typeList) {
// 过滤已缓存的类型,避免重复请求
const needLoadTypes = typeList.filter(type => !dictCache.has(type))
if (needLoadTypes.length === 0) return
try {
const res = await request({
url: '/user/api/sysDict/type/list', // 替换为你的实际接口地址
method: 'POST',
data: {
typeList: needLoadTypes
}
})
// 替换 loadDicts 中的缓存部分
if (res.code === 200 && Array.isArray(res.data)) {
for (const dict of res.data) {
const { dictType, dictItemList = [] } = dict
if (!dictType) continue
// 缓存完整列表(并可选排序 + 过滤)
const validItems = dictItemList
.filter(item => item.status === 1) // 只取启用的
.sort((a, b) => a.orderNum - b.orderNum) // 按序号排序
dictCache.set(dictType, validItems) // 👈 缓存完整 item 列表
}
}
} catch (error) {
console.error('字典加载失败:', error)
throw error
}
}
// 可选:提供清除缓存方法(用于权限切换等场景)
export function clearDictCache() {
dictCache.clear()
}
export function getDictOptions(dictType) {
const items = dictCache.get(dictType) || []
// console.log('getDictOptions',items)
return items.map(item => ({
value: item.itemValue,
label: item.itemLabel
// 如果需要,还可以加其他字段:disabled, key 等
}))
}
// 同时更新 getDictLabel
export function getDictLabel(dictType, value) {
const items = dictCache.get(dictType) || []
const item = items.find(i => i.itemValue === value)
return item ? item.itemLabel : value
}
\ No newline at end of file
......@@ -5,33 +5,7 @@
:page-size='pageSize' @size-change='handleSizeChange' @current-change='handleCurrentChange'>
<!-- 搜索区域 -->
<template #searchForm>
<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="转介人" label-position="top">
<el-select v-model="queryParams.broker" placeholder="请选择转介人" clearable :remote-method="loadBrokers"
:loading="searchLoading" filterable remote reserve-keyword>
<el-option v-for="item in brokerOptions" :key="item.userSaleBizId" :label="item.realName + '(' + item.phone + ')'"
:value="item.realName"/>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6">
<el-form-item label="出账日期" label-position="top">
<el-date-picker v-model="queryParams.accountDate" 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 label="出账状态" label-position="top">
<el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
<el-option v-for="item in dictLists" :key="item.itemValue" :label="item.itemLabel"
:value="item.itemValue" />
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<SearchForm ref="searchFormRef" :config="searchConfig" />
</template>
<!-- 列表区域 -->
<template #table>
......@@ -47,7 +21,7 @@
</el-row>
</div>
<el-table :data="tableData" @selection-change="handleSelectionChange" v-loading="loading" ref="tableRef"
row-key="fortuneAccountBizId" :reserve-selection="true" border="true">
row-key="fortuneAccountBizId" :reserve-selection="true" :border="true">
<el-table-column type="selection" width="55" :reserve-selection="true" />
<el-table-column prop="broker" label="转介人" min-width="120" sortable />
<el-table-column prop="team" label="所属团队" min-width="120" sortable />
......@@ -68,6 +42,7 @@
</el-tag>
</template>
</el-table-column>
<el-table-column prop="fortuneAccountDate" label="出账日" min-width="150" show-overflow-tooltip />
<el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip />
</el-table>
</template>
......@@ -107,10 +82,44 @@ import {
getReferrerFortuneList,
salaryStatistics,
} from '@/api/financial/commission'
import { searchIntermediaries } from '@/api/search'
// import { searchIntermediaries } from '@/api/search'
import { formatCurrency } from '@/utils/number'
import { debounce } from '@/utils/index';
import {ElMessageBox} from 'element-plus'
import { ElMessageBox } from 'element-plus'
import SearchForm from '@/components/SearchForm/SearchForm.vue'
const searchFormRef = ref(null)
const searchParams = ref({})
const searchConfig = ref([
{
type: 'select',
prop: 'brokerBizIdList',
label: '转介人',
api: '/insurance/base/api/userSaleExpand/page',
keywordField: 'realName',
requestParams: { pageNo: 1, pageSize: 20 },
placeholder: '输入转介人名称搜索',
debounceWait: 500, // 自定义防抖时间
valueKey: 'userSaleBizId',
labelKey: 'realName',
multiple: true,
transform: (res) => {
return res?.data.records || []
}
},
{
type: 'daterange',
prop: 'payoutDate',
label: '出账日(实)',
startPlaceholder: '开始时间',
endPlaceholder: '结束时间'
},
{
type: 'select',
prop: 'status',
label: '出账状态',
dictType: 'csf_fortune_account_status'
}
])
// 添加表格引用
const tableRef = ref()
// 存储所有选中的行数据(用于跨页保持选择)
......@@ -120,16 +129,7 @@ const statisticInfo = ref({
totalAmount: 0,
brokerCount: 0
})
// 查询参数
const queryParams = reactive({
broker: '',
accountDate: [],
accountDateStart: '',
accountDateEnd: '',
sortField: '',
sortOrder: 'desc',
status: '6'
})
// 表格数据
const tableData = ref([])
const loading = ref(false)
......@@ -221,16 +221,14 @@ const clearAllSelection = () => {
// 获取数据列表
const getList = async () => {
const getList = async (searchParams = {}) => {
loading.value = true
try {
if (queryParams.accountDate.length > 0) {
queryParams.accountDateStart = queryParams.accountDate[0]
queryParams.accountDateEnd = queryParams.accountDate[1]
}
const params = {
...queryParams,
accountDate:undefined,
...searchParams,
accountDateStart: searchParams.payoutDate?.[0] || undefined,
accountDateEnd: searchParams.payoutDate?.[1] || undefined,
payoutDate:undefined,
pageNo: currentPage.value,
pageSize: pageSize.value
}
......@@ -241,7 +239,7 @@ const getList = async () => {
pageTotal.value = response.data.page.total
loading.value = false
}
if (response.data.statisticsVO && isSearch.value) {
if (response.data.statisticsVO) {
statisticInfo.value = response.data.statisticsVO
}
// 数据加载完成后,设置当前页的选中状态
......@@ -266,32 +264,19 @@ const getStatusType = status => {
// 查询
const handleQuery = () => {
queryParams.pageNo = 1
Object.values(queryParams).some(value => {
if (Array.isArray(value) && value.length > 0) {
isSearch.value = true
}
if (value !== '' && value != null) {
isSearch.value = true
}
})
const params = searchFormRef.value.getSearchParams()
console.log('父组件发起查询:', params)
clearAllSelection()
getList()
getList(params)
}
// 重置查询
const handleReset = () => {
Object.assign(queryParams, {
broker: '',
accountDateStart: '',
accountDateEnd: '',
sortField: '',
sortOrder: 'desc'
})
isSearch.value = false
// 清空选择
clearAllSelection()
getList()
// 重置搜索表单
searchFormRef.value.resetForm()
searchParams.value = {}
console.log('表单已重置')
getList(searchParams.value)
}
// 选择行变化
......@@ -391,7 +376,7 @@ const fetchCompletePolicyFortune = async row => {
const searchLoading = ref(false)
const brokerOptions = ref([])
// 获取转介人列表
const loadBrokers = async (query='') => {
const loadBrokers = async (query = '') => {
searchLoading.value = true
const params = {
realName: query,
......@@ -399,18 +384,18 @@ const loadBrokers = async (query='') => {
pageSize: 1000,
}
try {
const res = await searchIntermediaries(params)
if (res.code === 200) {
brokerOptions.value = res.data.records || []
searchLoading.value = false
} else {
brokerOptions.value = []
searchLoading.value = false
}
// const res = await searchIntermediaries(params)
// if (res.code === 200) {
// brokerOptions.value = res.data.records || []
// searchLoading.value = false
// } else {
// brokerOptions.value = []
// searchLoading.value = false
// }
} catch (error) { }
}
debounce(loadBrokers, 500,false)
debounce(loadBrokers, 500, false)
const visibleDefaultButtons = ref(['reset', 'query'])
// 按钮配置
const operationBtnList = ref([
......
......@@ -64,20 +64,24 @@
</div>
<!-- 应付款管理列表 -->
<el-table :data="tableData" height="400" border highlight-current-row style="width: 100%" v-loading="loading">
<el-table-column prop="commissionBizType" label="应付款类型" width="120" fixed="left" sortable />
<el-table-column prop="payableNo" label="应付款编号" width="120" />
<el-table-column prop="policyNo" label="保单号" width="120" />
<el-table-column prop="fortuneBizType" label="应付款类型" width="120" fixed="left" sortable>
<template #default="{ row }">
{{ getFortuneBizTypeLabel(row.fortuneBizType) }}
</template>
</el-table-column>
<el-table-column prop="payableNo" label="应付款编号" width="120" sortable/>
<el-table-column prop="policyNo" label="保单号" width="120" sortable/>
<el-table-column prop="status" label="出账状态" width="120" sortable>
<template #default="{ row }">
<el-tag :type="row.status === '1' ? 'success' : 'warning'">
{{ row.status === '1' ? '已入账' : '待入账' }}
</el-tag>
{{ getDictLabel('csf_expected_fortune_status', row.status) }}
</template>
</el-table-column>
<el-table-column prop="currency" label="出账币种" width="120" sortable />
<el-table-column prop="fortunePeriod" label="出账期数" width="120" sortable />
<el-table-column prop="fortuneTotalPeriod" label="出账总期数" width="120" sortable />
<el-table-column prop="fortuneType" label="出账项目" width="120" sortable />
<el-table-column prop="fortuneName" label="出账项目" width="120" sortable />
<el-table-column prop="payoutDate" label="出账日(估)" width="120" sortable />
<el-table-column prop="actualPayoutDate" label="出账日(实)" width="120" sortable />
<el-table-column prop="commissionRatio" label="出账比例(估)" width="140" sortable>
<template #default="{ row }">
{{ (row.commissionRatio || 0) + '%' }}
......@@ -85,7 +89,7 @@
</el-table-column>
<el-table-column prop="amount" label="出账金额(估)" width="140" sortable>
<template #default="{ row }">
{{ formatCurrency(row.expectedAmount) }}
{{ formatCurrency(row.amount) }}
</template>
</el-table-column>
<el-table-column prop="paidRatio" label="已出账比例" width="120" sortable>
......@@ -153,6 +157,18 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import { formatCurrency } from '@/utils/number'
import { expectedFortuneList, payRecordList } from '@/api/financial/commission'
import SearchForm from '@/components/SearchForm/SearchForm.vue'
import {getDictLabel} from '@/utils/useDict';
// 应收单类型
const fortuneBizTypeOptions = [
{ value: 'R', label: '关联保单应付单' },
{ value: 'U', label: '非关联保单应付单' }
]
// 应付单类型通过value转成label
const getFortuneBizTypeLabel = (value) => {
const item = fortuneBizTypeOptions.find(item => item.value === value)
return item?.label || ''
}
const searchFormRef = ref(null)
const searchParams = ref({})
const searchConfig = ref([
......@@ -173,39 +189,22 @@ const searchConfig = ref([
prop: 'statusList',
label: '出账状态',
multiple: true,
options: [
{ value: '1', label: '启用' },
{ value: '0', label: '禁用' }
]
dictType: 'csf_expected_fortune_status'
},
{
type: 'input',
prop: 'fortunePeriod',
label: '出账期数'
label: '出账期数',
inputType: 'decimal',
rules: [
{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }
]
},
{
type: 'select',
prop: 'fortuneName',
label: '出账项目',
options: [
{ value: '1', label: '启用' },
{ value: '0', label: '禁用' }
]
},
{
type: 'select',
prop: 'insurerBizId',
label: '对账公司',
api: '/insurance/base/api/insuranceReconciliationCompany/page',
keywordField: 'name',
requestParams: { pageNo: 1, pageSize: 20 },
placeholder: '输入对账公司名称搜索',
debounceWait: 500, // 自定义防抖时间
valueKey: 'reconciliationCompanyBizId',
labelKey: 'name',
transform: (res) => {
return res?.data.records || []
}
dictType: 'csf_fortune_type'
},
{
type: 'select',
......@@ -219,6 +218,7 @@ const searchConfig = ref([
valueKey: 'insuranceCompanyBizId',
labelKey: 'abbreviation',
transform: (res) => {
console.log(res)
return res?.data.records || []
}
}, {
......@@ -227,7 +227,7 @@ const searchConfig = ref([
label: '产品计划',
api: '/product/api/relProjectProductLaunch/parameter/page',
keywordField: 'productName',
requestParams: { fieldBizId:'field_olk1qZe81qHHKXbw',fieldValueBizId:'field_value_uOfJH5ucA2YwJpbn',pageNo: 1, pageSize: 20 },
requestParams: { fieldBizId: 'field_olk1qZe81qHHKXbw', fieldValueBizId: 'field_value_uOfJH5ucA2YwJpbn', pageNo: 1, pageSize: 20 },
placeholder: '输入产品计划名称搜索',
debounceWait: 500, // 自定义防抖时间
valueKey: 'productLaunchBizId',
......@@ -353,14 +353,15 @@ const handleCurrentChange = (val) => {
}
// 加载表格数据
const loadTableData = async (searchParams={}) => {
const loadTableData = async (searchParams = {}) => {
console.log(searchFormRef.value)
loading.value = true
try {
const params = {
...searchParams,
payoutDateStart: searchParams.payoutDate?.[0] || undefined,
payoutDateEnd: searchParams.payoutDate?.[1] || undefined,
payoutDate:undefined,
payoutDate: undefined,
pageNo: currentPage.value,
pageSize: pageSize.value
}
......
......@@ -52,6 +52,17 @@ export default defineConfig(({ mode, command }) => {
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '')
},
'/csf': {
target: 'http://139.224.145.34:9002',
changeOrigin: true,
secure: false,
// 如果后端需要 host 头
// configure: (proxy, options) => {
// proxy.on('proxyReq', (proxyReq, req, res) => {
// proxyReq.setHeader('host', '139.224.145.34:9002')
// })
// }
},
// springdoc proxy
'^/v3/api-docs/(.*)': {
target: baseUrl,
......
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