Files
klp-oa/klp-ui/src/views/crm/contract/components/OrderDetail.vue
砂糖 79ee9d572d feat(contract): 替换产品内容组件为订单详情组件并优化表单字段
重构合同预览和订单详情展示,使用新的OrderDetail组件替代原有的ProductContent组件
调整订单详情表单字段,增加宽度、厚度等必要字段,移除不必要字段
优化表单验证规则和显示逻辑
2026-04-17 15:11:09 +08:00

307 lines
7.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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