10.17沟通调整

计划收款信息增加复制操作
上传合同调整为:上传合同、上传PI、上传水单(均为必传,且支持多文件操作与下载)
This commit is contained in:
浅念
2025-10-22 11:52:20 +08:00
parent 222d07d483
commit ff0fb83bd0
20 changed files with 2139 additions and 856 deletions
+53 -45
View File
@@ -83,44 +83,19 @@
:close-on-click-modal="false"
>
<OrderDetailContent :orderData="orderDialog.orderData" />
<!-- 合同文件 -->
<div class="boxshadow">
<div class="form-title">
<!-- <span class="border"></span> -->
<span class="title">合同</span>
</div>
<div class="file-preview">
<div v-if="contractFile" class="contract-file">
<div v-if="isImageFile(contractFile)" class="image-preview">
<img
:src="contractFile.url"
:alt="contractFile.name"
class="preview-image"
@click="previewImage(contractFile)"
/>
<div class="file-info">
<span class="file-name">{{ contractFile.name }}</span>
<el-button type="text" size="small" @click="previewImage(contractFile)">
预览
</el-button>
</div>
</div>
<div v-else class="document-preview">
<div class="file-icon">
<i class="iconfont-sys">&#xe814;</i>
</div>
<div class="file-info">
<span class="file-name">{{ contractFile.name }}</span>
<el-button type="primary" size="small" @click="downloadFile(contractFile)">
下载
</el-button>
</div>
</div>
</div>
<div v-else class="no-file">
<i class="iconfont-sys">&#xe60c;</i>
<span>暂无合同文件</span>
</div>
</div>
<FilePreview title="合同文件" :files="contractFiles" empty-text="暂无合同文件" />
</div>
<!-- PI文件 -->
<div class="boxshadow">
<FilePreview title="PI文件" :files="piFiles" empty-text="暂无PI文件" />
</div>
<!-- 水单文件 -->
<div class="boxshadow">
<FilePreview title="水单文件" :files="waterBillFiles" empty-text="暂无水单文件" />
</div>
<template #footer>
<div style="display: flex; justify-content: flex-end; gap: 8px">
@@ -138,7 +113,7 @@
>
<div style="max-height: 70vh; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; justify-content: flex-end; gap: 8px">
<el-button @click="download">下载</el-button>
<el-button @click="download" v-if="isFinites">下载</el-button>
</div>
<div
v-if="pdf.images.length"
@@ -184,8 +159,10 @@
import ApprovalTimeline from '@/components/custom/ApprovalTimeline.vue'
import type { OrderData } from '@/composables/useOrderDetailDialog'
import { usePdfPreview } from '@/composables/usePdfPreview'
import FilePreview from '@/components/custom/FilePreview.vue'
const timelineDialogVisible = ref(false)
const approvalRecords = ref<any[]>([])
const isFinites = ref(false)
// PDF 预览/打印(公共)
const { pdf, frameRef, openWithResponse, download, print, preparePreview, prepareImages } = usePdfPreview()
defineOptions({ name: 'AdminFinalListPage' })
@@ -248,6 +225,11 @@
}
//打印
const printfn = (row: any) => {
if (row.approval_status == 2) {
isFinites.value = true
} else {
isFinites.value = false
}
manageService
.printStock({ id: row.id })
.then((res) => {
@@ -261,16 +243,42 @@
console.log(err)
})
}
// 文件数据
const contractFiles = ref<Array<{ name: string; url: string; file_name: string }>>([])
const piFiles = ref<Array<{ name: string; url: string; file_name: string }>>([])
const waterBillFiles = ref<Array<{ name: string; url: string; file_name: string }>>([])
const contractFile = ref<{ name: string; url: string; file_name: string } | null>(null)
// 处理文件数据
const processFiles = (files: any[], type: string) => {
if (!files || !Array.isArray(files)) return []
return files.map((file: any) => ({
name: `${type}文件`,
url: file.file_full_url || file.file_url,
file_name: file.file_url
}))
}
const handleView1 = async (row: any) => {
const res = await manageService.checkStock({ id: row.object_id })
if (res?.contract) {
contractFile.value = {
name: '合同文件',
url: res.contract_url || res.contract,
file_name: res.contract
}
// 处理合同文件
const file_list = res?.file_list
if (file_list?.contract) {
contractFiles.value = processFiles(file_list.contract, '合同')
} else {
contractFiles.value = []
}
// 处理PI文件
if (file_list?.pi_doc) {
piFiles.value = processFiles(file_list.pi_doc, 'PI')
} else {
piFiles.value = []
}
// 处理水单文件
if (file_list?.transaction_slip) {
waterBillFiles.value = processFiles(file_list.transaction_slip, '水单')
} else {
waterBillFiles.value = []
}
if (res) {
// 获取订单详情成功
+6 -6
View File
@@ -177,8 +177,8 @@
<ElRow :gutter="12">
<ElCol :span="6">
<ElFormItem label="合计到岸价" label-width="85px">
<ElInput v-model="base.total_cif" disabled>
<template #append>{{ base.total_cif_currency }}</template>
<ElInput v-model="base.cif_total" disabled>
<template #append>{{ base.cif_total_currency }}</template>
</ElInput>
</ElFormItem>
</ElCol>
@@ -332,8 +332,8 @@
channel: '',
customer_name: '',
client_country: '',
total_cif: '',
total_cif_currency: '',
cif_total: '',
cif_total_currency: '',
contract_rate: ''
})
const items = ref<any[]>([])
@@ -429,8 +429,8 @@
)
ship.latest_arrival = res?.latest_arrival_date || ''
// 合计与汇率
base.total_cif = res?.cif_total_amount?.amount ?? ''
base.total_cif_currency = res?.cif_total_amount?.currency || ''
base.cif_total = res?.cif_total_amount?.amount ?? ''
base.cif_total_currency = res?.cif_total_amount?.currency || ''
base.contract_rate = res?.contract_exchange_rate || res?.contract_rate || ''
// 计划收款(全部展示)
payments.value = (Array.isArray(res?.account_list) ? res.account_list : []).map((p: any) => ({
+6 -6
View File
@@ -172,8 +172,8 @@
<ElRow :gutter="12">
<ElCol :span="6">
<ElFormItem label="合计到岸价" label-width="85px">
<ElInput v-model="base.total_cif" disabled>
<template #append>{{ base.total_cif_currency }}</template>
<ElInput v-model="base.cif_total" disabled>
<template #append>{{ base.cif_total_currency }}</template>
</ElInput>
</ElFormItem>
</ElCol>
@@ -327,8 +327,8 @@
channel: '',
customer_name: '',
client_country: '',
total_cif: '',
total_cif_currency: '',
cif_total: '',
cif_total_currency: '',
contract_rate: ''
})
const items = ref<any[]>([])
@@ -421,8 +421,8 @@
)
ship.latest_arrival = res?.latest_arrival_date || ''
// 合计与汇率
base.total_cif = res?.cif_total_amount?.amount ?? ''
base.total_cif_currency = res?.cif_total_amount?.currency || ''
base.cif_total = res?.cif_total_amount?.amount ?? ''
base.cif_total_currency = res?.cif_total_amount?.currency || ''
base.contract_rate = res?.contract_exchange_rate || res?.contract_rate || ''
// 计划收款(全部展示)
payments.value = (Array.isArray(res?.account_list) ? res.account_list : []).map((p: any) => ({
+162 -63
View File
@@ -68,7 +68,7 @@
type="success"
underline="never"
@click="handleView(scope.row)"
style="margin-right: 8px"
style="margin-right: 8px;color: #333333;"
>
<i class="iconfont-sys">&#xe76c;</i> 查看
</el-link>
@@ -100,7 +100,7 @@
>
<div style="max-height: 70vh; display: flex; flex-direction: column; gap: 12px">
<div style="display: flex; justify-content: flex-end; gap: 8px;">
<el-button @click="download">下载</el-button>
<el-button @click="download" v-if="isFinites">下载</el-button>
</div>
<div
v-if="pdf.images.length"
@@ -129,44 +129,19 @@
:close-on-click-modal="false"
>
<OrderDetailContent :orderData="orderDialog.orderData" />
<!-- 合同文件 -->
<div class="boxshadow">
<div class="form-title">
<!-- <span class="border"></span> -->
<span class="title">合同</span>
</div>
<div class="file-preview">
<div v-if="contractFile" class="contract-file">
<div v-if="isImageFile(contractFile)" class="image-preview">
<img
:src="contractFile.url"
:alt="contractFile.name"
class="preview-image"
@click="previewImage(contractFile)"
/>
<div class="file-info">
<span class="file-name">{{ contractFile.name }}</span>
<el-button type="text" size="small" @click="previewImage(contractFile)">
预览
</el-button>
</div>
</div>
<div v-else class="document-preview">
<div class="file-icon">
<i class="iconfont-sys">&#xe814;</i>
</div>
<div class="file-info">
<span class="file-name">{{ contractFile.name }}</span>
<el-button type="primary" size="small" @click="downloadFile(contractFile)">
下载
</el-button>
</div>
</div>
</div>
<div v-else class="no-file">
<i class="iconfont-sys">&#xe60c;</i>
<span>暂无合同文件</span>
</div>
</div>
<FilePreview title="合同文件" :files="contractFiles" empty-text="暂无合同文件" />
</div>
<!-- PI文件 -->
<div class="boxshadow">
<FilePreview title="PI文件" :files="piFiles" empty-text="暂无PI文件" />
</div>
<!-- 水单文件 -->
<div class="boxshadow">
<FilePreview title="水单文件" :files="waterBillFiles" empty-text="暂无水单文件" />
</div>
<template #footer>
<div style="display: flex; justify-content: flex-end; gap: 8px">
@@ -196,8 +171,10 @@
import OrderDetailContent from '@/components/custom/OrderDetailContent.vue'
import ApprovalTimeline from '@/components/custom/ApprovalTimeline.vue'
import type { OrderData } from '@/composables/useOrderDetailDialog'
import FilePreview from '@/components/custom/FilePreview.vue'
const timelineDialogVisible = ref(false)
const approvalRecords = ref<any[]>([])
const isFinites = ref(false)
defineOptions({ name: 'StockingListAdmin' })
// import { useAuth } from '@/composables/useAuth'
// const { hasAuth } = useAuth()
@@ -260,18 +237,48 @@
getList()
}
const contractFile = ref<{ name: string; url: string; file_name: string } | null>(null)
// 文件数据
const contractFiles = ref<Array<{ name: string; url: string; file_name: string }>>([])
const piFiles = ref<Array<{ name: string; url: string; file_name: string }>>([])
const waterBillFiles = ref<Array<{ name: string; url: string; file_name: string }>>([])
// 处理文件数据
const processFiles = (files: any[], type: string) => {
if (!files || !Array.isArray(files)) return []
return files.map((file: any) => ({
name: `${type}文件`,
url: file.file_full_url || file.file_url,
file_name: file.file_url
}))
}
const handleView = async (row: any) => {
try {
// 获取订单详情数据
const res = await manageService.checkStock({ id: row.id })
if (res?.contract) {
contractFile.value = {
name: '合同文件',
url: res.contract_url || res.contract,
file_name: res.contract
}
// 处理合同文件
const file_list = res?.file_list
if (file_list?.contract) {
contractFiles.value = processFiles(file_list.contract, '合同')
} else {
contractFiles.value = []
}
// 处理PI文件
if (file_list?.pi_doc) {
piFiles.value = processFiles(file_list.pi_doc, 'PI')
} else {
piFiles.value = []
}
// 处理水单文件
if (file_list?.transaction_slip) {
waterBillFiles.value = processFiles(file_list.transaction_slip, '水单')
} else {
waterBillFiles.value = []
}
if (res) {
// 转换数据格式以适配 OrderDetailDialog
const orderData: OrderData = res
@@ -284,21 +291,33 @@
console.error('获取订单详情失败:', error)
ElMessage.error('获取订单详情失败')
}
// router.push({
// path: '/admin/stock/show_admin',
// query: { id: row.id } // 可带客户名等参数
// })
// TODO: 跳转或弹窗查看备货单
}
const handleView1 = async (row: any) => {
const res = await manageService.checkStock({ id: row.object_id })
if (res?.contract) {
contractFile.value = {
name: '合同文件',
url: res.contract_url || res.contract,
file_name: res.contract
}
// 处理合同文件
const file_list = res?.file_list
if (file_list?.contract) {
contractFiles.value = processFiles(file_list.contract, '合同')
} else {
contractFiles.value = []
}
// 处理PI文件
if (file_list?.pi_doc) {
piFiles.value = processFiles(file_list.pi_doc, 'PI')
} else {
piFiles.value = []
}
// 处理水单文件
if (file_list?.transaction_slip) {
waterBillFiles.value = processFiles(file_list.transaction_slip, '水单')
} else {
waterBillFiles.value = []
}
if (res) {
// 获取订单详情成功
const orderData: OrderData = res
@@ -306,12 +325,6 @@
orderDialog.title = '合塑实业-汽车事业部-备货单(客户下定)'
orderDialog.visible = true
}
// router.push({
// path: '/admin/stock/final_show_admin',
// query: { id: row.object_id } // 可带客户名等参数
// })
// router.push('/crmpc/stocking/final_show')
// TODO: 跳转或弹窗查看备货单
}
// 判断是否为图片文件
const isImageFile = (file: { name: string; url: string; file_name: string }) => {
@@ -419,6 +432,11 @@
}
//打印
const printfn = (row: any) => {
if (row.approval_status == 2) {
isFinites.value = true
} else {
isFinites.value = false
}
manageService
.printStock({ id: row.id })
.then((res) => {
@@ -506,5 +524,86 @@
font-size: 48px;
color: #ddd;
}
.files-list {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.file-item {
flex: 0 0 auto;
min-width: 200px;
max-width: 300px;
}
.file-preview {
position: relative;
width: 100%;
max-height: 120px;
border: 1px solid #e4e7ed;
border-radius: 6px;
overflow: hidden;
background: #fafafa;
padding: 10px;
}
.image-preview {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.preview-image {
flex: 1;
max-height: 80px;
object-fit: cover;
cursor: pointer;
transition: transform 0.2s;
}
.preview-image:hover {
transform: scale(1.05);
}
.document-preview {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.file-icon {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.file-icon i {
font-size: 48px;
color: #409eff;
}
.file-info {
padding: 8px;
background: rgba(255, 255, 255, 0.9);
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.file-name {
font-size: 12px;
color: #606266;
text-align: center;
word-break: break-all;
max-width: 100%;
}
</style>