feat(calc): 引入高精度计算工具并替换原有精度处理逻辑
- 新增基于 decimal.js 的高精度计算工具类 - 在 main.js 中全局挂载 $calc 对象供所有组件使用 - 替换项目中多处使用的 preciseCurrencyRound 方法 - 统一处理加减乘除及四舍五入运算,提升数值计算准确性 - 移除旧的 ruoyi.js 中的精确货币舍入函数 - 更新 package.json 添加 decimal.js 依赖项dev_1.0.0
parent
fb00d486e0
commit
7afab80e0c
|
|
@ -48,7 +48,8 @@
|
||||||
"vue-cropper": "0.5.5",
|
"vue-cropper": "0.5.5",
|
||||||
"vue-router": "3.4.9",
|
"vue-router": "3.4.9",
|
||||||
"vuedraggable": "2.24.3",
|
"vuedraggable": "2.24.3",
|
||||||
"vuex": "3.6.0"
|
"vuex": "3.6.0",
|
||||||
|
"decimal.js": "10.4.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "4.4.6",
|
"@vue/cli-plugin-babel": "4.4.6",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ import Cookies from 'js-cookie'
|
||||||
|
|
||||||
import Element from 'element-ui'
|
import Element from 'element-ui'
|
||||||
import './assets/styles/element-variables.scss'
|
import './assets/styles/element-variables.scss'
|
||||||
|
import * as Calc from '@/utils/calc'
|
||||||
|
|
||||||
|
Vue.prototype.$calc = Calc // 全局挂载
|
||||||
import '@/assets/styles/index.scss' // global css
|
import '@/assets/styles/index.scss' // global css
|
||||||
import '@/assets/styles/ruoyi.scss' // ruoyi css
|
import '@/assets/styles/ruoyi.scss' // ruoyi css
|
||||||
import App from './App'
|
import App from './App'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import Decimal from 'decimal.js'
|
||||||
|
|
||||||
|
// 默认保留小数位(你可根据业务修改,比如金额一般 2 位)
|
||||||
|
const DEFAULT_DP = 2
|
||||||
|
|
||||||
|
// 内部方法:统一转换 Decimal,避免 null/undefined 报错
|
||||||
|
function D(n) {
|
||||||
|
return new Decimal(n || 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保留小数位 & 四舍五入
|
||||||
|
* @param value 数值
|
||||||
|
* @param dp 保留位数(默认 DEFAULT_DP)
|
||||||
|
*/
|
||||||
|
export function toFixed(value, dp = DEFAULT_DP) {
|
||||||
|
return D(value).toDecimalPlaces(dp).toNumber()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加法
|
||||||
|
export function add(a, b, dp = DEFAULT_DP) {
|
||||||
|
return D(a).plus(b).toDecimalPlaces(dp).toNumber()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 减法
|
||||||
|
export function sub(a, b, dp = DEFAULT_DP) {
|
||||||
|
return D(a).minus(b).toDecimalPlaces(dp).toNumber()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 乘法
|
||||||
|
export function mul(a, b, dp = DEFAULT_DP) {
|
||||||
|
return D(a).times(b).toDecimalPlaces(dp).toNumber()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 除法
|
||||||
|
export function div(a, b, dp = DEFAULT_DP) {
|
||||||
|
return D(a).div(b || 1).toDecimalPlaces(dp).toNumber()
|
||||||
|
}
|
||||||
|
|
@ -226,9 +226,4 @@ export function getNormalPath(p) {
|
||||||
export function blobValidate(data) {
|
export function blobValidate(data) {
|
||||||
return data.type !== 'application/json'
|
return data.type !== 'application/json'
|
||||||
}
|
}
|
||||||
export function preciseCurrencyRound(amount,decimalPlace) {
|
|
||||||
if (decimalPlace){
|
|
||||||
return Number(Math.round(amount + `e${decimalPlace}`) + `e-${decimalPlace}`);
|
|
||||||
}
|
|
||||||
return Number(Math.round(amount + 'e2') + 'e-2');
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,6 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {preciseCurrencyRound} from "@/utils/ruoyi";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ConfigInfo",
|
name: "ConfigInfo",
|
||||||
|
|
@ -302,8 +301,9 @@ export default {
|
||||||
if (discount === 1) {
|
if (discount === 1) {
|
||||||
return product.allPrice;
|
return product.allPrice;
|
||||||
}
|
}
|
||||||
const roundedDiscountedUnitPrice = preciseCurrencyRound( product.price * discount);
|
const roundedDiscountedUnitPrice = this.$calc.mul( product.price,discount);
|
||||||
return roundedDiscountedUnitPrice * product.quantity;
|
|
||||||
|
return this.$calc.mul(roundedDiscountedUnitPrice , product.quantity);
|
||||||
},
|
},
|
||||||
calculateTotal(productList, discount) {
|
calculateTotal(productList, discount) {
|
||||||
if (!productList) return 0;
|
if (!productList) return 0;
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SelectProduct from '@/views/system/product/selectProduct.vue';
|
import SelectProduct from '@/views/system/product/selectProduct.vue';
|
||||||
import {preciseCurrencyRound} from "@/utils/ruoyi";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProductConfig',
|
name: 'ProductConfig',
|
||||||
|
|
@ -322,8 +322,8 @@ export default {
|
||||||
quantity: item.quantity || 0,
|
quantity: item.quantity || 0,
|
||||||
taxRate: item.taxRate || 13,
|
taxRate: item.taxRate || 13,
|
||||||
cataloguePriceFormat: this.formatAmount(item.cataloguePrice),
|
cataloguePriceFormat: this.formatAmount(item.cataloguePrice),
|
||||||
guidanceDiscountFormat: item.guidanceDiscount ? preciseCurrencyRound(item.guidanceDiscount * 100, 2) : '',
|
guidanceDiscountFormat: item.guidanceDiscount ? this.$calc.mul(item.guidanceDiscount, 100) : '',
|
||||||
discountFormat: item.discount ? preciseCurrencyRound(item.discount * 100, 2) : '',
|
discountFormat: item.discount ? this.$calc.mul(item.discount, 100) : '',
|
||||||
priceFormat: this.formatAmount(item.price),
|
priceFormat: this.formatAmount(item.price),
|
||||||
allPriceFormat: this.formatAmount(item.allPrice),
|
allPriceFormat: this.formatAmount(item.allPrice),
|
||||||
catalogueAllPriceFormat: this.formatAmount(item.catalogueAllPrice)
|
catalogueAllPriceFormat: this.formatAmount(item.catalogueAllPrice)
|
||||||
|
|
@ -413,9 +413,9 @@ export default {
|
||||||
row.cataloguePrice = product.cataloguePrice;
|
row.cataloguePrice = product.cataloguePrice;
|
||||||
row.cataloguePriceFormat = this.formatAmount(product.cataloguePrice);
|
row.cataloguePriceFormat = this.formatAmount(product.cataloguePrice);
|
||||||
row.guidanceDiscount = product.guidanceDiscount;
|
row.guidanceDiscount = product.guidanceDiscount;
|
||||||
row.guidanceDiscountFormat = product.guidanceDiscount ? preciseCurrencyRound(product.guidanceDiscount * 100, 2) : '';
|
row.guidanceDiscountFormat = product.guidanceDiscount ? this.$calc.mul(product.guidanceDiscount, 100) : '';
|
||||||
row.discount = product.guidanceDiscount || 0;
|
row.discount = product.guidanceDiscount || 0;
|
||||||
row.discountFormat = product.guidanceDiscount ? preciseCurrencyRound(product.guidanceDiscount * 100, 2) : '';
|
row.discountFormat = product.guidanceDiscount ? this.$calc.mul(product.guidanceDiscount, 100) : '';
|
||||||
|
|
||||||
this.calculateRow(row);
|
this.calculateRow(row);
|
||||||
this.emitChange();
|
this.emitChange();
|
||||||
|
|
@ -439,14 +439,13 @@ export default {
|
||||||
if (isNaN(price)) {
|
if (isNaN(price)) {
|
||||||
price = 0;
|
price = 0;
|
||||||
}
|
}
|
||||||
row.price = preciseCurrencyRound(price, 2);
|
row.price = this.$calc.toFixed(price);
|
||||||
row.priceFormat = this.formatAmount(row.price);
|
row.priceFormat = this.formatAmount(row.price);
|
||||||
|
|
||||||
// 如果目录单价存在且不为0,则重新计算折扣
|
// 如果目录单价存在且不为0,则重新计算折扣
|
||||||
if (row.cataloguePrice && row.cataloguePrice > 0) {
|
if (row.cataloguePrice && row.cataloguePrice > 0) {
|
||||||
const discount = row.price / row.cataloguePrice;
|
row.discount = this.$calc.div(row.price,row.cataloguePrice,4) // 精度为4位
|
||||||
row.discount = preciseCurrencyRound(discount, 4); // 精度为4位
|
row.discountFormat = this.$calc.mul(row.discount ,100, 2); // 显示为百分比,保留2位小数
|
||||||
row.discountFormat = preciseCurrencyRound(discount * 100, 2); // 显示为百分比,保留2位小数
|
|
||||||
} else {
|
} else {
|
||||||
// 如果目录单价为0,则折扣也为0
|
// 如果目录单价为0,则折扣也为0
|
||||||
row.discount = 0;
|
row.discount = 0;
|
||||||
|
|
@ -454,9 +453,9 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重新计算总价和目录总价
|
// 重新计算总价和目录总价
|
||||||
row.allPrice = preciseCurrencyRound(row.price * row.quantity, 2);
|
row.allPrice = this.$calc.mul(row.price , row.quantity, 2);
|
||||||
row.allPriceFormat = this.formatAmount(row.allPrice);
|
row.allPriceFormat = this.formatAmount(row.allPrice);
|
||||||
row.catalogueAllPrice = preciseCurrencyRound(row.cataloguePrice * row.quantity, 2);
|
row.catalogueAllPrice = this.$calc.mul(row.cataloguePrice ,row.quantity, 2);
|
||||||
row.catalogueAllPriceFormat = this.formatAmount(row.catalogueAllPrice);
|
row.catalogueAllPriceFormat = this.formatAmount(row.catalogueAllPrice);
|
||||||
|
|
||||||
this.emitChange();
|
this.emitChange();
|
||||||
|
|
@ -466,17 +465,17 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 计算单价 = 目录单价 * 折扣
|
// 计算单价 = 目录单价 * 折扣
|
||||||
const discount = row.discountFormat ? row.discountFormat / 100 : 0;
|
const discount = row.discountFormat ? this.$calc.div(row.discountFormat , 100,4) : 0;
|
||||||
row.discount = preciseCurrencyRound(discount, 4);
|
row.discount = discount;
|
||||||
row.price =preciseCurrencyRound(row.cataloguePrice * discount, 2);
|
row.price =this.$calc.mul(row.cataloguePrice , discount, 2);
|
||||||
row.priceFormat = this.formatAmount(row.price);
|
row.priceFormat = this.formatAmount(row.price);
|
||||||
|
|
||||||
// 计算总价 = 单价 * 数量
|
// 计算总价 = 单价 * 数量
|
||||||
row.allPrice = preciseCurrencyRound(row.price * row.quantity, 2);
|
row.allPrice = this.$calc.mul(row.price , row.quantity, 2);
|
||||||
row.allPriceFormat = this.formatAmount(row.allPrice);
|
row.allPriceFormat = this.formatAmount(row.allPrice);
|
||||||
|
|
||||||
// 计算目录总价 = 目录单价 * 数量
|
// 计算目录总价 = 目录单价 * 数量
|
||||||
row.catalogueAllPrice = preciseCurrencyRound(row.cataloguePrice * row.quantity, 2);
|
row.catalogueAllPrice = this.$calc.mul(row.cataloguePrice , row.quantity, 2);
|
||||||
row.catalogueAllPriceFormat = this.formatAmount(row.catalogueAllPrice);
|
row.catalogueAllPriceFormat = this.formatAmount(row.catalogueAllPrice);
|
||||||
|
|
||||||
this.emitChange();
|
this.emitChange();
|
||||||
|
|
@ -535,7 +534,7 @@ export default {
|
||||||
if (isNaN(cataloguePrice)) {
|
if (isNaN(cataloguePrice)) {
|
||||||
cataloguePrice = 0;
|
cataloguePrice = 0;
|
||||||
}
|
}
|
||||||
row.cataloguePrice = preciseCurrencyRound(cataloguePrice, 2);
|
row.cataloguePrice = this.$calc.toFixed(cataloguePrice, 2);
|
||||||
row.cataloguePriceFormat = this.formatAmount(row.cataloguePrice);
|
row.cataloguePriceFormat = this.formatAmount(row.cataloguePrice);
|
||||||
|
|
||||||
// Recalculate based on new catalogue price
|
// Recalculate based on new catalogue price
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ import { listAllVendor } from "@/api/base/vendor";
|
||||||
import SelectUser from "@/views/system/user/selectUser";
|
import SelectUser from "@/views/system/user/selectUser";
|
||||||
import SelectProduct from "@/views/system/product/selectProduct";
|
import SelectProduct from "@/views/system/product/selectProduct";
|
||||||
import { getDicts } from "@/api/system/dict/data";
|
import { getDicts } from "@/api/system/dict/data";
|
||||||
import {preciseCurrencyRound} from "@/utils/ruoyi";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "PurchaseOrderDetail",
|
name: "PurchaseOrderDetail",
|
||||||
|
|
@ -271,7 +271,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
totalAmountWithTax() {
|
totalAmountWithTax() {
|
||||||
const total = this.form.omsPurchaseOrderItemList?.reduce((acc, cur) => acc + (cur.amountTotal || 0), 0);
|
const total = this.form.omsPurchaseOrderItemList?.reduce((acc, cur) => acc + (cur.amountTotal || 0), 0);
|
||||||
this.form.totalAmount=preciseCurrencyRound(total) || 0;
|
this.form.totalAmount=this.$calc.toFixed(total) || 0;
|
||||||
return this.form.totalAmount;
|
return this.form.totalAmount;
|
||||||
},
|
},
|
||||||
totalAmountWithoutTax() {
|
totalAmountWithoutTax() {
|
||||||
|
|
@ -280,10 +280,10 @@ export default {
|
||||||
const taxRate = cur.taxRate || 0;
|
const taxRate = cur.taxRate || 0;
|
||||||
return acc + (amount / (1 + taxRate));
|
return acc + (amount / (1 + taxRate));
|
||||||
}, 0);
|
}, 0);
|
||||||
return (preciseCurrencyRound(total)) || 0;
|
return (this.$calc.toFixed(total)) || 0;
|
||||||
},
|
},
|
||||||
totalTaxAmount() {
|
totalTaxAmount() {
|
||||||
return (preciseCurrencyRound((this.totalAmountWithTax - this.totalAmountWithoutTax )) ) || 0;
|
return this.$calc.sub(this.totalAmountWithTax , this.totalAmountWithoutTax ) || 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
@ -392,8 +392,8 @@ export default {
|
||||||
/** 计算含税小计 */
|
/** 计算含税小计 */
|
||||||
calculateRowTotal(row) {
|
calculateRowTotal(row) {
|
||||||
if (row.quantity != null && row.price != null) {
|
if (row.quantity != null && row.price != null) {
|
||||||
row.amountTotal = preciseCurrencyRound(row.quantity * row.price);
|
row.amountTotal = this.$calc.mul(row.quantity , row.price);
|
||||||
row.taxTotal = row.amountTotal - preciseCurrencyRound(row.amountTotal / (1 + row.taxRate));
|
row.taxTotal = row.amountTotal - this.$calc.div(row.amountTotal , (1 + row.taxRate));
|
||||||
} else {
|
} else {
|
||||||
row.amountTotal = 0;
|
row.amountTotal = 0;
|
||||||
row.taxTotal = 0;
|
row.taxTotal = 0;
|
||||||
|
|
@ -401,9 +401,9 @@ export default {
|
||||||
},
|
},
|
||||||
/** 获取厂商列表 */
|
/** 获取厂商列表 */
|
||||||
getVendorList() {
|
getVendorList() {
|
||||||
return listAllVendor().then(res => {
|
return listAllVendor().then(res => {
|
||||||
this.vendorOptions = res.data;
|
this.vendorOptions = res.data;
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/** 制造商选择变化 */
|
/** 制造商选择变化 */
|
||||||
handleVendorChange(vendorId) {
|
handleVendorChange(vendorId) {
|
||||||
|
|
@ -414,26 +414,26 @@ export default {
|
||||||
this.form.payMethod=this.selectedVendor.payMethod;
|
this.form.payMethod=this.selectedVendor.payMethod;
|
||||||
} else {
|
} else {
|
||||||
this.selectedVendor = {};
|
this.selectedVendor = {};
|
||||||
this.form.warehouseId = null;
|
this.form.warehouseId = null;
|
||||||
this.currentVendorCode = null;
|
this.currentVendorCode = null;
|
||||||
this.form.payMethod = null;
|
this.form.payMethod = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** 处理采购员选择 */
|
/** 处理采购员选择 */
|
||||||
handlePurchaserSelect(user) {
|
handlePurchaserSelect(user) {
|
||||||
|
|
||||||
console.log(user)
|
console.log(user)
|
||||||
this.$set(this.form, 'purchaserId', user.userId);
|
this.$set(this.form, 'purchaserId', user.userId);
|
||||||
this.$set(this.form, 'purchaserName', user.userName);
|
this.$set(this.form, 'purchaserName', user.userName);
|
||||||
this.$set(this.form, 'purchaserMobile', user.phonenumber);
|
this.$set(this.form, 'purchaserMobile', user.phonenumber);
|
||||||
this.$set(this.form, 'purchaserEmail', user.email);
|
this.$set(this.form, 'purchaserEmail', user.email);
|
||||||
this.purchaserSelectOpen = false;
|
this.purchaserSelectOpen = false;
|
||||||
},
|
},
|
||||||
/** 处理汇智负责人选择 */
|
/** 处理汇智负责人选择 */
|
||||||
handleOwnerSelect(user) {
|
handleOwnerSelect(user) {
|
||||||
this.$set(this.form, 'ownerId', user.userId);
|
this.$set(this.form, 'ownerId', user.userId);
|
||||||
this.$set(this.form, 'ownerName', user.userName);
|
this.$set(this.form, 'ownerName', user.userName);
|
||||||
this.ownerSelectOpen = false;
|
this.ownerSelectOpen = false;
|
||||||
},
|
},
|
||||||
/** 提交按钮 */
|
/** 提交按钮 */
|
||||||
submitForm() {
|
submitForm() {
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@
|
||||||
import {getPurchaseorder, getPurchaseOrderHistory} from "@/api/sip/purchaseorder";
|
import {getPurchaseorder, getPurchaseOrderHistory} from "@/api/sip/purchaseorder";
|
||||||
import {listAllVendor} from "@/api/base/vendor";
|
import {listAllVendor} from "@/api/base/vendor";
|
||||||
import {getDicts} from "@/api/system/dict/data";
|
import {getDicts} from "@/api/system/dict/data";
|
||||||
import {preciseCurrencyRound} from "@/utils/ruoyi";
|
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -277,7 +277,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
totalAmountWithTax() {
|
totalAmountWithTax() {
|
||||||
const total = this.form.omsPurchaseOrderItemList?.reduce((acc, cur) => acc + (cur.amountTotal || 0), 0);
|
const total = this.form.omsPurchaseOrderItemList?.reduce((acc, cur) => acc + (cur.amountTotal || 0), 0);
|
||||||
return preciseCurrencyRound(total) || 0;
|
return this.$calc.toFixed(total) || 0;
|
||||||
},
|
},
|
||||||
totalAmountWithoutTax() {
|
totalAmountWithoutTax() {
|
||||||
const total = this.form.omsPurchaseOrderItemList?.reduce((acc, cur) => {
|
const total = this.form.omsPurchaseOrderItemList?.reduce((acc, cur) => {
|
||||||
|
|
@ -285,10 +285,10 @@ export default {
|
||||||
const taxRate = cur.taxRate || 0;
|
const taxRate = cur.taxRate || 0;
|
||||||
return acc + (amount / (1 + taxRate));
|
return acc + (amount / (1 + taxRate));
|
||||||
}, 0);
|
}, 0);
|
||||||
return (preciseCurrencyRound(total)) || 0;
|
return (this.$calc.toFixed(total)) || 0;
|
||||||
},
|
},
|
||||||
totalTaxAmount() {
|
totalTaxAmount() {
|
||||||
return (preciseCurrencyRound((this.totalAmountWithTax - this.totalAmountWithoutTax))) || 0;
|
return (this.$calc.sub(this.totalAmountWithTax , this.totalAmountWithoutTax)) || 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue