feat(contract): 启用产品内容组件并优化合同相关功能
- 在合同页面启用ProductContent组件替代注释代码 - 优化ProductContent组件数值计算和空值处理 - 修改ContractList组件从productContent字段获取数据 - 在OrderDetail组件添加"写入合同"功能 - 优化ReceiveTable组件未收款金额计算逻辑
This commit is contained in:
@@ -42,6 +42,8 @@
|
|||||||
<el-table-column label="备注" align="center" prop="remark" />
|
<el-table-column label="备注" align="center" prop="remark" />
|
||||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" v-if="editable">
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" v-if="editable">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
<el-button size="mini" type="text" icon="el-icon-plus"
|
||||||
|
@click="handleWriteToContract(scope.row)">写入合同</el-button>
|
||||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
|
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
|
||||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
|
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -77,17 +79,17 @@
|
|||||||
<el-input v-model="form.material" placeholder="请输入材质" />
|
<el-input v-model="form.material" placeholder="请输入材质" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="重量" prop="weight">
|
<el-form-item label="重量" prop="weight">
|
||||||
<el-input v-model="form.weight" placeholder="请输入重量" />
|
<el-input type="number" v-model="form.weight" placeholder="请输入重量" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="含税单价(元/吨)" prop="contractPrice">
|
<el-form-item label="含税单价(元/吨)" prop="contractPrice">
|
||||||
<el-input v-model="form.contractPrice" placeholder="请输入含税单价" />
|
<el-input type="number" v-model="form.contractPrice" placeholder="请输入含税单价" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="无税单价(元/吨)" prop="itemAmount">
|
<el-form-item label="无税单价(元/吨)" prop="itemAmount">
|
||||||
<el-input v-model="form.itemAmount" placeholder="请输入无税单价" />
|
<el-input type="number" v-model="form.itemAmount" placeholder="请输入无税单价" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="卷数" prop="productNum">
|
<el-form-item label="卷数" prop="productNum">
|
||||||
<el-input v-model="form.productNum" placeholder="请输入卷数" />
|
<el-input type="number" v-model="form.productNum" placeholder="请输入卷数" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="表面处理" prop="surfaceTreatment">
|
<el-form-item label="表面处理" prop="surfaceTreatment">
|
||||||
<el-input v-model="form.surfaceTreatment" placeholder="请输入表面处理" />
|
<el-input v-model="form.surfaceTreatment" placeholder="请输入表面处理" />
|
||||||
@@ -129,7 +131,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { listOrderItem, getOrderItem } from "@/api/crm/orderItem";
|
import { listOrderItem, getOrderItem } from "@/api/crm/orderItem";
|
||||||
import { actions, ORDER_ACTIONS } from "../js/actions";
|
import { actions, ORDER_ACTIONS } from "../js/actions";
|
||||||
import { getOrder } from "@/api/crm/order";
|
import { getOrder, updateOrder } from "@/api/crm/order";
|
||||||
import OrderPrinter from "./OrderPrinter.vue";
|
import OrderPrinter from "./OrderPrinter.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -186,41 +188,9 @@ export default {
|
|||||||
productType: [
|
productType: [
|
||||||
{ required: true, message: "请输入产品类型", trigger: "blur" }
|
{ required: true, message: "请输入产品类型", trigger: "blur" }
|
||||||
],
|
],
|
||||||
// productNum: [
|
|
||||||
// { required: true, message: "请输入产品数量", trigger: "blur" }
|
|
||||||
// ],
|
|
||||||
// rawMaterialSpec: [
|
|
||||||
// { required: true, message: "请输入原料规格", trigger: "blur" }
|
|
||||||
// ],
|
|
||||||
// finishedProductSpec: [
|
|
||||||
// { required: true, message: "请输入成品规格", trigger: "blur" }
|
|
||||||
// ],
|
|
||||||
// 重量和合同定价不能为空,且必须是数字,最多两位小数
|
|
||||||
// weight: [
|
|
||||||
// { required: true, message: "请输入重量", trigger: "blur" },
|
|
||||||
// // 必须是数字,最多两位小数,使用自定义的校验规则
|
|
||||||
// {
|
|
||||||
// validator: (rule, value, callback) => {
|
|
||||||
// if (!/^\d+(\.\d{1,2,3})?$/.test(value)) {
|
|
||||||
// callback(new Error("请输入最多三位小数的数字"));
|
|
||||||
// } else {
|
|
||||||
// callback();
|
|
||||||
// }
|
|
||||||
// }, trigger: "change"
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
contractPrice: [
|
contractPrice: [
|
||||||
{ required: true, message: "请输入合同定价", trigger: "blur" },
|
{ required: true, message: "请输入合同定价", trigger: "blur" },
|
||||||
// 必须是数字,最多两位小数,使用自定义的校验规则
|
// 必须是数字,最多两位小数,使用自定义的校验规则
|
||||||
{
|
|
||||||
validator: (rule, value, callback) => {
|
|
||||||
if (!/^\d+(\.\d{1,2,3})?$/.test(value)) {
|
|
||||||
callback(new Error("请输入最多三位小数的数字"));
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
}, trigger: "change"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
orderContent: {},
|
orderContent: {},
|
||||||
@@ -234,6 +204,9 @@ export default {
|
|||||||
// if (newVal !== oldVal) {
|
// if (newVal !== oldVal) {
|
||||||
this.queryParams.orderId = newVal;
|
this.queryParams.orderId = newVal;
|
||||||
this.getList();
|
this.getList();
|
||||||
|
getOrder(this.orderId).then(response => {
|
||||||
|
this.orderContent = response.data;
|
||||||
|
});
|
||||||
// }
|
// }
|
||||||
},
|
},
|
||||||
immediate: true
|
immediate: true
|
||||||
@@ -301,6 +274,127 @@ export default {
|
|||||||
this.orderLoading = false;
|
this.orderLoading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 计算大写金额
|
||||||
|
totalAmountInWords(amountStr) {
|
||||||
|
const amount = parseFloat(amountStr);
|
||||||
|
if (isNaN(amount)) return '无效的金额格式';
|
||||||
|
|
||||||
|
if (amount === 0) return '零元整';
|
||||||
|
|
||||||
|
const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
|
||||||
|
const units = ['', '拾', '佰', '仟'];
|
||||||
|
const bigUnits = ['', '万', '亿'];
|
||||||
|
|
||||||
|
let integerPart = Math.floor(amount);
|
||||||
|
let decimalPart = Math.round((amount - integerPart) * 100);
|
||||||
|
|
||||||
|
let result = '';
|
||||||
|
|
||||||
|
// 处理整数部分
|
||||||
|
if (integerPart > 0) {
|
||||||
|
let unitIndex = 0;
|
||||||
|
let bigUnitIndex = 0;
|
||||||
|
|
||||||
|
while (integerPart > 0) {
|
||||||
|
let section = integerPart % 10000;
|
||||||
|
if (section > 0) {
|
||||||
|
let sectionResult = '';
|
||||||
|
let temp = section;
|
||||||
|
let unitIndexInSection = 0;
|
||||||
|
|
||||||
|
while (temp > 0) {
|
||||||
|
let digit = temp % 10;
|
||||||
|
if (digit > 0) {
|
||||||
|
sectionResult = digits[digit] + units[unitIndexInSection] + sectionResult;
|
||||||
|
} else {
|
||||||
|
// 避免连续的零
|
||||||
|
if (sectionResult && !sectionResult.startsWith('零')) {
|
||||||
|
sectionResult = '零' + sectionResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
temp = Math.floor(temp / 10);
|
||||||
|
unitIndexInSection++;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = sectionResult + bigUnits[bigUnitIndex] + result;
|
||||||
|
}
|
||||||
|
|
||||||
|
integerPart = Math.floor(integerPart / 10000);
|
||||||
|
bigUnitIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += '元';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理小数部分
|
||||||
|
if (decimalPart === 0) {
|
||||||
|
result += '整';
|
||||||
|
} else {
|
||||||
|
if (decimalPart >= 10) {
|
||||||
|
result += digits[Math.floor(decimalPart / 10)] + '角';
|
||||||
|
}
|
||||||
|
if (decimalPart % 10 > 0) {
|
||||||
|
result += digits[decimalPart % 10] + '分';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
async handleWriteToContract(row) {
|
||||||
|
const { data } = await getOrder(this.orderId);
|
||||||
|
let productContent = data.productContent;
|
||||||
|
try {
|
||||||
|
if (!productContent) {
|
||||||
|
productContent = {
|
||||||
|
productName: '',
|
||||||
|
products: [{
|
||||||
|
spec: row.finishedProductSpec || '',
|
||||||
|
material: row.material || '',
|
||||||
|
quantity: parseFloat(row.weight) || 0,
|
||||||
|
taxPrice: parseFloat(row.contractPrice) || 0,
|
||||||
|
noTaxPrice: parseFloat(row.itemAmount) || 0,
|
||||||
|
taxTotal: parseFloat(row.contractPrice) || 0 * (parseFloat(row.weight) || 0),
|
||||||
|
remark: row.remark || ''
|
||||||
|
}],
|
||||||
|
remark: '',
|
||||||
|
totalQuantity: parseFloat(row.weight) || 0,
|
||||||
|
totalTaxTotal: parseFloat(row.contractPrice) || 0 * (parseFloat(row.weight) || 0),
|
||||||
|
totalAmountInWords: this.totalAmountInWords(parseFloat(row.contractPrice) || 0 * (parseFloat(row.weight) || 0)).toString()
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
productContent = JSON.parse(productContent);
|
||||||
|
productContent.products.push({
|
||||||
|
spec: row.finishedProductSpec || '',
|
||||||
|
material: row.material || '',
|
||||||
|
quantity: parseFloat(row.weight) || 0,
|
||||||
|
taxPrice: parseFloat(row.contractPrice) || 0,
|
||||||
|
noTaxPrice: parseFloat(row.itemAmount) || 0,
|
||||||
|
taxTotal: parseFloat(row.contractPrice) || 0 * (parseFloat(row.weight) || 0),
|
||||||
|
remark: row.remark || ''
|
||||||
|
});
|
||||||
|
// 将现有的全部加和计算
|
||||||
|
productContent.totalQuantity = productContent.products.reduce((acc, cur) => acc + (parseFloat(cur.quantity) || 0), 0);
|
||||||
|
console.log(productContent.totalQuantity);
|
||||||
|
productContent.totalTaxTotal = productContent.products.reduce((acc, cur) => acc + (parseFloat(cur.taxTotal) || 0), 0);
|
||||||
|
productContent.totalAmountInWords = this.totalAmountInWords(productContent.totalTaxTotal).toString();
|
||||||
|
}
|
||||||
|
console.log(productContent);
|
||||||
|
const jsonContent = JSON.stringify(productContent, null, 2);
|
||||||
|
console.log(jsonContent);
|
||||||
|
updateOrder({
|
||||||
|
...this.orderContent,
|
||||||
|
productContent: jsonContent
|
||||||
|
}).then(response => {
|
||||||
|
this.$modal.msgSuccess("写入成功,请刷新合同内容查看");
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
this.$modal.msgError("产品内容格式错误");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(productContent.products);
|
||||||
|
},
|
||||||
printOrder() {
|
printOrder() {
|
||||||
this.$refs["printer"].print();
|
this.$refs["printer"].print();
|
||||||
this.orderOpen = false;
|
this.orderOpen = false;
|
||||||
|
|||||||
@@ -162,7 +162,6 @@ export default {
|
|||||||
return this.receivableList.reduce((total, item) => total + parseFloat(item.amount), 0);
|
return this.receivableList.reduce((total, item) => total + parseFloat(item.amount), 0);
|
||||||
},
|
},
|
||||||
unreceivedAmount() {
|
unreceivedAmount() {
|
||||||
// return this.order ? this.order.totalAmount - this.order.receivedAmount : 0;
|
|
||||||
return this.order ? this.order.orderAmount - this.receivedAmount : 0;
|
return this.order ? this.order.orderAmount - this.receivedAmount : 0;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -232,14 +231,6 @@ export default {
|
|||||||
this.receivableList = response.rows;
|
this.receivableList = response.rows;
|
||||||
this.total = response.total;
|
this.total = response.total;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
if (this.isFirst) {
|
|
||||||
this.isFirst = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
updateOrder({
|
|
||||||
orderId: this.orderId,
|
|
||||||
unpaidAmount: this.unreceivedAmount,
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 取消按钮
|
// 取消按钮
|
||||||
|
|||||||
@@ -261,10 +261,10 @@ export default {
|
|||||||
// 1. 创建excel
|
// 1. 创建excel
|
||||||
const workbook = new ExcelJS.Workbook();
|
const workbook = new ExcelJS.Workbook();
|
||||||
const worksheet = workbook.addWorksheet('产品销售合同');
|
const worksheet = workbook.addWorksheet('产品销售合同');
|
||||||
let orderItems = [];
|
// let orderItems = [];
|
||||||
// 2. 查询合同详情
|
// // 2. 查询合同详情
|
||||||
const res = await listOrderItem({ orderId: row.orderId, pageNum: 1, pageSize: 1000 });
|
// const res = await listOrderItem({ orderId: row.orderId, pageNum: 1, pageSize: 1000 });
|
||||||
orderItems = res.rows || [];
|
// orderItems = res.rows || [];
|
||||||
|
|
||||||
// 2. 设置列宽
|
// 2. 设置列宽
|
||||||
worksheet.columns = [
|
worksheet.columns = [
|
||||||
@@ -408,38 +408,46 @@ export default {
|
|||||||
totalAmountInWords: '零元整'
|
totalAmountInWords: '零元整'
|
||||||
};
|
};
|
||||||
|
|
||||||
if (orderItems) {
|
if (row.productContent) {
|
||||||
try {
|
try {
|
||||||
// 改为从orderItems中获取产品内容
|
productData = JSON.parse(row.productContent);
|
||||||
const productName = orderItems[0].productType || '冷硬钢卷';
|
|
||||||
const remark = row.remark || '';
|
|
||||||
const products = orderItems.map(item => ({
|
|
||||||
spec: item.finishedProductSpec || '',
|
|
||||||
material: item.material || '',
|
|
||||||
quantity: parseFloat(item.weight || 0),
|
|
||||||
taxPrice: parseFloat(item.contractPrice || 0),
|
|
||||||
noTaxPrice: parseFloat(item.itemAmount || 0),
|
|
||||||
taxTotal: parseFloat(item.contractPrice) * parseFloat(item.weight || 0),
|
|
||||||
remark: item.remark || ''
|
|
||||||
}));
|
|
||||||
|
|
||||||
const totalQuantity = products.reduce((acc, product) => acc + parseFloat(product.quantity || 0), 0);
|
|
||||||
const totalTaxTotal = products.reduce((acc, product) => acc + parseFloat(product.taxTotal || 0), 0);
|
|
||||||
const totalAmountInWords = this.convertToChinese(totalTaxTotal);
|
|
||||||
|
|
||||||
productData = {
|
|
||||||
products,
|
|
||||||
productName,
|
|
||||||
remark,
|
|
||||||
totalQuantity,
|
|
||||||
totalTaxTotal,
|
|
||||||
totalAmountInWords
|
|
||||||
};
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('解析产品内容失败:', error);
|
console.error('解析产品内容失败:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (orderItems) {
|
||||||
|
// try {
|
||||||
|
// // 改为从orderItems中获取产品内容
|
||||||
|
// const productName = orderItems[0].productType || '冷硬钢卷';
|
||||||
|
// const remark = row.remark || '';
|
||||||
|
// const products = orderItems.map(item => ({
|
||||||
|
// spec: item.finishedProductSpec || '',
|
||||||
|
// material: item.material || '',
|
||||||
|
// quantity: parseFloat(item.weight || 0),
|
||||||
|
// taxPrice: parseFloat(item.contractPrice || 0),
|
||||||
|
// noTaxPrice: parseFloat(item.itemAmount || 0),
|
||||||
|
// taxTotal: parseFloat(item.contractPrice) * parseFloat(item.weight || 0),
|
||||||
|
// remark: item.remark || ''
|
||||||
|
// }));
|
||||||
|
|
||||||
|
// const totalQuantity = products.reduce((acc, product) => acc + parseFloat(product.quantity || 0), 0);
|
||||||
|
// const totalTaxTotal = products.reduce((acc, product) => acc + parseFloat(product.taxTotal || 0), 0);
|
||||||
|
// const totalAmountInWords = this.convertToChinese(totalTaxTotal);
|
||||||
|
|
||||||
|
// productData = {
|
||||||
|
// products,
|
||||||
|
// productName,
|
||||||
|
// remark,
|
||||||
|
// totalQuantity,
|
||||||
|
// totalTaxTotal,
|
||||||
|
// totalAmountInWords
|
||||||
|
// };
|
||||||
|
// } catch (error) {
|
||||||
|
// console.error('解析产品内容失败:', error);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// 更新产品名称
|
// 更新产品名称
|
||||||
worksheet.getCell('A6').value = `产品名称:${productData.productName}`;
|
worksheet.getCell('A6').value = `产品名称:${productData.productName}`;
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
|
|
||||||
<div style="margin-top: 20px;">
|
<div style="margin-top: 20px;">
|
||||||
<h4 style="margin-bottom: 10px; color: #606266;">一、产品内容</h4>
|
<h4 style="margin-bottom: 10px; color: #606266;">一、产品内容</h4>
|
||||||
<OrderDetail :orderId="contract.orderId" :remark="contract.remark" readonly />
|
<!-- <OrderDetail :orderId="contract.orderId" :remark="contract.remark" readonly /> -->
|
||||||
<!-- <ProductContent v-model="contract.productContent" readonly /> -->
|
<ProductContent v-model="contract.productContent" readonly />
|
||||||
<!-- <div v-html="contract.productContent" style="border: 1px solid #e4e7ed; padding: 10px; border-radius: 4px;"></div> -->
|
<!-- <div v-html="contract.productContent" style="border: 1px solid #e4e7ed; padding: 10px; border-radius: 4px;"></div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -182,13 +182,13 @@
|
|||||||
// 计算总数量
|
// 计算总数量
|
||||||
totalQuantity() {
|
totalQuantity() {
|
||||||
return this.products.reduce((total, item) => {
|
return this.products.reduce((total, item) => {
|
||||||
return total + (item.quantity || 0);
|
return total + (parseFloat(item.quantity) || 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
},
|
},
|
||||||
// 计算总含税总额
|
// 计算总含税总额
|
||||||
totalTaxTotal() {
|
totalTaxTotal() {
|
||||||
return this.products.reduce((total, item) => {
|
return this.products.reduce((total, item) => {
|
||||||
return total + (item.taxTotal || 0);
|
return total + (parseFloat(item.taxTotal) || 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
},
|
},
|
||||||
// 计算大写金额
|
// 计算大写金额
|
||||||
@@ -283,6 +283,12 @@
|
|||||||
// 监听value变化,更新内部数据
|
// 监听value变化,更新内部数据
|
||||||
value: {
|
value: {
|
||||||
handler(newValue) {
|
handler(newValue) {
|
||||||
|
if (!newValue) {
|
||||||
|
this.products = [{}];
|
||||||
|
this.remark = '';
|
||||||
|
this.productName = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.parseContent(newValue);
|
this.parseContent(newValue);
|
||||||
},
|
},
|
||||||
immediate: true
|
immediate: true
|
||||||
|
|||||||
@@ -81,9 +81,9 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- <el-form-item label="产品内容">
|
<el-form-item label="产品内容">
|
||||||
<ProductContent v-model="form.productContent" :readonly="false" />
|
<ProductContent v-model="form.productContent" :readonly="false" />
|
||||||
</el-form-item> -->
|
</el-form-item>
|
||||||
<el-form-item label="合同内容">
|
<el-form-item label="合同内容">
|
||||||
<ContractTemplateManager @select="handleTemplateSelect" />
|
<ContractTemplateManager @select="handleTemplateSelect" />
|
||||||
<editor v-model="form.contractContent" :min-height="192" />
|
<editor v-model="form.contractContent" :min-height="192" />
|
||||||
@@ -326,8 +326,6 @@ export default {
|
|||||||
console.log(customer);
|
console.log(customer);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** 处理合同模板选择 */
|
/** 处理合同模板选择 */
|
||||||
handleTemplateSelect(template) {
|
handleTemplateSelect(template) {
|
||||||
this.form.contractContent = template.dictValue;
|
this.form.contractContent = template.dictValue;
|
||||||
|
|||||||
Reference in New Issue
Block a user