重构合同预览和订单详情展示,使用新的OrderDetail组件替代原有的ProductContent组件 调整订单详情表单字段,增加宽度、厚度等必要字段,移除不必要字段 优化表单验证规则和显示逻辑
307 lines
7.4 KiB
Vue
307 lines
7.4 KiB
Vue
<template>
|
||
<div v-loading="loading">
|
||
<!-- 网格布局实现的表格,共8列 -->
|
||
<div class="product-content">
|
||
<!-- 第一行合并所有八个单元格,内容为:嘉祥科伦普重工有限公司 -->
|
||
<div class="table-row table-header">
|
||
<div class="table-cell" colspan="3">
|
||
<div class="company-name">产品名称:{{ productName }}</div>
|
||
</div>
|
||
<div class="table-cell" colspan="5">
|
||
<div class="company-name">生产厂家:嘉祥科伦普重工有限公司</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 第二行为表头 -->
|
||
<div class="table-row">
|
||
<div class="table-cell">序号</div>
|
||
<div class="table-cell">规格(mm)</div>
|
||
<div class="table-cell">材质</div>
|
||
<div class="table-cell">数量(吨)</div>
|
||
<div class="table-cell">含税单价(元/吨)</div>
|
||
<div class="table-cell">不含税单价(元/吨)</div>
|
||
<div class="table-cell">含税总额(元)</div>
|
||
<div class="table-cell">备注</div>
|
||
</div>
|
||
|
||
<!-- 产品行 -->
|
||
<div
|
||
v-for="(item, index) in products"
|
||
:key="index"
|
||
class="table-row"
|
||
:class="{ 'table-row-hover': !readonly }"
|
||
>
|
||
<div class="table-cell">
|
||
<div class="serial-number">
|
||
<span>{{ index + 1 }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="table-cell">
|
||
{{ item.finishedProductSpec }}
|
||
</div>
|
||
<div class="table-cell">
|
||
{{ item.material }}
|
||
</div>
|
||
<div class="table-cell">
|
||
{{ item.weight }}
|
||
</div>
|
||
<div class="table-cell">
|
||
{{ item.contractPrice }}
|
||
</div>
|
||
<div class="table-cell">
|
||
{{ item.itemAmount }}
|
||
</div>
|
||
<div class="table-cell">
|
||
{{ item.contractPrice * item.weight }}
|
||
</div>
|
||
<div class="table-cell">
|
||
{{ item.remark }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 合计行 -->
|
||
<div class="table-row table-total-row">
|
||
<div class="table-cell" colspan="3">合计</div>
|
||
<div class="table-cell">{{ totalQuantity }}</div>
|
||
<div class="table-cell"></div>
|
||
<div class="table-cell"></div>
|
||
<div class="table-cell">{{ totalTaxTotal }}</div>
|
||
<div class="table-cell"></div>
|
||
</div>
|
||
|
||
<!-- 合计人民币(大写) -->
|
||
<div class="table-row">
|
||
<div class="table-cell" colspan="8">
|
||
<span>合计人民币(大写):</span>
|
||
<span>{{ totalAmountInWords }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 备注 -->
|
||
<div class="table-row">
|
||
<div class="table-cell" colspan="8">
|
||
<span>备注:</span>
|
||
<pre>{{ remark }}</pre>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import { listOrderItem } from '@/api/crm/orderItem'
|
||
|
||
export default {
|
||
name: 'ProductContent',
|
||
props: {
|
||
orderId: {
|
||
type: Number,
|
||
default: 0
|
||
},
|
||
remark: {
|
||
type: String,
|
||
default: ''
|
||
},
|
||
readonly: {
|
||
type: Boolean,
|
||
default: false
|
||
}
|
||
},
|
||
data() {
|
||
return {
|
||
loading: false,
|
||
products: [],
|
||
productName: ''
|
||
}
|
||
},
|
||
computed: {
|
||
// 计算总数量(吨)
|
||
totalQuantity() {
|
||
return this.products.reduce((sum, item) => sum + (Number(item.weight) || 0), 0)
|
||
},
|
||
// 计算含税总额(元)
|
||
totalTaxTotal() {
|
||
return this.products.reduce((sum, item) => sum + (Number(item.contractPrice) || 0) * (Number(item.weight) || 0), 0)
|
||
},
|
||
// 计算合计人民币(大写)
|
||
totalAmountInWords() {
|
||
const amount = this.totalTaxTotal
|
||
if (amount === 0) return '零元整'
|
||
|
||
const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
|
||
const units = ['', '拾', '佰', '仟']
|
||
const bigUnits = ['', '万', '亿']
|
||
|
||
let integerPart = Math.floor(amount)
|
||
let decimalPart = Math.round((amount - integerPart) * 100)
|
||
|
||
let result = ''
|
||
let unitIndex = 0
|
||
let bigUnitIndex = 0
|
||
|
||
if (integerPart === 0) {
|
||
result = '零'
|
||
} else {
|
||
while (integerPart > 0) {
|
||
let section = integerPart % 10000
|
||
if (section > 0) {
|
||
let sectionResult = ''
|
||
let sectionUnitIndex = 0
|
||
|
||
while (section > 0) {
|
||
let digit = section % 10
|
||
if (digit > 0) {
|
||
sectionResult = digits[digit] + units[sectionUnitIndex] + sectionResult
|
||
} else if (sectionResult && !sectionResult.startsWith('零')) {
|
||
sectionResult = '零' + sectionResult
|
||
}
|
||
section = Math.floor(section / 10)
|
||
sectionUnitIndex++
|
||
}
|
||
|
||
result = sectionResult + bigUnits[bigUnitIndex] + result
|
||
}
|
||
integerPart = Math.floor(integerPart / 10000)
|
||
bigUnitIndex++
|
||
}
|
||
}
|
||
|
||
result += '元'
|
||
|
||
if (decimalPart === 0) {
|
||
result += '整'
|
||
} else {
|
||
const jiao = Math.floor(decimalPart / 10)
|
||
const fen = decimalPart % 10
|
||
if (jiao > 0) {
|
||
result += digits[jiao] + '角'
|
||
}
|
||
if (fen > 0) {
|
||
result += digits[fen] + '分'
|
||
}
|
||
}
|
||
|
||
return result
|
||
}
|
||
},
|
||
watch: {
|
||
// 监听 orderId 变化,重新获取订单商品列表
|
||
orderId: {
|
||
handler(newVal) {
|
||
if (newVal) {
|
||
this.getOrderItems()
|
||
} else {
|
||
this.products = []
|
||
this.productName = ''
|
||
}
|
||
},
|
||
immediate: true
|
||
}
|
||
},
|
||
methods: {
|
||
// 获取订单商品列表
|
||
async getOrderItems() {
|
||
this.loading = true
|
||
try {
|
||
const res = await listOrderItem({
|
||
orderId: this.orderId
|
||
})
|
||
if (res.code === 200) {
|
||
this.products = res.rows || []
|
||
this.productName = res.rows[0]?.productType || ''
|
||
} else {
|
||
this.products = []
|
||
this.productName = ''
|
||
}
|
||
} catch (error) {
|
||
console.error('获取订单商品列表失败:', error)
|
||
this.products = []
|
||
this.productName = ''
|
||
} finally {
|
||
this.loading = false
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.product-content {
|
||
border: 1px solid #e4e7ed;
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.table-header {
|
||
background-color: #f5f7fa;
|
||
text-align: center;
|
||
border-bottom: 1px solid #e4e7ed;
|
||
}
|
||
|
||
.company-name {
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.table-row {
|
||
display: grid;
|
||
grid-template-columns: 80px 150px 120px 100px 140px 150px 120px 1fr;
|
||
border-bottom: 1px solid #e4e7ed;
|
||
}
|
||
|
||
.table-row-hover:hover {
|
||
background-color: #f5f7fa;
|
||
}
|
||
|
||
.table-header-row {
|
||
background-color: #f5f7fa;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.table-total-row {
|
||
background-color: #f5f7fa;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.table-cell {
|
||
padding: 8px;
|
||
border-right: 1px solid #e4e7ed;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.table-cell:last-child {
|
||
border-right: none;
|
||
}
|
||
|
||
.table-cell[colspan="3"] {
|
||
grid-column: span 3;
|
||
}
|
||
|
||
.table-cell[colspan="5"] {
|
||
grid-column: span 5;
|
||
}
|
||
|
||
.table-cell[colspan="8"] {
|
||
grid-column: span 8;
|
||
}
|
||
|
||
.serial-number {
|
||
position: relative;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.delete-btn {
|
||
opacity: 0;
|
||
margin-left: 10px;
|
||
}
|
||
|
||
.serial-number:hover .delete-btn {
|
||
opacity: 1;
|
||
}
|
||
|
||
.el-input {
|
||
width: 100%;
|
||
}
|
||
</style> |