Merge remote-tracking branch 'origin/master'

This commit is contained in:
z 2026-05-14 08:34:44 +08:00
commit 08fa9c07b3

View File

@ -0,0 +1,455 @@
<template>
<!-- 全屏模式详情 -->
<div v-if="dialogVisible" class="fullscreen-form">
<div class="form-header">
<h2>{{ dialogTitle }}</h2>
</div>
<div class="form-content">
<!-- 基础信息区域 -->
<div class="basic-info">
<h3 class="section-title">基础信息</h3>
<el-form
:model="formData"
label-width="100px"
v-loading="formLoading"
>
<!-- 第一行订单编号订单类型订单状态下单日期 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="订单编号">
<el-input v-model="formData.saleOrdNo" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="订单类型">
<el-select v-model="formData.ordType" disabled>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.ORDER_TYPE)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="订单状态">
<el-select v-model="formData.ordStatus" disabled>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.ORDER_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="下单日期">
<el-date-picker
v-model="formData.ordDate"
type="date"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
disabled
/>
</el-form-item>
</el-col>
</el-row>
<!-- 第二行业务部门业务人员客户名称是否急单 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="业务部门">
<el-input v-model="formData.saleDeptName" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="业务人员">
<el-input v-model="formData.saleManName" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="客户名称">
<el-input v-model="formData.custName" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="是否急单">
<el-select v-model="formData.isUrgent" disabled>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.SYSTEM_IS_CELL)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 第三行交货日期合同编号付款方式是否变更 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="交货日期">
<el-date-picker
v-model="formData.reqDeliveryDate"
type="date"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
disabled
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="合同编号">
<el-input v-model="formData.contractNo" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="付款方式">
<el-select v-model="formData.paymentTerms" disabled>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.PAY_METH)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="是否变更">
<el-select v-model="formData.isChange" disabled>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.SYSTEM_IS_CELL)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 第四行税率含税总金额发货状态 -->
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="税率">
<el-input v-model="formData.taxRate" disabled class="text-right" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="含税总金额">
<el-input v-model="formData.totalAmount" disabled class="text-right" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="发货状态">
<el-select v-model="formData.deliveryStatus" disabled>
<el-option
v-for="dict in getIntDictOptions(DICT_TYPE.SHIPPING_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 第五行包装要求质量要求 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="包装要求">
<el-input v-model="formData.packReq" type="textarea" disabled :rows="3" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="质量要求">
<el-input v-model="formData.qualityReq" type="textarea" disabled :rows="3" />
</el-form-item>
</el-col>
</el-row>
<!-- 备注 -->
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="formData.remark" type="textarea" disabled :rows="3" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<!-- 产品明细区域 -->
<div class="product-detail">
<div class="section-header">
<h3 class="section-title">产品明细</h3>
</div>
<el-table
:data="productList"
stripe
style="width: 100%;"
:show-overflow-tooltip="true"
>
<el-table-column label="序号" align="center" type="index" width="60px" />
<el-table-column label="产品名称" align="center" prop="materialName" />
<el-table-column label="规格型号" align="center" prop="spec" />
<el-table-column label="单位" align="center" prop="unit">
<template #default="scope">
<dict-tag :type="DICT_TYPE.UNIT" :value="scope.row.unit" />
</template>
</el-table-column>
<el-table-column label="订单数量" align="center" prop="ordQty" />
<el-table-column label="含税单价" align="center" prop="priceTax" />
<el-table-column label="用途" align="center" width="120px">
<template #default="scope">
<dict-tag :type="DICT_TYPE.PURPOSE" :value="scope.row.materialUse" />
</template>
</el-table-column>
<el-table-column label="发货数量" align="center" prop="deliveriedQty" />
<el-table-column label="已转生成数量" align="center" prop="produceQty" />
<el-table-column label="备注" align="center" prop="remark" />
</el-table>
</div>
<!-- 附件信息区域 -->
<div class="attachment-info">
<h3 class="section-title">附件信息</h3>
<el-table
v-if="uploadedFiles.length > 0"
:data="uploadedFiles"
border
size="small"
class="mt-20px"
>
<el-table-column type="index" label="序号" width="80" align="center" />
<el-table-column prop="name" label="文件名称" align="center" />
<el-table-column prop="uploadTime" label="上传时间" width="200" align="center" />
</el-table>
<div v-else class="no-data">暂无附件</div>
</div>
<!-- 底部按钮区域 -->
<div class="form-footer">
<el-button @click="handleCancel">关闭</el-button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import * as OrderApi from '@/api/biz/tsoorder/'
import { getIntDictOptions, getStrDictOptions, DICT_TYPE } from '@/utils/dict'
const { t } = useI18n()
const message = useMessage()
const dialogVisible = ref(false)
const dialogTitle = ref('订单详情')
const formLoading = ref(false)
const formData = reactive({
id: undefined,
saleOrdNo: undefined,
ordDate: undefined,
custId: undefined,
custName: undefined,
contact: undefined,
conPhone: undefined,
saleMan: undefined,
saleManName: undefined,
saleDeptId: undefined,
saleDeptName: undefined,
ordType: undefined,
paymentTerms: undefined,
taxRate: undefined,
totalAmount: undefined,
reqDeliveryDate: undefined,
isUrgent: undefined,
isChange: undefined,
ordStatus: undefined,
contractNo: undefined,
packReq: undefined,
qualityReq: undefined,
remark: undefined,
attFile: undefined,
proStatus: undefined,
deliveryStatus: undefined,
})
//
const productList = ref([])
//
const uploadedFiles = ref<Array<{ id: string; name: string; uploadTime: string; url: string }>>([])
const open = async (id: number) => {
formLoading.value = true
try {
const response = await OrderApi.getOrder(id)
const data = response.data || response
if (!data || typeof data !== 'object') {
console.error('API响应数据格式异常:', response)
return
}
const normalizeValue = (val: any) => {
if (Array.isArray(val) && val.length > 0) {
return val[0]
}
return val
}
const normalizeDate = (val: any) => {
if (!val) return undefined
if (typeof val === 'string') {
return val
}
return val
}
const cleanedData: any = {}
for (const key in data) {
if (key === 'items') continue
if (key === 'ordDate' || key === 'reqDeliveryDate') {
cleanedData[key] = normalizeDate(data[key])
} else if (key === 'ordStatus' || key === 'deliveryStatus' || key === 'proStatus') {
cleanedData[key] = Number(normalizeValue(data[key])) || 0
} else {
cleanedData[key] = normalizeValue(data[key])
}
}
Object.assign(formData, cleanedData)
//
const rawItems = data?.items
const rows = Array.isArray(rawItems) ? rawItems : (rawItems != null ? [rawItems] : [])
productList.value = rows.length ? rows.map((r) => ({ ...r })) : []
//
const rawAttFile = data?.attFile
if (rawAttFile) {
try {
const attFileArray = typeof rawAttFile === 'string' ? JSON.parse(rawAttFile) : rawAttFile
if (Array.isArray(attFileArray)) {
uploadedFiles.value = attFileArray.map((item: any) => ({
id: item.filePath?.split('/').pop() || Date.now().toString(),
name: item.fileName,
uploadTime: item.uploadTime || '-',
url: item.filePath
}))
}
} catch (e) {
console.error('解析附件信息失败', e)
}
}
} finally {
formLoading.value = false
}
dialogVisible.value = true
}
const handleCancel = () => {
dialogVisible.value = false
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.fullscreen-form {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #f5f7fa;
z-index: 2000;
display: flex;
flex-direction: column;
}
.form-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
background: #fff;
border-bottom: 1px solid #e4e7ed;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
h2 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: #303133;
}
}
.form-content {
flex: 1;
min-height: 0;
min-width: 0;
overflow-y: auto;
padding: 20px;
padding-bottom: 80px;
}
.basic-info,
.product-detail,
.attachment-info {
margin-bottom: 20px;
padding: 15px;
background: #fff;
border-radius: 8px;
}
.section-header {
display: flex;
justify-content: flex-start;
align-items: center;
gap: 10px;
margin-bottom: 15px;
}
.section-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin: 0 0 15px 0;
}
.product-detail .section-title {
margin: 0;
}
.text-right {
text-align: right;
}
.no-data {
text-align: center;
color: #909399;
padding: 20px;
}
.form-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
gap: 15px;
padding: 15px 20px;
background: #fff;
border-top: 1px solid #e4e7ed;
box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.05);
z-index: 2001;
}
.mt-20px {
margin-top: 20px;
}
</style>