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 @@
</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