Commit b60297ec by yuzhenWang

Merge branch 'wyz' into 'test'

按需求修改

See merge request !144
parents 8367be89 2b3989c6
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -273,7 +273,7 @@ ...@@ -273,7 +273,7 @@
</CommonDialog> </CommonDialog>
<!-- 设置出账年月弹窗 --> <!-- 设置出账年月弹窗 -->
<CommonDialog <CommonDialog
dialogTitle="设置本期出账金额" dialogTitle="设置本期出账年月(实)"
dialogWidth="80%" dialogWidth="80%"
:openDialog="settingBillYearMonthFlag" :openDialog="settingBillYearMonthFlag"
:showAction="true" :showAction="true"
...@@ -452,7 +452,7 @@ const editTableRef = ref(null) ...@@ -452,7 +452,7 @@ const editTableRef = ref(null)
const splitTableColumns = ref([ const splitTableColumns = ref([
{ {
prop: 'splitRatio', prop: 'splitRatio',
label: '出账比例', label: '出账比例(%)',
editType: 'input', editType: 'input',
inputType: 'decimal', // integer / decimalNumber / decimal inputType: 'decimal', // integer / decimalNumber / decimal
decimalDigits: 2, // 小数位数,默认2 decimalDigits: 2, // 小数位数,默认2
...@@ -542,38 +542,7 @@ const splitTableColumns = ref([ ...@@ -542,38 +542,7 @@ const splitTableColumns = ref([
required: true, required: true,
width: 150 width: 150
}, },
// {
// prop: 'amount',
// label: '原币种金额',
// editType: 'input',
// inputType: 'decimalNumber', // integer / decimalNumber / decimal
// decimalDigits: 2, // 小数位数,默认2
// required: true
// },
// {
// prop: 'originalAmount',
// label: '本次出账原币种金额',
// editType: 'input',
// inputType: 'decimalNumber', // integer / decimalNumber / decimal
// decimalDigits: 2, // 小数位数,默认2
// required: true
// },
// {
// prop: 'exchangeRate',
// label: '结算汇率',
// editType: 'input',
// inputType: 'decimal', // integer / decimalNumber / decimal
// decimalDigits: 2, // 小数位数,默认2
// required: true
// },
// {
// prop: 'hkdAmount',
// label: '港币出账金额',
// editType: 'input',
// inputType: 'decimalNumber', // integer / decimalNumber / decimal
// decimalDigits: 2, // 小数位数,默认2
// required: true
// },
{ {
prop: 'payoutYearMonth', prop: 'payoutYearMonth',
label: '出账年月(估)', label: '出账年月(估)',
...@@ -710,7 +679,8 @@ const confirmRateExchange = async () => { ...@@ -710,7 +679,8 @@ const confirmRateExchange = async () => {
const res = await editExchangeRateApi(formData) const res = await editExchangeRateApi(formData)
ElMessage.success('结算汇率修改成功') ElMessage.success('结算汇率修改成功')
rateExchangeFlag.value = false rateExchangeFlag.value = false
loadTableData() const params = searchFormRef.value.getFormData()
loadTableData(params)
} catch (error) { } catch (error) {
ElMessage.error('结算汇率修改失败') ElMessage.error('结算汇率修改失败')
rateExchangeFlag.value = true rateExchangeFlag.value = true
...@@ -1006,7 +976,8 @@ const handleSpiltSubmit = async () => { ...@@ -1006,7 +976,8 @@ const handleSpiltSubmit = async () => {
console.log('分期出账结果', res) console.log('分期出账结果', res)
installmentsBillFlag.value = false installmentsBillFlag.value = false
ElMessage.success('分期出账已保存') ElMessage.success('分期出账已保存')
loadTableData() const searchParams = searchFormRef.value.getFormData()
loadTableData(searchParams)
} catch (error) { } catch (error) {
installmentsBillFlag.value = true installmentsBillFlag.value = true
console.log('分期出账错误', error) console.log('分期出账错误', error)
...@@ -1039,9 +1010,18 @@ const addSpiltRecord = () => { ...@@ -1039,9 +1010,18 @@ const addSpiltRecord = () => {
id: generateId(), // 必须有 rowIdKey 对应的字段(默认 'id') id: generateId(), // 必须有 rowIdKey 对应的字段(默认 'id')
payoutCurrency: 'HKD', payoutCurrency: 'HKD',
ruleCurrency: selectedRow.value.ruleCurrency, ruleCurrency: selectedRow.value.ruleCurrency,
originalCurrency: selectedRow.value.originalCurrency originalCurrency: selectedRow.value.originalCurrency,
hkdToPayoutRate: '1'
} }
if (selectedRow.value.originalCurrency && selectedRow.value.originalCurrency == 'HKD') {
newRow.originalToHkdRate = '1'
}
// if (selectedRow.value.payoutCurrency && selectedRow.value.payoutCurrency == 'HKD') {
// newRow.hkdToPayoutRate = '1'
// }
console.log('====================================')
console.log('newRow', newRow)
console.log('====================================')
// 插入到表格数据最前面 // 插入到表格数据最前面
splitTableData.value.push(newRow) splitTableData.value.push(newRow)
} }
...@@ -1380,11 +1360,13 @@ loadTableData() ...@@ -1380,11 +1360,13 @@ loadTableData()
// 分页事件 // 分页事件
const handleSizeChange = val => { const handleSizeChange = val => {
pageSize.value = val pageSize.value = val
loadTableData() const params = searchFormRef.value.getFormData()
loadTableData(params)
} }
const handleCurrentChange = val => { const handleCurrentChange = val => {
currentPage.value = val currentPage.value = val
loadTableData() const params = searchFormRef.value.getFormData()
loadTableData(params)
} }
// 表格数据 // 表格数据
const tableData = ref([]) const tableData = ref([])
...@@ -1407,15 +1389,13 @@ const handleSelect = (e, row) => { ...@@ -1407,15 +1389,13 @@ const handleSelect = (e, row) => {
ruleCurrency: row.ruleCurrency, ruleCurrency: row.ruleCurrency,
originalCurrency: row.originalCurrency, originalCurrency: row.originalCurrency,
payoutCurrency: row.payoutCurrency, payoutCurrency: row.payoutCurrency,
hkdToPayoutRate: row.hkdToPayoutRate ? row.hkdToPayoutRate : '', hkdToPayoutRate: '',
exchangeRate: row.exchangeRate ? row.exchangeRate : '', exchangeRate: row.exchangeRate ? row.exchangeRate : '',
originalToHkdRate: row.originalToHkdRate ? row.originalToHkdRate : '', originalToHkdRate: '',
payoutAmount: row.payoutAmount ? Number(row.payoutAmount).toFixed(2) : '', payoutAmount: row.payoutAmount ? Number(row.payoutAmount).toFixed(2) : '',
ruleAmount: row.ruleAmount ? Number(row.ruleAmount).toFixed(2) : '', ruleAmount: row.ruleAmount ? Number(row.ruleAmount).toFixed(2) : '',
hkdAmount: row.hkdAmount ? Number(row.hkdAmount).toFixed(2) : '' hkdAmount: row.hkdAmount ? Number(row.hkdAmount).toFixed(2) : ''
} }
rateExchangeFlag.value = true rateExchangeFlag.value = true
} }
} }
...@@ -1465,6 +1445,7 @@ const updatePayoutAmountapi = async data => { ...@@ -1465,6 +1445,7 @@ const updatePayoutAmountapi = async data => {
const updatePayRollStatusDisable = ref(true) const updatePayRollStatusDisable = ref(true)
const multipleSelection = ref([]) const multipleSelection = ref([])
const handleSelectionChange = val => { const handleSelectionChange = val => {
multipleSelection.value = val multipleSelection.value = val
console.log('全选:', val) console.log('全选:', val)
// 完成检核按钮是否禁用 // 完成检核按钮是否禁用
...@@ -1481,7 +1462,8 @@ const submitSettingBillYearMonth = async () => { ...@@ -1481,7 +1462,8 @@ const submitSettingBillYearMonth = async () => {
if (res.code === 200) { if (res.code === 200) {
settingBillYearMonthFlag.value = false settingBillYearMonthFlag.value = false
ElMessage.success('完成检核,等待关账') ElMessage.success('完成检核,等待关账')
loadTableData() const params = searchFormRef.value.getFormData()
loadTableData(params)
} }
} catch (error) { } catch (error) {
console.error('检核失败:', error) console.error('检核失败:', error)
......
...@@ -976,15 +976,135 @@ const updatePayRecordFormConfig = [ ...@@ -976,15 +976,135 @@ const updatePayRecordFormConfig = [
// label: '备注' // label: '备注'
// } // }
] ]
// const addPayRecordFormConfig = [
// {
// type: 'select',
// prop: 'fortuneBizType',
// label: '应付单类型',
// options: [
// { value: 'R', label: '关联保单应付单' },
// { value: 'U', label: '非关联保单应付单' }
// ]
// },
// {
// type: 'input',
// prop: 'policyNo',
// label: '关联保单号',
// visible: formData => formData.fortuneBizType === 'R'
// },
// {
// type: 'input',
// prop: 'fortunePeriod',
// label: '佣金期数',
// inputType: 'decimal',
// visible: formData => formData.fortuneBizType === 'R',
// rules: [{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }]
// },
// {
// type: 'input',
// prop: 'fortuneTotalPeriod',
// label: '总期数',
// inputType: 'decimal',
// visible: formData => formData.fortuneBizType === 'R',
// rules: [{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }]
// },
// {
// type: 'date',
// prop: 'payoutDate',
// label: '出账日(估)',
// placeholder: '请选择'
// },
// {
// type: 'date',
// prop: 'actualPayoutDate',
// label: '出账日(实)',
// placeholder: '请选择',
// maxDate: 'today'
// },
// {
// type: 'input',
// prop: 'hkdAmount',
// label: '出账金额',
// rules: [
// { required: true, message: '请输入', trigger: 'blur' },
// { pattern: /^-?\d+(\.\d{1,2})?$/, message: '小数(最多两位)', trigger: 'blur' }
// ]
// },
// {
// type: 'select',
// prop: 'currency',
// label: '出账币种',
// dictType: 'bx_currency_type',
// defaultValue: 'HKD'
// },
// {
// type: 'input',
// prop: 'defaultExchangeRate',
// label: '结算汇率(入账检核时的汇率)',
// rules: [
// { required: true, message: '请输入', trigger: 'blur' },
// { pattern: /^-?\d+(\.\d{1,6})?$/, message: '小数(最多6位)', trigger: 'blur' }
// ]
// },
// {
// type: 'select',
// prop: 'fortuneType',
// label: '出账项目',
// dictType: 'csf_fortune_type'
// },
// {
// type: 'select',
// prop: 'brokerBizId',
// label: '转介人',
// api: '/insurance/base/api/userSaleExpand/page',
// keywordField: 'realName',
// requestParams: { pageNo: 1, pageSize: 200 },
// placeholder: '输入转介人名称搜索',
// debounceWait: 500, // 自定义防抖时间
// valueKey: 'clientUserBizId',
// labelKey: 'realName',
// onChangeExtraFields: {
// broker: 'realName', // 自动同步 raw.name 到 reconciliationCompany
// reconciliationCompanyCode: 'code'
// },
// transform: res => {
// return res?.data.records || []
// }
// },
// {
// type: 'select',
// prop: 'status',
// label: '出账状态',
// dictType: 'csf_expected_fortune_status'
// },
// {
// type: 'input',
// prop: 'exchangeRate',
// label: '结算汇率',
// inputType: 'decimal',
// rules: [{ required: true, message: '只能输入正整数和小数', trigger: 'blur' }]
// // defaultValue: 1
// },
// {
// type: 'input',
// prop: 'remark',
// label: '备注'
// }
// ]
const addPayRecordFormConfig = [ const addPayRecordFormConfig = [
{ {
type: 'select', type: 'select',
prop: 'fortuneBizType', prop: 'fortuneBizType',
label: '应付单类型', label: '应付单类型',
options: [ options: fortuneBizTypeOptions,
{ value: 'R', label: '关联保单应付单' }, rules: [{ required: true, message: '应付单类型必填', trigger: 'blur' }]
{ value: 'U', label: '非关联保单应付单' } },
] {
type: 'select',
prop: 'status',
label: '出账状态',
dictType: 'csf_expected_fortune_status',
rules: [{ required: true, message: '出账状态必填', trigger: 'blur' }]
}, },
{ {
type: 'input', type: 'input',
...@@ -993,64 +1113,54 @@ const addPayRecordFormConfig = [ ...@@ -993,64 +1113,54 @@ const addPayRecordFormConfig = [
visible: formData => formData.fortuneBizType === 'R' visible: formData => formData.fortuneBizType === 'R'
}, },
{ {
type: 'input', type: 'month',
prop: 'fortunePeriod',
label: '佣金期数',
inputType: 'decimal',
visible: formData => formData.fortuneBizType === 'R',
rules: [{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }]
},
{
type: 'input',
prop: 'fortuneTotalPeriod',
label: '总期数',
inputType: 'decimal',
visible: formData => formData.fortuneBizType === 'R',
rules: [{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }]
},
{
type: 'date',
prop: 'payoutDate', prop: 'payoutDate',
label: '出账日(估)', label: '出账月(估)',
placeholder: '请选择' placeholder: '请选择',
maxDate: 'today',
rules: [{ required: true, message: '出账月(估)必填', trigger: 'blur' }]
}, },
{ {
type: 'date', type: 'month',
prop: 'actualPayoutDate', prop: 'actualPayoutDate',
label: '出账日(实)', label: '出账月(实)',
placeholder: '请选择', placeholder: '请选择',
maxDate: 'today' maxDate: 'today',
rules: [{ required: true, message: '出账月(实)必填', trigger: 'blur' }]
}, },
{ {
type: 'input', type: 'input',
prop: 'hkdAmount', prop: 'statusDesc',
label: '出账金额', label: '修改理由'
rules: [ },
{ required: true, message: '请输入', trigger: 'blur' }, {
{ pattern: /^-?\d+(\.\d{1,2})?$/, message: '小数(最多两位)', trigger: 'blur' } type: 'input',
] prop: 'fortuneName',
label: '出账项目名称',
rules: [{ required: true, message: '出账项目名称必填', trigger: 'blur' }]
}, },
{ {
type: 'select', type: 'select',
prop: 'currency', prop: 'fortuneType',
label: '出账币种', label: '出账项目类型',
dictType: 'bx_currency_type', dictType: 'csf_fortune_type',
defaultValue: 'HKD' rules: [{ required: true, message: '出账项目类型必填', trigger: 'blur' }]
}, },
{ {
type: 'input', type: 'input',
prop: 'defaultExchangeRate', prop: 'fortunePeriod',
label: '结算汇率(入账检核时的汇率)', label: '佣金期数',
rules: [ inputType: 'decimal',
{ required: true, message: '请输入', trigger: 'blur' }, visible: formData => formData.fortuneBizType === 'R',
{ pattern: /^-?\d+(\.\d{1,6})?$/, message: '小数(最多6位)', trigger: 'blur' } rules: [{ required: true, pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }]
]
}, },
{ {
type: 'select', type: 'input',
prop: 'fortuneType', prop: 'fortuneTotalPeriod',
label: '出账项目', label: '总期数',
dictType: 'csf_fortune_type' inputType: 'decimal',
visible: formData => formData.fortuneBizType === 'R',
rules: [{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }]
}, },
{ {
type: 'select', type: 'select',
...@@ -1066,32 +1176,125 @@ const addPayRecordFormConfig = [ ...@@ -1066,32 +1176,125 @@ const addPayRecordFormConfig = [
onChangeExtraFields: { onChangeExtraFields: {
broker: 'realName', // 自动同步 raw.name 到 reconciliationCompany broker: 'realName', // 自动同步 raw.name 到 reconciliationCompany
reconciliationCompanyCode: 'code' reconciliationCompanyCode: 'code'
// team: 'deptName',
// teamBizId: 'deptBizId'
},
transform: res => {
return res?.data.records || []
},
rules: [{ required: true, message: '转介人必填', trigger: 'blur' }]
},
{
type: 'select',
prop: 'teamBizId',
label: '所属团队',
api: '/csf/api/team/page',
keywordField: 'teamName',
requestParams: { pageNo: 1, pageSize: 200 },
placeholder: '输入所属团队名称搜索',
debounceWait: 500, // 自定义防抖时间
valueKey: 'teamBizId',
labelKey: 'teamName',
onChangeExtraFields: {
// broker: 'realName', // 自动同步 raw.name 到 reconciliationCompany
// reconciliationCompanyCode: 'code',
team: 'teamName',
teamBizId: 'teamBizId'
}, },
transform: res => { transform: res => {
return res?.data.records || [] return res?.data.records || []
} }
// rules: [{ required: true, message: '所属团队必填', trigger: 'blur' }]
}, },
// {
// type: 'input',
// prop: 'defaultExchangeRate',
// label: '结算汇率(入账检核时的汇率)',
// rules: [
// { required: true, message: '请输入', trigger: 'blur' },
// { pattern: /^-?\d+(\.\d{1,6})?$/, message: '小数(最多6位)', trigger: 'blur' }
// ]
// },
{ {
type: 'select', type: 'select',
prop: 'status', prop: 'ruleCurrency',
label: '出账状态', label: '保单币种',
dictType: 'csf_expected_fortune_status' dictType: 'bx_currency_type',
rules: [{ required: true, message: '保单币种必填', trigger: 'blur' }]
},
{
type: 'select',
prop: 'originalCurrency',
label: '原币种',
dictType: 'bx_currency_type',
rules: [{ required: true, message: '原币种必填', trigger: 'blur' }]
},
{
type: 'select',
prop: 'payoutCurrency',
label: '发放币种',
dictType: 'bx_currency_type',
rules: [{ required: true, message: '发放币种必填', trigger: 'blur' }]
}, },
{ {
type: 'input', type: 'input',
prop: 'exchangeRate', prop: 'originalAmount',
label: '结算汇率', label: '原币种金额',
inputType: 'decimal',
rules: [{ required: true, message: '只能输入正整数和小数', trigger: 'blur' }]
},
{
type: 'input',
prop: 'originalToHkdRate',
label: '汇率3(原币种->港币)',
inputType: 'decimal',
rules: [{ required: true, message: '只能输入正整数和小数', trigger: 'blur' }]
// defaultValue: 1
},
{
type: 'input',
prop: 'hkdAmount',
label: '港币金额',
inputType: 'decimal',
rules: [{ required: true, message: '只能输入正整数和小数', trigger: 'blur' }]
},
{
type: 'input',
prop: 'hkdToPayoutRate',
label: '汇率1(港币->发放币种)',
inputType: 'decimal',
rules: [{ required: true, message: '只能输入正整数和小数', trigger: 'blur' }]
// defaultValue: 1
},
{
type: 'input',
prop: 'payoutAmount',
label: '实际发放金额',
inputType: 'decimal',
rules: [{ required: true, message: '只能输入正整数和小数', trigger: 'blur' }]
},
{
type: 'input',
prop: 'defaultExchangeRate',
label: '汇率2(保单币种->港币)入账检核汇率',
inputType: 'decimal', inputType: 'decimal',
rules: [{ required: true, message: '只能输入正整数和小数', trigger: 'blur' }] rules: [{ required: true, message: '只能输入正整数和小数', trigger: 'blur' }]
// defaultValue: 1 // defaultValue: 1
}, },
{ {
type: 'input', type: 'input',
prop: 'ruleAmount',
label: '保单币种金额',
inputType: 'decimal',
rules: [{ required: true, message: '只能输入正整数和小数', trigger: 'blur' }]
},
{
type: 'input',
prop: 'remark', prop: 'remark',
label: '备注' label: '备注'
} }
] ]
//是否实收 //是否实收
const typeOptions = [ const typeOptions = [
{ value: 1, label: '预计' }, { value: 1, label: '预计' },
...@@ -1121,7 +1324,7 @@ const handleInputChange = async (formType, prop, value, item) => { ...@@ -1121,7 +1324,7 @@ const handleInputChange = async (formType, prop, value, item) => {
commissionPeriod: fortunePeriod commissionPeriod: fortunePeriod
}) })
if (res.code == 200) { if (res.code == 200) {
addPayRecordFormModel.value.exchangeRate = res.data addPayRecordFormModel.value.defaultExchangeRate = res.data
} else { } else {
ElMessage.error('查询结算汇率失败') ElMessage.error('查询结算汇率失败')
} }
...@@ -1141,9 +1344,9 @@ const handleInputChange = async (formType, prop, value, item) => { ...@@ -1141,9 +1344,9 @@ const handleInputChange = async (formType, prop, value, item) => {
await nextTick() await nextTick()
addPayRecordFormModel.value.payoutAmount = payoutAmount addPayRecordFormModel.value.payoutAmount = payoutAmount
} }
const exchangeRate = addPayRecordFormModel.value.exchangeRate const defaultExchangeRate = addPayRecordFormModel.value.defaultExchangeRate
if (exchangeRate) { if (defaultExchangeRate) {
const ruleAmount = calculateAmount(hkdAmount, exchangeRate, 2, 'Divided') const ruleAmount = calculateAmount(hkdAmount, defaultExchangeRate, 2, 'Divided')
await nextTick() await nextTick()
addPayRecordFormModel.value.ruleAmount = ruleAmount addPayRecordFormModel.value.ruleAmount = ruleAmount
} }
...@@ -1165,9 +1368,9 @@ const handleInputChange = async (formType, prop, value, item) => { ...@@ -1165,9 +1368,9 @@ const handleInputChange = async (formType, prop, value, item) => {
await nextTick() await nextTick()
addPayRecordFormModel.value.payoutAmount = payoutAmount addPayRecordFormModel.value.payoutAmount = payoutAmount
} }
const exchangeRate = addPayRecordFormModel.value.exchangeRate const defaultExchangeRate = addPayRecordFormModel.value.defaultExchangeRate
if (exchangeRate) { if (defaultExchangeRate) {
const ruleAmount = calculateAmount(hkdAmount, exchangeRate, 2, 'Divided') const ruleAmount = calculateAmount(hkdAmount, defaultExchangeRate, 2, 'Divided')
await nextTick() await nextTick()
addPayRecordFormModel.value.ruleAmount = ruleAmount addPayRecordFormModel.value.ruleAmount = ruleAmount
} }
...@@ -1190,18 +1393,18 @@ const handleInputChange = async (formType, prop, value, item) => { ...@@ -1190,18 +1393,18 @@ const handleInputChange = async (formType, prop, value, item) => {
} }
//3.计算保单币种金额 港币金额*保单币种->港币汇率 //3.计算保单币种金额 港币金额*保单币种->港币汇率
if (prop == 'hkdAmount' && value && addPayRecordFormModel.value.exchangeRate) { if (prop == 'hkdAmount' && value && addPayRecordFormModel.value.defaultExchangeRate) {
// 计算保单币种金额 // 计算保单币种金额
const exchangeRate = addPayRecordFormModel.value.exchangeRate const defaultExchangeRate = addPayRecordFormModel.value.defaultExchangeRate
const hkdAmount = value const hkdAmount = value
const ruleAmount = calculateAmount(hkdAmount, exchangeRate, 2, 'Divided') const ruleAmount = calculateAmount(hkdAmount, defaultExchangeRate, 2, 'Divided')
await nextTick() await nextTick()
addPayRecordFormModel.value.ruleAmount = ruleAmount addPayRecordFormModel.value.ruleAmount = ruleAmount
} else if (prop == 'exchangeRate' && value && addPayRecordFormModel.value.hkdAmount) { } else if (prop == 'defaultExchangeRate' && value && addPayRecordFormModel.value.hkdAmount) {
// 计算保单币种金额 // 计算保单币种金额
const exchangeRate = value const defaultExchangeRate = value
const hkdAmount = addPayRecordFormModel.value.hkdAmount const hkdAmount = addPayRecordFormModel.value.hkdAmount
const ruleAmount = calculateAmount(hkdAmount, exchangeRate, 2, 'Divided') const ruleAmount = calculateAmount(hkdAmount, defaultExchangeRate, 2, 'Divided')
await nextTick() await nextTick()
addPayRecordFormModel.value.ruleAmount = ruleAmount addPayRecordFormModel.value.ruleAmount = ruleAmount
} }
......
...@@ -376,10 +376,9 @@ const addReceivablesFormConfig = [ ...@@ -376,10 +376,9 @@ const addReceivablesFormConfig = [
visible: formData => formData.commissionBizType === 'R', visible: formData => formData.commissionBizType === 'R',
rules: [{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }] rules: [{ pattern: /^\d+$/, message: '只能输入正整数', trigger: 'blur' }]
}, },
// 等待key
{ {
type: 'month', type: 'month',
prop: 'commissionDateMonth', prop: 'commissionDate',
label: '入账月(估)', label: '入账月(估)',
placeholder: '请选择' placeholder: '请选择'
}, },
......
...@@ -181,7 +181,7 @@ ...@@ -181,7 +181,7 @@
<el-dialog <el-dialog
v-model="previewDialogVisible" v-model="previewDialogVisible"
:title="previewFileName" :title="previewFileName"
width="80%" width="90%"
:close-on-click-modal="false" :close-on-click-modal="false"
destroy-on-close destroy-on-close
@close="closePreview" @close="closePreview"
...@@ -191,19 +191,10 @@ ...@@ -191,19 +191,10 @@
<div v-if="previewFileType === 'image'" class="preview-image-wrapper"> <div v-if="previewFileType === 'image'" class="preview-image-wrapper">
<img :src="previewUrl" class="preview-image" alt="预览图片" /> <img :src="previewUrl" class="preview-image" alt="预览图片" />
</div> </div>
<!-- PDF 预览区域(滚动多页) -->
<!-- PDF 预览(pdf.js 插件) -->
<div v-else-if="previewFileType === 'pdf'" class="pdf-viewer"> <div v-else-if="previewFileType === 'pdf'" class="pdf-viewer">
<div class="pdf-toolbar"> <div class="pdf-toolbar">
<el-button-group> <!-- 只保留缩放按钮 -->
<el-button size="small" :disabled="pdfCurrentPage <= 1" @click="prevPage">
<el-icon><ArrowLeft /></el-icon> 上一页
</el-button>
<el-button size="small" :disabled="pdfCurrentPage >= pdfTotalPages" @click="nextPage">
下一页 <el-icon><ArrowRight /></el-icon>
</el-button>
</el-button-group>
<span class="page-info"> 第 {{ pdfCurrentPage }} / {{ pdfTotalPages }} 页 </span>
<el-button-group> <el-button-group>
<el-button size="small" @click="zoomOut"> <el-button size="small" @click="zoomOut">
<el-icon><ZoomOut /></el-icon> 缩小 <el-icon><ZoomOut /></el-icon> 缩小
...@@ -212,12 +203,16 @@ ...@@ -212,12 +203,16 @@
<el-icon><ZoomIn /></el-icon> 放大 <el-icon><ZoomIn /></el-icon> 放大
</el-button> </el-button>
</el-button-group> </el-button-group>
<span class="page-info">共 {{ pdfTotalPages }} 页</span>
</div> </div>
<div class="pdf-canvas-wrapper"> <div
<canvas ref="pdfCanvasRef" class="pdf-canvas"></canvas> class="pdf-scroll-wrapper"
v-loading="pdfLoading"
element-loading-text="正在渲染页面..."
>
<div ref="pdfScrollContainer" class="pdf-scroll-container"></div>
</div> </div>
</div> </div>
<!-- 不支持预览的文件类型 --> <!-- 不支持预览的文件类型 -->
<div v-else-if="previewFileType === 'unsupported'" class="preview-unsupported"> <div v-else-if="previewFileType === 'unsupported'" class="preview-unsupported">
<el-icon :size="48" color="#909399"><Document /></el-icon> <el-icon :size="48" color="#909399"><Document /></el-icon>
...@@ -235,7 +230,7 @@ ...@@ -235,7 +230,7 @@
</template> </template>
<script setup name="FileUpload"> <script setup name="FileUpload">
import { ref, nextTick } from 'vue' import { ref, nextTick, shallowRef } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { downloadFilesAsZip } from '@/utils/zipDownload' // 引入刚才封装的工具 import { downloadFilesAsZip } from '@/utils/zipDownload' // 引入刚才封装的工具
import CommonDialog from '@/components/commonDialog' import CommonDialog from '@/components/commonDialog'
...@@ -244,7 +239,7 @@ import { getToken } from '@/utils/auth' ...@@ -244,7 +239,7 @@ import { getToken } from '@/utils/auth'
import { addFile, getAppointmentFile, delFile, editAppointmentFile } from '@/api/sign/appointment' import { addFile, getAppointmentFile, delFile, editAppointmentFile } from '@/api/sign/appointment'
import useDictStore from '@/store/modules/dict' import useDictStore from '@/store/modules/dict'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { ArrowLeft, ArrowRight, ZoomIn, ZoomOut, Document } from '@element-plus/icons-vue' import { ArrowLeft, ArrowRight, ZoomIn, ZoomOut, Document, Loading } from '@element-plus/icons-vue'
const userStore = useUserStore() const userStore = useUserStore()
import { import {
uploadMaterialList, uploadMaterialList,
...@@ -257,16 +252,14 @@ import { ...@@ -257,16 +252,14 @@ import {
} from '@/api/common' } from '@/api/common'
import * as PDFJS from 'pdfjs-dist' import * as PDFJS from 'pdfjs-dist'
// 设置 worker 路径(重要!) PDFJS.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.min.mjs'
PDFJS.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.js',
import.meta.url
).toString()
const props = defineProps({ const props = defineProps({
activeName: { type: String, default: '' }, //tab名称 activeName: { type: String, default: '' }, //tab名称
idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象 idsObj: { type: Object, default: () => ({}) }, //父组件传递过来的id对象
pageSource: { type: String, default: '' } //页面来源 pageSource: { type: String, default: '' } //页面来源
}) })
// 在定义其他响应式变量的附近添加
const pdfLoading = ref(false) // PDF 加载状态
const acceptUploadType = ref('.pdf,.jpg,.jpeg,.png,.bmp,.gif,.svg') const acceptUploadType = ref('.pdf,.jpg,.jpeg,.png,.bmp,.gif,.svg')
const uploadRef = ref(null) const uploadRef = ref(null)
const dictStore = useDictStore() //获取字典数据 const dictStore = useDictStore() //获取字典数据
...@@ -281,17 +274,63 @@ const headers = ref({ Authorization: 'Bearer ' + getToken() }) ...@@ -281,17 +274,63 @@ const headers = ref({ Authorization: 'Bearer ' + getToken() })
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + '/oss/api/oss/upload') // 上传的服务器地址 const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + '/oss/api/oss/upload') // 上传的服务器地址
// PDF 预览相关 // PDF 预览相关
const pdfCanvasRef = ref(null) // canvas 元素引用 const pdfCanvasRef = ref(null) // canvas 元素引用
const pdfDoc = ref(null) // pdf 文档实例 // 修改 pdfDoc 的定义
const pdfCurrentPage = ref(1) // 当前页 const pdfDoc = shallowRef(null) // pdf 文档实例
const pdfTotalPages = ref(0) // 总页数
const pdfScale = ref(1.2) // 缩放比例 const pdfScale = ref(1.2) // 缩放比例
// 新增标志:是否取消PDF加载
let pdfLoadingCanceled = false
// ==================== 文件预览弹窗 ====================
const previewDialogVisible = ref(false)
const previewUrl = ref('')
const previewFileName = ref('')
const previewFileType = ref('') // 'image', 'pdf', 'unsupported'
const pdfScrollContainer = ref(null) // 滚动容器的 ref
const pdfTotalPages = ref(0) // 总页数(仅供显示)
const isRendering = ref(false) // 防止重复渲染
const loadPdf = async url => {
pdfLoadingCanceled = false
pdfLoading.value = true
try {
if (pdfDoc.value) {
await pdfDoc.value.destroy().catch(() => {})
pdfDoc.value = null
}
// 清空滚动容器
if (pdfScrollContainer.value) {
pdfScrollContainer.value.innerHTML = ''
}
const loadingTask = PDFJS.getDocument(url)
pdfDoc.value = await loadingTask.promise
if (pdfLoadingCanceled) {
if (pdfDoc.value) pdfDoc.value.destroy()
pdfLoading.value = false
return
}
pdfTotalPages.value = pdfDoc.value.numPages
await renderAllPages(pdfScale.value) // 渲染所有页面
pdfLoading.value = false
} catch (err) {
if (!pdfLoadingCanceled) {
console.error('PDF 加载失败', err)
ElMessage.error('PDF 文件加载失败,请检查文件链接')
previewDialogVisible.value = false
}
pdfLoading.value = false
}
}
// 渲染指定页 // 修改 renderPdfPage,增加有效性检查
const renderPdfPage = async pageNum => { const renderPdfPage = async pageNum => {
if (!pdfDoc.value) return if (!pdfDoc.value || pdfLoadingCanceled) return
try {
const page = await pdfDoc.value.getPage(pageNum) const page = await pdfDoc.value.getPage(pageNum)
const viewport = page.getViewport({ scale: pdfScale.value }) const viewport = page.getViewport({ scale: pdfScale.value })
const canvas = pdfCanvasRef.value const canvas = pdfCanvasRef.value
if (!canvas) return
const context = canvas.getContext('2d') const context = canvas.getContext('2d')
canvas.height = viewport.height canvas.height = viewport.height
canvas.width = viewport.width canvas.width = viewport.width
...@@ -301,108 +340,67 @@ const renderPdfPage = async pageNum => { ...@@ -301,108 +340,67 @@ const renderPdfPage = async pageNum => {
viewport: viewport viewport: viewport
} }
await page.render(renderContext).promise await page.render(renderContext).promise
}
// 加载并渲染 PDF
const loadPdf = async url => {
try {
// 重置状态
pdfDoc.value = null
pdfCurrentPage.value = 1
pdfTotalPages.value = 0
const loadingTask = PDFJS.getDocument(url)
pdfDoc.value = await loadingTask.promise
pdfTotalPages.value = pdfDoc.value.numPages
await renderPdfPage(pdfCurrentPage.value)
} catch (err) { } catch (err) {
console.error('PDF 加载失败', err) if (!pdfLoadingCanceled) {
ElMessage.error('PDF 文件加载失败,请检查文件链接') console.error('渲染PDF页失败', err)
previewDialogVisible.value = false
} }
}
// 上一页
const prevPage = () => {
if (pdfCurrentPage.value > 1) {
pdfCurrentPage.value--
renderPdfPage(pdfCurrentPage.value)
} }
} }
const renderAllPages = async scale => {
if (!pdfDoc.value || pdfLoadingCanceled || isRendering.value) return
isRendering.value = true
pdfLoading.value = true // 显示加载状态
// 下一页 const container = pdfScrollContainer.value
const nextPage = () => { if (!container) {
if (pdfCurrentPage.value < pdfTotalPages.value) { isRendering.value = false
pdfCurrentPage.value++ return
renderPdfPage(pdfCurrentPage.value)
} }
} // 清空之前的 canvas
container.innerHTML = ''
// 放大/缩小 try {
const zoomIn = () => { const promises = []
pdfScale.value = Math.min(pdfScale.value + 0.2, 3.0) for (let pageNum = 1; pageNum <= pdfTotalPages.value; pageNum++) {
renderPdfPage(pdfCurrentPage.value) if (pdfLoadingCanceled) break
} const page = await pdfDoc.value.getPage(pageNum)
const zoomOut = () => { const viewport = page.getViewport({ scale })
pdfScale.value = Math.max(pdfScale.value - 0.2, 0.5)
renderPdfPage(pdfCurrentPage.value) // 创建 canvas 元素
} const canvas = document.createElement('canvas')
const closePreview = () => { canvas.className = 'pdf-page-canvas'
// 清理 PDF 资源 const context = canvas.getContext('2d')
if (pdfDoc.value) { canvas.height = viewport.height
pdfDoc.value.destroy() canvas.width = viewport.width
pdfDoc.value = null // 添加一些底部间距,便于区分页面
canvas.style.marginBottom = '16px'
canvas.style.boxShadow = '0 2px 8px rgba(0,0,0,0.1)'
container.appendChild(canvas)
// 渲染该页
const renderTask = page.render({
canvasContext: context,
viewport: viewport
})
promises.push(renderTask.promise)
}
await Promise.all(promises)
} catch (err) {
if (!pdfLoadingCanceled) {
console.error('渲染多页 PDF 失败', err)
ElMessage.error('渲染 PDF 页面失败')
}
} finally {
isRendering.value = false
pdfLoading.value = false
} }
pdfTotalPages.value = 0
pdfCurrentPage.value = 1
pdfScale.value = 1.0
previewUrl.value = ''
} }
// ==================== 文件预览弹窗 ====================
const previewDialogVisible = ref(false)
const previewUrl = ref('')
const previewFileName = ref('')
const previewFileType = ref('') // 'image', 'pdf', 'unsupported'
// 预览文件(页面内弹窗,不打开新窗口) // 修改 previewFile 中的 PDF 分支
// function previewFile(file) {
// console.log('====================================')
// console.log('file', file)
// console.log('====================================')
// // const url = file.url || file.fileUrl
// let url = ''
// if (file.fileKey) {
// // url = `https://files.csf.hk/${file.fileKey}`
// url = `https://csf-hk.oss-cn-hongkong.aliyuncs.com/PC/test/pdf/2026/05/13/a482331b118142d782ac6ba7697eae15.pdf`
// } else {
// url = file.url
// }
// if (!url) {
// ElMessage.warning('文件地址不存在')
// return
// }
// const ext = (file.originalName || '').split('.').pop().toLowerCase()
// previewUrl.value = url
// previewFileName.value = file.originalName || '文件'
// if (['jpg', 'jpeg', 'png', 'webp', 'gif', 'bmp', 'svg'].includes(ext)) {
// previewFileType.value = 'image'
// previewDialogVisible.value = true
// } else if (ext === 'pdf') {
// previewFileType.value = 'pdf'
// previewDialogVisible.value = true
// } else {
// // 不支持预览的文件类型,弹窗显示提示
// previewFileType.value = 'unsupported'
// previewDialogVisible.value = true
// }
// console.log('====================================')
// console.log('previewUrl.value', previewUrl.value)
// console.log('previewFileName.value', previewFileName.value)
// console.log('previewFileType.value', previewFileType.value)
// console.log('====================================')
// }
function previewFile(file) { function previewFile(file) {
console.log('====================================')
console.log('file', file)
console.log('====================================')
const url = file.url || file.fileUrl const url = file.url || file.fileUrl
if (!url) { if (!url) {
ElMessage.warning('文件地址不存在') ElMessage.warning('文件地址不存在')
...@@ -418,7 +416,8 @@ function previewFile(file) { ...@@ -418,7 +416,8 @@ function previewFile(file) {
} else if (ext === 'pdf') { } else if (ext === 'pdf') {
previewFileType.value = 'pdf' previewFileType.value = 'pdf'
previewDialogVisible.value = true previewDialogVisible.value = true
// 确保 DOM 更新后再加载 PDF // 先清理旧的资源
closePreview()
nextTick(() => { nextTick(() => {
loadPdf(previewUrl.value) loadPdf(previewUrl.value)
}) })
...@@ -427,6 +426,29 @@ function previewFile(file) { ...@@ -427,6 +426,29 @@ function previewFile(file) {
previewDialogVisible.value = true previewDialogVisible.value = true
} }
} }
const closePreview = () => {
pdfLoadingCanceled = true // 取消任何进行中的渲染
pdfLoading.value = false
isRendering.value = false
if (pdfDoc.value) {
pdfDoc.value.destroy().catch(() => {})
pdfDoc.value = null
}
pdfTotalPages.value = 0
pdfScale.value = 1.2
if (pdfScrollContainer.value) {
pdfScrollContainer.value.innerHTML = ''
}
}
const zoomIn = () => {
pdfScale.value = Math.min(pdfScale.value + 0.2, 3.0)
renderAllPages(pdfScale.value)
}
const zoomOut = () => {
pdfScale.value = Math.max(pdfScale.value - 0.2, 0.5)
renderAllPages(pdfScale.value)
}
// 图片查看相关状态 // 图片查看相关状态
const imageViewerVisible = ref(false) const imageViewerVisible = ref(false)
const imageUrl = ref('') const imageUrl = ref('')
...@@ -867,6 +889,61 @@ defineExpose({ ...@@ -867,6 +889,61 @@ defineExpose({
padding: 8px 0; padding: 8px 0;
border-bottom: 1px solid #e4e7ed; border-bottom: 1px solid #e4e7ed;
margin-bottom: 12px; margin-bottom: 12px;
.page-info {
font-size: 14px;
color: #606266;
}
}
.pdf-scroll-wrapper {
flex: 1;
overflow-y: auto; /* 垂直滚动 */
border: 1px solid #ebeef5;
border-radius: 4px;
background: #f9fafc;
}
.pdf-scroll-container {
display: flex;
flex-direction: column;
align-items: center; /* 页面居中显示 */
padding: 16px;
}
.pdf-page-canvas {
display: block;
max-width: 100%; /* 自适应宽度,防止溢出容器 */
height: auto;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
margin-bottom: 16px;
}
.pdf-loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 300px;
color: #409eff;
gap: 12px;
.el-icon {
font-size: 32px;
}
}
.pdf-viewer {
display: flex;
flex-direction: column;
height: 70vh;
}
.pdf-toolbar {
display: flex;
justify-content: center;
align-items: center;
gap: 16px;
padding: 8px 0;
border-bottom: 1px solid #e4e7ed;
margin-bottom: 12px;
.page-info { .page-info {
font-size: 14px; font-size: 14px;
......
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