Commit 2b3989c6 by yuzhenWang

按需求修改

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