Compare commits
No commits in common. "9be4076df81a27e7fce02f794b39e0ba2a34c324" and "2aa7df132a57c9ed024e1d514f467eb2bed66d79" have entirely different histories.
9be4076df8
...
2aa7df132a
@ -13,7 +13,7 @@ export default {
|
|||||||
"process.env.TARO_API_DOMAIN":
|
"process.env.TARO_API_DOMAIN":
|
||||||
process.env.TARO_ENV === "h5"
|
process.env.TARO_ENV === "h5"
|
||||||
? '"/api"'
|
? '"/api"'
|
||||||
: '"http://api.erp.xunhong168.test"',
|
: '"https://api.erp.qilincloud168.com"',
|
||||||
"process.env.TARO_POSTER_DOMAIN":
|
"process.env.TARO_POSTER_DOMAIN":
|
||||||
process.env.TARO_ENV === "h5"
|
process.env.TARO_ENV === "h5"
|
||||||
? '""'
|
? '""'
|
||||||
|
|||||||
@ -1,84 +1,17 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
import { Image, Text, View } from "@tarojs/components";
|
import { Image, Text, View } from "@tarojs/components";
|
||||||
import { Button, TabPane, Tabs } from "@nutui/nutui-react-taro";
|
import { Button } from "@nutui/nutui-react-taro";
|
||||||
import Taro from "@tarojs/taro";
|
import Taro from "@tarojs/taro";
|
||||||
import { Icon } from "@/components";
|
import { Icon } from "@/components";
|
||||||
import { business, poster } from "@/services";
|
|
||||||
import {
|
|
||||||
exportProfitTableExcel,
|
|
||||||
OrderCalculator,
|
|
||||||
ProfitTableRow,
|
|
||||||
ProfitTableTemplate,
|
|
||||||
} from "@/utils";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
|
|
||||||
interface Step3SuccessProps {
|
interface Step3SuccessProps {
|
||||||
pdfUrl: string;
|
pdfUrl: string;
|
||||||
picUrl?: string;
|
picUrl?: string;
|
||||||
orderVO: BusinessAPI.OrderVO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Step3Success(props: Step3SuccessProps) {
|
export default function Step3Success(props: Step3SuccessProps) {
|
||||||
const { pdfUrl, picUrl, orderVO } = props!;
|
const { pdfUrl, picUrl } = props;
|
||||||
const [tempFilePath, setTempFilePath] = useState<string>();
|
const [tempFilePath, setTempFilePath] = useState<string>();
|
||||||
const [tabValue, setTabValue] = useState<string>("0"); // 默认选中发货单
|
|
||||||
const [excelTempFilePath, setExcelTempFilePath] = useState<string>();
|
|
||||||
|
|
||||||
// 利润表相关状态
|
|
||||||
const [profitPicUrl, setProfitPicUrl] = useState<string>();
|
|
||||||
|
|
||||||
// 获取当前月份
|
|
||||||
const currentMonth = dayjs(orderVO.orderVehicle.deliveryTime).format(
|
|
||||||
"YYYY-MM-01",
|
|
||||||
);
|
|
||||||
const [profitData, setProfitData] = useState<ProfitTableRow[]>([]);
|
|
||||||
|
|
||||||
const init = async (currentMonth: string) => {
|
|
||||||
// 查询本月的所有订单数据
|
|
||||||
const {
|
|
||||||
data: { data: orderVOList = [] },
|
|
||||||
} = await business.order.listOrder({
|
|
||||||
orderListQry: {
|
|
||||||
month: currentMonth,
|
|
||||||
state: "COMPLETED", // 只查询已完成的订单
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取当前车次
|
|
||||||
const currentVehicleNo = orderVO.orderVehicle.vehicleNo;
|
|
||||||
|
|
||||||
// 筛选截止到当前车次之前的数据
|
|
||||||
const profitData: ProfitTableRow[] = [];
|
|
||||||
let includeNext = true;
|
|
||||||
|
|
||||||
// orderVOList 根据车次正序
|
|
||||||
orderVOList.sort((a, b) => {
|
|
||||||
return (
|
|
||||||
Number(a.orderVehicle.vehicleNo) - Number(b.orderVehicle?.vehicleNo)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const order of orderVOList) {
|
|
||||||
// 如果还没有到达当前车次,继续
|
|
||||||
if (includeNext) {
|
|
||||||
const profitRow = calculateOrderProfit(order);
|
|
||||||
profitData.push(profitRow);
|
|
||||||
|
|
||||||
// 如果是当前车次,停止添加
|
|
||||||
if (order.orderVehicle.vehicleNo === currentVehicleNo) {
|
|
||||||
includeNext = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setProfitData(profitData);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (currentMonth) {
|
|
||||||
init(currentMonth).then();
|
|
||||||
}
|
|
||||||
}, [currentMonth]);
|
|
||||||
|
|
||||||
// 保存图片
|
// 保存图片
|
||||||
const handleSaveImage = async () => {
|
const handleSaveImage = async () => {
|
||||||
@ -162,180 +95,10 @@ export default function Step3Success(props: Step3SuccessProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 下载Excel
|
|
||||||
const handleDownloadExcel = async () => {
|
|
||||||
Taro.showToast({
|
|
||||||
title: "正在下载Excel文件",
|
|
||||||
icon: "loading",
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
|
|
||||||
const profitExcelUrl = await exportProfitTableExcel(
|
|
||||||
profitData,
|
|
||||||
currentMonth,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 根据环境选择不同的导出方式
|
|
||||||
const processEnv = process.env.TARO_ENV;
|
|
||||||
|
|
||||||
if (processEnv === "h5") {
|
|
||||||
const link = document.createElement("a");
|
|
||||||
link.href = profitExcelUrl;
|
|
||||||
link.download = `诚信志远利润明细_${currentMonth}.xlsx`;
|
|
||||||
link.style.display = "none";
|
|
||||||
|
|
||||||
// 触发下载
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
|
|
||||||
// 清理URL对象
|
|
||||||
window.URL.revokeObjectURL(profitExcelUrl);
|
|
||||||
|
|
||||||
await Taro.showToast({
|
|
||||||
title: "导出成功",
|
|
||||||
icon: "success",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setExcelTempFilePath(profitExcelUrl);
|
|
||||||
Taro.showToast({
|
|
||||||
title: "Excel下载成功",
|
|
||||||
icon: "success",
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 查看Excel文档
|
|
||||||
const handleViewExcel = async () => {
|
|
||||||
if (!excelTempFilePath) {
|
|
||||||
await handleDownloadExcel();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (excelTempFilePath) {
|
|
||||||
Taro.openDocument({
|
|
||||||
filePath: excelTempFilePath,
|
|
||||||
showMenu: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 保存利润表图片
|
|
||||||
const handleSaveProfitImage = async () => {
|
|
||||||
if (!profitPicUrl) {
|
|
||||||
Taro.showToast({
|
|
||||||
title: "没有可保存的利润表图片",
|
|
||||||
icon: "none",
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 下载文件
|
|
||||||
const downloadRes = await Taro.downloadFile({
|
|
||||||
url: profitPicUrl!,
|
|
||||||
});
|
|
||||||
// 保存图片到相册
|
|
||||||
await Taro.saveImageToPhotosAlbum({
|
|
||||||
filePath: downloadRes.tempFilePath,
|
|
||||||
});
|
|
||||||
|
|
||||||
Taro.showToast({
|
|
||||||
title: "图片已保存到相册",
|
|
||||||
icon: "success",
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error("保存图片失败:", error);
|
|
||||||
Taro.showToast({
|
|
||||||
title: "保存图片失败,请检查相册权限",
|
|
||||||
icon: "none",
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 计算单车的利润数据
|
|
||||||
const calculateOrderProfit = (order: BusinessAPI.OrderVO): ProfitTableRow => {
|
|
||||||
// 车次
|
|
||||||
const vehicleNo = `第${order.orderVehicle.vehicleNo || ""}车`;
|
|
||||||
|
|
||||||
// 发货日期 - 从 orderShipList 获取
|
|
||||||
const shippingDate = dayjs(order.orderVehicle.deliveryTime).format(
|
|
||||||
"YYYY/MM/DD",
|
|
||||||
);
|
|
||||||
|
|
||||||
const orderCalculator = new OrderCalculator(order);
|
|
||||||
// 计算产地成本
|
|
||||||
const originCost = orderCalculator
|
|
||||||
.getCostCalculator()
|
|
||||||
.calculateMelonPurchaseCost();
|
|
||||||
// 报价金额
|
|
||||||
const quoteAmount = orderCalculator.getSalesAmount();
|
|
||||||
// 计算利润
|
|
||||||
const profit = orderCalculator.getPersonalProfit();
|
|
||||||
|
|
||||||
return {
|
|
||||||
vehicleNo,
|
|
||||||
shippingDate,
|
|
||||||
originCost,
|
|
||||||
quoteAmount,
|
|
||||||
profit,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// 生成利润表
|
|
||||||
const generateProfitTable = async () => {
|
|
||||||
try {
|
|
||||||
if (!profitData || profitData.length === 0) {
|
|
||||||
Taro.showToast({
|
|
||||||
title: "本月暂无订单数据",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成预览图片
|
|
||||||
const template = new ProfitTableTemplate(profitData, currentMonth);
|
|
||||||
const {
|
|
||||||
data: { data: picData },
|
|
||||||
} = await poster.poster.postApiV1Poster({
|
|
||||||
html: template.generateHtmlString(),
|
|
||||||
//@ts-ignore
|
|
||||||
format: "a4",
|
|
||||||
});
|
|
||||||
|
|
||||||
setProfitPicUrl(picData?.path);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("生成利润表失败:", error);
|
|
||||||
Taro.showToast({
|
|
||||||
title: "生成利润表失败",
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className="flex flex-1 flex-col overflow-hidden rounded-md bg-gray-100 shadow-md">
|
<View className="flex flex-1 flex-col overflow-hidden rounded-md bg-gray-100 shadow-md">
|
||||||
{/* Tab 切换 */}
|
|
||||||
<View className="bg-white px-2.5 pt-2.5">
|
|
||||||
<Tabs
|
|
||||||
style={{
|
|
||||||
// @ts-ignore
|
|
||||||
"--nutui-tabs-tabpane-padding": 0,
|
|
||||||
}}
|
|
||||||
value={tabValue}
|
|
||||||
onChange={async (value) => {
|
|
||||||
if (value === 1 && !profitPicUrl) {
|
|
||||||
await generateProfitTable();
|
|
||||||
}
|
|
||||||
setTabValue(value.toString());
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<TabPane title="发货单" value={0}>
|
|
||||||
{/* 预览区域 */}
|
{/* 预览区域 */}
|
||||||
<View className="p-2.5">
|
<View className="flex-1 p-2.5">
|
||||||
<View className="rounded-lg bg-white shadow-sm">
|
<View className="rounded-lg bg-white shadow-sm">
|
||||||
{picUrl ? (
|
{picUrl ? (
|
||||||
<View
|
<View
|
||||||
@ -396,15 +159,14 @@ export default function Step3Success(props: Step3SuccessProps) {
|
|||||||
{tempFilePath && (
|
{tempFilePath && (
|
||||||
<View className="flex-1">
|
<View className="flex-1">
|
||||||
<Button
|
<Button
|
||||||
icon={<Icon name="eye" size={16} color={"orange"} />}
|
icon={<Icon name="eye" size={16} />}
|
||||||
type="default"
|
type="primary"
|
||||||
color="orange"
|
|
||||||
fill={"outline"}
|
fill={"outline"}
|
||||||
size={"large"}
|
size={"large"}
|
||||||
block
|
block
|
||||||
onClick={handleViewPDF}
|
onClick={handleViewPDF}
|
||||||
>
|
>
|
||||||
<Text className="text-orange font-medium">查看PDF</Text>
|
<Text className="font-medium">查看PDF</Text>
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
@ -418,100 +180,6 @@ export default function Step3Success(props: Step3SuccessProps) {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</TabPane>
|
|
||||||
|
|
||||||
{orderVO.orderDealer.shareAdjusted && (
|
|
||||||
<TabPane title="利润表" value={1}>
|
|
||||||
{/* 预览区域 */}
|
|
||||||
<View className="p-2.5">
|
|
||||||
<View className="rounded-lg bg-white shadow-sm">
|
|
||||||
{profitPicUrl ? (
|
|
||||||
<View
|
|
||||||
className="overflow-hidden rounded-lg border border-gray-200"
|
|
||||||
style={{ maxHeight: Taro.pxTransform(400) }}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={profitPicUrl}
|
|
||||||
mode="widthFix"
|
|
||||||
className="w-full"
|
|
||||||
onClick={() => {
|
|
||||||
Taro.previewImage({
|
|
||||||
urls: [profitPicUrl],
|
|
||||||
current: profitPicUrl,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<View className="flex h-48 items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50">
|
|
||||||
<Text className="text-gray-500">暂无利润表预览图片</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 底部按钮区域 */}
|
|
||||||
<View className="border-t border-gray-100 bg-white p-2.5">
|
|
||||||
<View className="flex flex-col gap-2.5">
|
|
||||||
{/* 保存利润表图片按钮 */}
|
|
||||||
{profitPicUrl && (
|
|
||||||
<Button
|
|
||||||
icon={<Icon name="download" size={16} color={"white"} />}
|
|
||||||
type="primary"
|
|
||||||
size={"large"}
|
|
||||||
block
|
|
||||||
onClick={handleSaveProfitImage}
|
|
||||||
className="flex items-center justify-center"
|
|
||||||
>
|
|
||||||
<Text className="font-medium">保存图片</Text>
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Excel操作按钮 */}
|
|
||||||
<View className="flex gap-3">
|
|
||||||
<View className="flex-1">
|
|
||||||
<Button
|
|
||||||
icon={
|
|
||||||
<Icon name="file-excel" size={16} color={"white"} />
|
|
||||||
}
|
|
||||||
type="primary"
|
|
||||||
size={"large"}
|
|
||||||
color="orange"
|
|
||||||
block
|
|
||||||
onClick={handleDownloadExcel}
|
|
||||||
>
|
|
||||||
<Text className="font-medium">下载Excel</Text>
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
{excelTempFilePath && (
|
|
||||||
<View className="flex-1">
|
|
||||||
<Button
|
|
||||||
icon={<Icon name="eye" size={16} color={"orange"} />}
|
|
||||||
type="default"
|
|
||||||
color="orange"
|
|
||||||
fill={"outline"}
|
|
||||||
size={"large"}
|
|
||||||
block
|
|
||||||
onClick={handleViewExcel}
|
|
||||||
>
|
|
||||||
<Text className="font-medium">查看Excel</Text>
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 提示信息 */}
|
|
||||||
<View className="text-center">
|
|
||||||
<Text className="text-xs text-gray-500">
|
|
||||||
点击预览图片可放大查看
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</TabPane>
|
|
||||||
)}
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import classNames from "classnames";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export type IconNames =
|
export type IconNames =
|
||||||
| "file-excel"
|
|
||||||
| "copy"
|
| "copy"
|
||||||
| "wallet"
|
| "wallet"
|
||||||
| "download"
|
| "download"
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import { business } from "@/services";
|
|||||||
// 定义ref暴露的方法接口
|
// 定义ref暴露的方法接口
|
||||||
export interface MadeOptionRef {
|
export interface MadeOptionRef {
|
||||||
onAdd: () => void;
|
onAdd: () => void;
|
||||||
scrollToTop: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMadeOptionProps {
|
interface IMadeOptionProps {
|
||||||
@ -46,16 +45,7 @@ export default forwardRef<MadeOptionRef, IMadeOptionProps>(function MadeOption(
|
|||||||
|
|
||||||
const active = Number(value.active);
|
const active = Number(value.active);
|
||||||
|
|
||||||
// 滚动到页面顶部
|
|
||||||
const scrollToTop = () => {
|
|
||||||
Taro.pageScrollTo({
|
|
||||||
scrollTop: 0,
|
|
||||||
duration: 100,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const setActive = (active: number) => {
|
const setActive = (active: number) => {
|
||||||
scrollToTop();
|
|
||||||
onChange({
|
onChange({
|
||||||
...value,
|
...value,
|
||||||
active,
|
active,
|
||||||
@ -261,7 +251,6 @@ export default forwardRef<MadeOptionRef, IMadeOptionProps>(function MadeOption(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollToTop();
|
|
||||||
onChange({
|
onChange({
|
||||||
...value,
|
...value,
|
||||||
active: 2,
|
active: 2,
|
||||||
@ -274,14 +263,10 @@ export default forwardRef<MadeOptionRef, IMadeOptionProps>(function MadeOption(
|
|||||||
orderSupplierId: generateShortId(),
|
orderSupplierId: generateShortId(),
|
||||||
supplierId: "",
|
supplierId: "",
|
||||||
name: "瓜农" + (orderSupplierList.length + 1),
|
name: "瓜农" + (orderSupplierList.length + 1),
|
||||||
payeeName: "",
|
|
||||||
idCard: "",
|
idCard: "",
|
||||||
bankName: "",
|
|
||||||
bankCard: "",
|
bankCard: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
selected: true,
|
selected: true,
|
||||||
loadingMode: orderSupplierList[selectedIndex].loadingMode,
|
|
||||||
pricingMethod: orderSupplierList[selectedIndex].pricingMethod,
|
|
||||||
isPaper: orderSupplierList[selectedIndex].isPaper,
|
isPaper: orderSupplierList[selectedIndex].isPaper,
|
||||||
orderPackageList: [],
|
orderPackageList: [],
|
||||||
productId: orderSupplierList[selectedIndex]?.productId,
|
productId: orderSupplierList[selectedIndex]?.productId,
|
||||||
@ -295,7 +280,6 @@ export default forwardRef<MadeOptionRef, IMadeOptionProps>(function MadeOption(
|
|||||||
// 将校验方法暴露给父组件
|
// 将校验方法暴露给父组件
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
onAdd,
|
onAdd,
|
||||||
scrollToTop,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
async function saveDraft() {
|
async function saveDraft() {
|
||||||
@ -332,7 +316,7 @@ export default forwardRef<MadeOptionRef, IMadeOptionProps>(function MadeOption(
|
|||||||
content: "当前采购订单已暂存成功",
|
content: "当前采购订单已暂存成功",
|
||||||
});
|
});
|
||||||
Taro.redirectTo({
|
Taro.redirectTo({
|
||||||
url: purchase.path["PRODUCTION_PURCHASE"].drafts,
|
url: "/pages/purchase/made/drafts",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import purchase from "@/constant/purchase";
|
|||||||
// 定义ref暴露的方法接口
|
// 定义ref暴露的方法接口
|
||||||
export interface MarketOptionRef {
|
export interface MarketOptionRef {
|
||||||
onAdd: () => void;
|
onAdd: () => void;
|
||||||
scrollToTop: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMarketOptionProps {
|
interface IMarketOptionProps {
|
||||||
@ -40,15 +39,7 @@ export default forwardRef<MarketOptionRef, IMarketOptionProps>(
|
|||||||
|
|
||||||
const active = Number(value.active);
|
const active = Number(value.active);
|
||||||
|
|
||||||
// 滚动到页面顶部
|
|
||||||
const scrollToTop = () => {
|
|
||||||
Taro.pageScrollTo({
|
|
||||||
scrollTop: 0,
|
|
||||||
duration: 100,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const setActive = (active: number) => {
|
const setActive = (active: number) => {
|
||||||
scrollToTop();
|
|
||||||
onChange({
|
onChange({
|
||||||
...value,
|
...value,
|
||||||
active,
|
active,
|
||||||
@ -201,7 +192,6 @@ export default forwardRef<MarketOptionRef, IMarketOptionProps>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollToTop();
|
|
||||||
onChange({
|
onChange({
|
||||||
...value,
|
...value,
|
||||||
active: 2,
|
active: 2,
|
||||||
@ -214,14 +204,11 @@ export default forwardRef<MarketOptionRef, IMarketOptionProps>(
|
|||||||
orderSupplierId: generateShortId(),
|
orderSupplierId: generateShortId(),
|
||||||
supplierId: "",
|
supplierId: "",
|
||||||
name: "档口" + (orderSupplierList.length + 1),
|
name: "档口" + (orderSupplierList.length + 1),
|
||||||
payeeName: "",
|
|
||||||
idCard: "",
|
idCard: "",
|
||||||
bankName: "",
|
|
||||||
bankCard: "",
|
bankCard: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
selected: true,
|
selected: true,
|
||||||
loadingMode: orderSupplierList[selectedIndex].loadingMode,
|
isPaper: orderSupplierList[selectedIndex].isPaper,
|
||||||
pricingMethod: orderSupplierList[selectedIndex].pricingMethod,
|
|
||||||
orderPackageList: [],
|
orderPackageList: [],
|
||||||
productId: orderSupplierList[selectedIndex]?.productId,
|
productId: orderSupplierList[selectedIndex]?.productId,
|
||||||
productName: orderSupplierList[selectedIndex]?.productName,
|
productName: orderSupplierList[selectedIndex]?.productName,
|
||||||
@ -234,7 +221,6 @@ export default forwardRef<MarketOptionRef, IMarketOptionProps>(
|
|||||||
// 将校验方法暴露给父组件
|
// 将校验方法暴露给父组件
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
onAdd,
|
onAdd,
|
||||||
scrollToTop,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
async function saveDraft() {
|
async function saveDraft() {
|
||||||
@ -266,7 +252,7 @@ export default forwardRef<MarketOptionRef, IMarketOptionProps>(
|
|||||||
content: "当前采购订单已暂存成功",
|
content: "当前采购订单已暂存成功",
|
||||||
});
|
});
|
||||||
Taro.redirectTo({
|
Taro.redirectTo({
|
||||||
url: purchase.path["MARKET_PURCHASE"].drafts,
|
url: "/pages/purchase/made/drafts",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -485,8 +485,10 @@ export default forwardRef<OrderVehicleRef, IOrderVehicleProps>(
|
|||||||
plate: newVehicle.plate?.split("-")[0]!,
|
plate: newVehicle.plate?.split("-")[0]!,
|
||||||
dealerId: newVehicle.dealerId || orderVehicle?.dealerId,
|
dealerId: newVehicle.dealerId || orderVehicle?.dealerId,
|
||||||
dealerName: newVehicle.dealerName || orderVehicle?.dealerName,
|
dealerName: newVehicle.dealerName || orderVehicle?.dealerName,
|
||||||
deliveryTime: dayjs().format("YYYY-MM-DD"),
|
openStrawCurtain: false,
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
|
strawCurtainPrice: "",
|
||||||
|
deliveryTime: dayjs().format("YYYY-MM-DD"),
|
||||||
originalData: originalData || "",
|
originalData: originalData || "",
|
||||||
},
|
},
|
||||||
orderDealer: {
|
orderDealer: {
|
||||||
|
|||||||
@ -190,7 +190,7 @@ export default forwardRef<StallInfoRef, IStallInfoProps>(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// 银行名称至少2个字符
|
// 银行名称至少2个字符
|
||||||
return bankName?.length >= 2;
|
return bankName.length >= 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 校验手机号函数
|
// 校验手机号函数
|
||||||
@ -955,7 +955,7 @@ export default forwardRef<StallInfoRef, IStallInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入档口名称"
|
placeholder="请输入档口名称"
|
||||||
value={supplierVO?.name || ""}
|
value={supplierVO.name}
|
||||||
onChange={(value) => handleNameChange(value, supplierVO)}
|
onChange={(value) => handleNameChange(value, supplierVO)}
|
||||||
onBlur={() =>
|
onBlur={() =>
|
||||||
handleNameBlur(
|
handleNameBlur(
|
||||||
@ -982,7 +982,7 @@ export default forwardRef<StallInfoRef, IStallInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入收款人姓名"
|
placeholder="请输入收款人姓名"
|
||||||
value={supplierVO?.payeeName || ""}
|
value={supplierVO.payeeName}
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
handlePayeeNameChange(value, supplierVO)
|
handlePayeeNameChange(value, supplierVO)
|
||||||
}
|
}
|
||||||
@ -1016,7 +1016,7 @@ export default forwardRef<StallInfoRef, IStallInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入银行名称"
|
placeholder="请输入银行名称"
|
||||||
value={supplierVO?.bankName || ""}
|
value={supplierVO.bankName}
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
handleBankNameChange(value, supplierVO)
|
handleBankNameChange(value, supplierVO)
|
||||||
}
|
}
|
||||||
@ -1050,7 +1050,7 @@ export default forwardRef<StallInfoRef, IStallInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="digit"
|
type="digit"
|
||||||
placeholder="请输入银行卡号"
|
placeholder="请输入银行卡号"
|
||||||
value={supplierVO?.bankCard || ""}
|
value={supplierVO.bankCard}
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
handleBankCardChange(value, supplierVO)
|
handleBankCardChange(value, supplierVO)
|
||||||
}
|
}
|
||||||
@ -1079,7 +1079,7 @@ export default forwardRef<StallInfoRef, IStallInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="tel"
|
type="tel"
|
||||||
placeholder="请输入手机号码"
|
placeholder="请输入手机号码"
|
||||||
value={supplierVO?.phone || ""}
|
value={supplierVO.phone}
|
||||||
onChange={(value) => handlePhoneChange(value, supplierVO)}
|
onChange={(value) => handlePhoneChange(value, supplierVO)}
|
||||||
onBlur={() =>
|
onBlur={() =>
|
||||||
handlePhoneBlur(
|
handlePhoneBlur(
|
||||||
@ -1121,6 +1121,9 @@ export default forwardRef<StallInfoRef, IStallInfoProps>(
|
|||||||
微信收款码
|
微信收款码
|
||||||
</View>
|
</View>
|
||||||
<View className="text-sm text-green-600">已上传完成</View>
|
<View className="text-sm text-green-600">已上传完成</View>
|
||||||
|
<View className="text-neutral-darker mt-1 text-xs">
|
||||||
|
若档口无法开发票,则可打款到微信
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className="flex flex-row gap-2.5">
|
<View className="flex flex-row gap-2.5">
|
||||||
@ -1173,6 +1176,9 @@ export default forwardRef<StallInfoRef, IStallInfoProps>(
|
|||||||
<View className="text-neutral-darker mt-1 text-xs">
|
<View className="text-neutral-darker mt-1 text-xs">
|
||||||
支持从相册选择或拍照
|
支持从相册选择或拍照
|
||||||
</View>
|
</View>
|
||||||
|
<View className="mt-2 text-center text-xs text-gray-400">
|
||||||
|
若档口无法开发票,则可打款到微信
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@ -869,7 +869,7 @@ export default forwardRef<SupplierInfoRef, ISupplierInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入姓名"
|
placeholder="请输入姓名"
|
||||||
value={supplierVO?.name || ""}
|
value={supplierVO.name}
|
||||||
onChange={(value) => handleNameChange(value, supplierVO)}
|
onChange={(value) => handleNameChange(value, supplierVO)}
|
||||||
onBlur={() =>
|
onBlur={() =>
|
||||||
handleNameBlur(
|
handleNameBlur(
|
||||||
@ -896,7 +896,7 @@ export default forwardRef<SupplierInfoRef, ISupplierInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="idcard"
|
type="idcard"
|
||||||
placeholder="请输入身份证号"
|
placeholder="请输入身份证号"
|
||||||
value={supplierVO?.idCard || ""}
|
value={supplierVO.idCard || ""}
|
||||||
onChange={(value) => handleIdCardChange(value, supplierVO)}
|
onChange={(value) => handleIdCardChange(value, supplierVO)}
|
||||||
onBlur={() =>
|
onBlur={() =>
|
||||||
handleIdCardBlur(
|
handleIdCardBlur(
|
||||||
@ -921,7 +921,7 @@ export default forwardRef<SupplierInfoRef, ISupplierInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="请输入银行名称"
|
placeholder="请输入银行名称"
|
||||||
value={supplierVO?.bankName || ""}
|
value={supplierVO.bankName || ""}
|
||||||
onChange={(value) => handleBankNameChange(value, supplierVO)}
|
onChange={(value) => handleBankNameChange(value, supplierVO)}
|
||||||
onBlur={() =>
|
onBlur={() =>
|
||||||
handleBankNameBlur(
|
handleBankNameBlur(
|
||||||
@ -953,7 +953,7 @@ export default forwardRef<SupplierInfoRef, ISupplierInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="digit"
|
type="digit"
|
||||||
placeholder="请输入银行卡号"
|
placeholder="请输入银行卡号"
|
||||||
value={supplierVO?.bankCard || ""}
|
value={supplierVO.bankCard || ""}
|
||||||
onChange={(value) => handleBankCardChange(value, supplierVO)}
|
onChange={(value) => handleBankCardChange(value, supplierVO)}
|
||||||
onBlur={() =>
|
onBlur={() =>
|
||||||
handleBankCardBlur(
|
handleBankCardBlur(
|
||||||
@ -978,7 +978,7 @@ export default forwardRef<SupplierInfoRef, ISupplierInfoProps>(
|
|||||||
clearable
|
clearable
|
||||||
type="tel"
|
type="tel"
|
||||||
placeholder="请输入手机号码"
|
placeholder="请输入手机号码"
|
||||||
value={supplierVO?.phone || ""}
|
value={supplierVO.phone}
|
||||||
onChange={(value) => handlePhoneChange(value, supplierVO)}
|
onChange={(value) => handlePhoneChange(value, supplierVO)}
|
||||||
onBlur={() =>
|
onBlur={() =>
|
||||||
handlePhoneBlur(
|
handlePhoneBlur(
|
||||||
|
|||||||
@ -95,14 +95,6 @@ export default function TicketUpload(props: ITicketUploadProps) {
|
|||||||
{supplierVO.netWeight || 0}
|
{supplierVO.netWeight || 0}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className="flex justify-between text-sm">
|
|
||||||
<View className="text-neutral-darker text-sm">
|
|
||||||
毛重量(斤)
|
|
||||||
</View>
|
|
||||||
<View className="font-medium text-gray-800">
|
|
||||||
{supplierVO.grossWeight || 0}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<View className="flex justify-between text-sm">
|
<View className="flex justify-between text-sm">
|
||||||
<View className="text-neutral-darker text-sm">
|
<View className="text-neutral-darker text-sm">
|
||||||
采购单价(元/斤)
|
采购单价(元/斤)
|
||||||
@ -175,7 +167,7 @@ export default function TicketUpload(props: ITicketUploadProps) {
|
|||||||
...supplierVO!,
|
...supplierVO!,
|
||||||
invoiceImg: [],
|
invoiceImg: [],
|
||||||
invoiceUpload: false,
|
invoiceUpload: false,
|
||||||
invoiceId: undefined,
|
invoiceId: 0,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -193,7 +185,7 @@ export default function TicketUpload(props: ITicketUploadProps) {
|
|||||||
...supplierVO!,
|
...supplierVO!,
|
||||||
invoiceImg: [],
|
invoiceImg: [],
|
||||||
invoiceUpload: false,
|
invoiceUpload: false,
|
||||||
invoiceId: undefined,
|
invoiceId: 0,
|
||||||
});
|
});
|
||||||
Toast.show("toast", {
|
Toast.show("toast", {
|
||||||
title: "删除成功",
|
title: "删除成功",
|
||||||
|
|||||||
@ -27,8 +27,8 @@ export default function OrderSupplierPicker(props: IOrderSupplierPickerProps) {
|
|||||||
const [orderSupplierList, setOrderSupplierList] = useState<
|
const [orderSupplierList, setOrderSupplierList] = useState<
|
||||||
BusinessAPI.OrderSupplierVO[]
|
BusinessAPI.OrderSupplierVO[]
|
||||||
>([]);
|
>([]);
|
||||||
// 瓜农
|
// 发票开具人(有开发票资质的瓜农)
|
||||||
const [supplierVO, setSupplierVO] = useState<BusinessAPI.SupplierVO>();
|
const [invoiceIssuer, setInvoiceIssuer] = useState<BusinessAPI.SupplierVO>();
|
||||||
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -112,7 +112,7 @@ export default function OrderSupplierPicker(props: IOrderSupplierPickerProps) {
|
|||||||
<SupplierPicker
|
<SupplierPicker
|
||||||
type={"FARMER"}
|
type={"FARMER"}
|
||||||
onFinish={(supplierVO) => {
|
onFinish={(supplierVO) => {
|
||||||
setSupplierVO(supplierVO);
|
setInvoiceIssuer(supplierVO);
|
||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
}}
|
}}
|
||||||
trigger={
|
trigger={
|
||||||
@ -120,14 +120,14 @@ export default function OrderSupplierPicker(props: IOrderSupplierPickerProps) {
|
|||||||
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
||||||
>
|
>
|
||||||
<View className={"text-primary text-xs"}>
|
<View className={"text-primary text-xs"}>
|
||||||
{supplierVO?.name || "瓜农"}
|
{invoiceIssuer?.name || "发票开具人"}
|
||||||
</View>
|
</View>
|
||||||
{supplierVO?.name ? (
|
{invoiceIssuer?.name ? (
|
||||||
<Icon
|
<Icon
|
||||||
name={"circle-xmark"}
|
name={"circle-xmark"}
|
||||||
size={16}
|
size={16}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
setSupplierVO(undefined);
|
setInvoiceIssuer(undefined);
|
||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}}
|
}}
|
||||||
@ -390,7 +390,6 @@ export default function OrderSupplierPicker(props: IOrderSupplierPickerProps) {
|
|||||||
invoiceUpload: false,
|
invoiceUpload: false,
|
||||||
poStates: ["AUDITING", "COMPLETED"],
|
poStates: ["AUDITING", "COMPLETED"],
|
||||||
poType: "PRODUCTION_PURCHASE",
|
poType: "PRODUCTION_PURCHASE",
|
||||||
supplierId: supplierVO?.supplierId,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
// App 相关常量
|
// App 相关常量
|
||||||
export const APP_VERSION = "v0.0.69";
|
export const APP_VERSION = "v0.0.65";
|
||||||
|
|||||||
@ -57,13 +57,11 @@ const path = {
|
|||||||
create: "/pages/purchase/made/create",
|
create: "/pages/purchase/made/create",
|
||||||
preview: "/pages/purchase/made/preview",
|
preview: "/pages/purchase/made/preview",
|
||||||
result: "/pages/purchase/made/result",
|
result: "/pages/purchase/made/result",
|
||||||
drafts: "/pages/purchase/made/drafts",
|
|
||||||
},
|
},
|
||||||
MARKET_PURCHASE: {
|
MARKET_PURCHASE: {
|
||||||
create: "/pages/purchase/market/create",
|
create: "/pages/purchase/market/create",
|
||||||
preview: "/pages/purchase/market/preview",
|
preview: "/pages/purchase/market/preview",
|
||||||
result: "/pages/purchase/market/result",
|
result: "/pages/purchase/market/result",
|
||||||
drafts: "/pages/purchase/market/drafts",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 5042354 */
|
font-family: "iconfont"; /* Project id 5042354 */
|
||||||
src:
|
src:
|
||||||
url("//at.alicdn.com/t/c/font_5042354_y6uqn91vagr.woff2?t=1767522385418")
|
url("//at.alicdn.com/t/c/font_5042354_c95qf1bojkl.woff2?t=1766645005700")
|
||||||
format("woff2"),
|
format("woff2"),
|
||||||
url("//at.alicdn.com/t/c/font_5042354_y6uqn91vagr.woff?t=1767522385418")
|
url("//at.alicdn.com/t/c/font_5042354_c95qf1bojkl.woff?t=1766645005700")
|
||||||
format("woff"),
|
format("woff"),
|
||||||
url("//at.alicdn.com/t/c/font_5042354_y6uqn91vagr.ttf?t=1767522385418")
|
url("//at.alicdn.com/t/c/font_5042354_c95qf1bojkl.ttf?t=1766645005700")
|
||||||
format("truetype");
|
format("truetype");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,10 +17,6 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-file-excel:before {
|
|
||||||
content: "\e639";
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-wallet:before {
|
.icon-wallet:before {
|
||||||
content: "\e638";
|
content: "\e638";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -251,8 +251,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{orderVO.orderDealer?.enableLoss &&
|
{orderVO.orderDealer?.enableLoss && (
|
||||||
Number(orderVO.orderDealer?.lossAmount) > 0 && (
|
|
||||||
<View className="cost-item flex flex-col px-3 py-2">
|
<View className="cost-item flex flex-col px-3 py-2">
|
||||||
<View className="text-sm text-gray-500">损耗金额</View>
|
<View className="text-sm text-gray-500">损耗金额</View>
|
||||||
<View className="font-medium">
|
<View className="font-medium">
|
||||||
@ -261,7 +260,8 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{Number(orderVO.orderDealer?.taxProvision || 0) > 0 && (
|
{orderVO.orderDealer?.taxProvision &&
|
||||||
|
orderVO.orderDealer?.taxProvision > 0 && (
|
||||||
<View className="cost-item flex flex-col px-3 py-2">
|
<View className="cost-item flex flex-col px-3 py-2">
|
||||||
<View className="text-sm text-gray-500">计提税金</View>
|
<View className="text-sm text-gray-500">计提税金</View>
|
||||||
<View className="font-medium">
|
<View className="font-medium">
|
||||||
@ -270,7 +270,8 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{Number(orderVO.orderDealer?.taxSubsidy || 0) > 0 && (
|
{orderVO.orderDealer?.taxSubsidy &&
|
||||||
|
orderVO.orderDealer?.taxSubsidy > 0 && (
|
||||||
<View className="cost-item flex flex-col px-3 py-2">
|
<View className="cost-item flex flex-col px-3 py-2">
|
||||||
<View className="text-sm text-gray-500">公司返点</View>
|
<View className="text-sm text-gray-500">公司返点</View>
|
||||||
<View className="font-medium">
|
<View className="font-medium">
|
||||||
@ -279,8 +280,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{orderVO.orderRebate &&
|
{orderVO.orderRebate?.amount && orderVO.orderRebate?.amount > 0 && (
|
||||||
Number(orderVO.orderRebate.amount || 0) > 0 && (
|
|
||||||
<View className="cost-item flex flex-col px-3 py-2">
|
<View className="cost-item flex flex-col px-3 py-2">
|
||||||
<View className="text-sm text-gray-500">个人返点</View>
|
<View className="text-sm text-gray-500">个人返点</View>
|
||||||
<View className="font-medium">
|
<View className="font-medium">
|
||||||
@ -289,7 +289,8 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{Number(orderVO.orderDealer?.costDifference || 0) > 0 && (
|
{orderVO.orderDealer?.costDifference &&
|
||||||
|
orderVO.orderDealer?.costDifference > 0 && (
|
||||||
<View className="cost-item flex flex-col px-3 py-2">
|
<View className="cost-item flex flex-col px-3 py-2">
|
||||||
<View className="text-sm text-gray-500">调诚信志远分成</View>
|
<View className="text-sm text-gray-500">调诚信志远分成</View>
|
||||||
<View className="font-medium">
|
<View className="font-medium">
|
||||||
|
|||||||
@ -719,7 +719,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
|
|
||||||
console.log("orderVO", orderVO);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View
|
<View
|
||||||
@ -862,14 +861,14 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
"text-red-500": personalProfit < 0,
|
"text-red-500": personalProfit < 0,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
¥ {personalProfit || "0"}
|
¥ {personalProfit || "-"}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className="flex justify-between gap-2 border-t border-gray-200 p-2.5">
|
<View className="flex justify-between gap-2 border-t border-gray-200 p-2.5">
|
||||||
{orderVO.state === "AUDITING" &&
|
{auditVO?.type === "REVIEWER_AUDIT" &&
|
||||||
(orderVO.auditState === "PENDING_QUOTE_APPROVAL" ||
|
(auditVO.state === "WAITING_AUDIT" ||
|
||||||
orderVO.auditState === "BOSS_REJECTED") ? (
|
auditVO.state === "AUDIT_REJECTED") ? (
|
||||||
<>
|
<>
|
||||||
<View className={"flex-1"}>
|
<View className={"flex-1"}>
|
||||||
<Button
|
<Button
|
||||||
@ -882,10 +881,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{auditVO &&
|
|
||||||
auditVO?.type === "REVIEWER_AUDIT" &&
|
|
||||||
(auditVO.state === "WAITING_AUDIT" ||
|
|
||||||
auditVO.state === "AUDIT_REJECTED") && (
|
|
||||||
<View className={"flex-1"}>
|
<View className={"flex-1"}>
|
||||||
<OrderRejectApprove
|
<OrderRejectApprove
|
||||||
size={"large"}
|
size={"large"}
|
||||||
@ -897,7 +892,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)}
|
|
||||||
<View className={"flex-1"}>
|
<View className={"flex-1"}>
|
||||||
<Button
|
<Button
|
||||||
block
|
block
|
||||||
|
|||||||
@ -364,11 +364,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
{step === 2 && <DeliveryStep2Preview moduleList={moduleList} />}
|
{step === 2 && <DeliveryStep2Preview moduleList={moduleList} />}
|
||||||
|
|
||||||
{step === 3 && pdfUrl && (
|
{step === 3 && pdfUrl && (
|
||||||
<DeliveryStep3Success
|
<DeliveryStep3Success pdfUrl={pdfUrl} picUrl={picUrl} />
|
||||||
pdfUrl={pdfUrl}
|
|
||||||
picUrl={picUrl}
|
|
||||||
orderVO={orderVO}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@ -275,7 +275,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
value={order as any}
|
value={order as any}
|
||||||
onChange={(orderVO: BusinessAPI.OrderVO) => {
|
onChange={(orderVO: BusinessAPI.OrderVO) => {
|
||||||
setOrder(orderVO);
|
setOrder(orderVO);
|
||||||
orderOptionRef.current?.scrollToTop();
|
|
||||||
}}
|
}}
|
||||||
melonFarmerRefs={supplierInfoRefs}
|
melonFarmerRefs={supplierInfoRefs}
|
||||||
weighRefs={supplierWeighRefs}
|
weighRefs={supplierWeighRefs}
|
||||||
|
|||||||
@ -605,6 +605,9 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
微信收款码
|
微信收款码
|
||||||
</View>
|
</View>
|
||||||
<View className="text-sm text-green-600">已上传完成</View>
|
<View className="text-sm text-green-600">已上传完成</View>
|
||||||
|
<View className="text-neutral-darker mt-1 text-xs">
|
||||||
|
若档口无法开发票,则可打款到微信
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className="flex flex-row gap-2.5">
|
<View className="flex flex-row gap-2.5">
|
||||||
@ -657,6 +660,9 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
<View className="text-neutral-darker mt-1 text-xs">
|
<View className="text-neutral-darker mt-1 text-xs">
|
||||||
支持从相册选择或拍照
|
支持从相册选择或拍照
|
||||||
</View>
|
</View>
|
||||||
|
<View className="mt-2 text-center text-xs text-gray-400">
|
||||||
|
若档口无法开发票,则可打款到微信
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@ -3219,8 +3219,6 @@ declare namespace BusinessAPI {
|
|||||||
| "BOSS_REJECTED";
|
| "BOSS_REJECTED";
|
||||||
/** 采购类型:1_产地采购;2_市场采购; */
|
/** 采购类型:1_产地采购;2_市场采购; */
|
||||||
type?: "PRODUCTION_PURCHASE" | "MARKET_PURCHASE";
|
type?: "PRODUCTION_PURCHASE" | "MARKET_PURCHASE";
|
||||||
/** 月份 */
|
|
||||||
month?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type OrderPackage = {
|
type OrderPackage = {
|
||||||
@ -3318,7 +3316,7 @@ declare namespace BusinessAPI {
|
|||||||
/** 返点单价 */
|
/** 返点单价 */
|
||||||
unitPrice?: number;
|
unitPrice?: number;
|
||||||
/** 返点金额 */
|
/** 返点金额 */
|
||||||
amount: number;
|
amount?: number;
|
||||||
/** 是否已付款 */
|
/** 是否已付款 */
|
||||||
isPaid?: boolean;
|
isPaid?: boolean;
|
||||||
};
|
};
|
||||||
@ -3449,10 +3447,6 @@ declare namespace BusinessAPI {
|
|||||||
pdfUrl?: string;
|
pdfUrl?: string;
|
||||||
/** 图片文件地址 */
|
/** 图片文件地址 */
|
||||||
picUrl?: string;
|
picUrl?: string;
|
||||||
/** 利润表图片文件地址 */
|
|
||||||
profitPicUrl?: string;
|
|
||||||
/** 利润表文件地址 */
|
|
||||||
profitExcelUrl?: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type OrderShipCreateCmd = {
|
type OrderShipCreateCmd = {
|
||||||
@ -3651,10 +3645,6 @@ declare namespace BusinessAPI {
|
|||||||
pdfUrl?: string;
|
pdfUrl?: string;
|
||||||
/** 图片文件地址 */
|
/** 图片文件地址 */
|
||||||
picUrl?: string;
|
picUrl?: string;
|
||||||
/** 利润表图片文件地址 */
|
|
||||||
profitPicUrl?: string;
|
|
||||||
/** 利润表文件地址 */
|
|
||||||
profitExcelUrl?: string;
|
|
||||||
/** 发货单状态:0_草稿;1_待发货;2_待回款;3_待改签;4_部分回款;5_已回款;6_拒收完结;7_已完结; */
|
/** 发货单状态:0_草稿;1_待发货;2_待回款;3_待改签;4_部分回款;5_已回款;6_拒收完结;7_已完结; */
|
||||||
state:
|
state:
|
||||||
| "DRAFT"
|
| "DRAFT"
|
||||||
|
|||||||
@ -16,10 +16,6 @@ export class OrderRules {
|
|||||||
* 是否包含草帘费成本
|
* 是否包含草帘费成本
|
||||||
*/
|
*/
|
||||||
shouldIncludeStrawCurtainCost(): boolean {
|
shouldIncludeStrawCurtainCost(): boolean {
|
||||||
if (!this.order.orderDealer?.strawMatCostFlag) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!(
|
return !!(
|
||||||
this.order.orderVehicle?.openStrawCurtain &&
|
this.order.orderVehicle?.openStrawCurtain &&
|
||||||
this.order.orderVehicle?.strawCurtainPrice
|
this.order.orderVehicle?.strawCurtainPrice
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export class DecimalUtils {
|
|||||||
* 创建 Decimal 实例
|
* 创建 Decimal 实例
|
||||||
*/
|
*/
|
||||||
static create(value: number | string | Decimal = 0): Decimal {
|
static create(value: number | string | Decimal = 0): Decimal {
|
||||||
return new Decimal(value || 0);
|
return new Decimal(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,7 +69,7 @@ export class DecimalUtils {
|
|||||||
if (!b || this.create(b).isZero()) {
|
if (!b || this.create(b).isZero()) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
return this.create(a).div(b).toDecimalPlaces(2).toNumber();
|
return this.create(a).div(b).toNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -74,8 +74,20 @@ export class SalesCalculator {
|
|||||||
* 计算平均销售单价(老板看的市场报价)
|
* 计算平均销售单价(老板看的市场报价)
|
||||||
*/
|
*/
|
||||||
calculateAverageSalesPrice(): number {
|
calculateAverageSalesPrice(): number {
|
||||||
const totalSalesPrice = this.calculateSalesAmount();
|
if (!this.order.orderSupplierList.length) {
|
||||||
return DecimalUtils.divide(totalSalesPrice, this.calculateTotalWeight(), 0);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalSalesPrice = this.order.orderSupplierList.reduce(
|
||||||
|
(total, supplier) => DecimalUtils.add(total, supplier.salePrice || 0),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
return DecimalUtils.divide(
|
||||||
|
totalSalesPrice,
|
||||||
|
this.order.orderSupplierList.length,
|
||||||
|
0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -0,0 +1,285 @@
|
|||||||
|
import { DecimalUtils } from "../core/DecimalUtils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 农户重量计算器
|
||||||
|
* 负责计算每个农户的净重和毛重
|
||||||
|
*/
|
||||||
|
export class StallWeightCalculator {
|
||||||
|
private suppliers: BusinessAPI.OrderSupplier[];
|
||||||
|
private initialEmptyWeight: number;
|
||||||
|
private previousTotalWeight: number;
|
||||||
|
|
||||||
|
constructor(suppliers: BusinessAPI.OrderSupplier[]) {
|
||||||
|
this.suppliers = suppliers || [];
|
||||||
|
this.initialEmptyWeight = this.suppliers[0]?.emptyWeight || 0;
|
||||||
|
this.previousTotalWeight = this.initialEmptyWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算所有农户的重量信息
|
||||||
|
* @returns 处理后的供应商列表
|
||||||
|
*/
|
||||||
|
calculate(): BusinessAPI.OrderSupplier[] {
|
||||||
|
if (!this.suppliers.length) {
|
||||||
|
return this.suppliers;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < this.suppliers.length; i++) {
|
||||||
|
const supplier = this.suppliers[i];
|
||||||
|
this.calculateSupplierWeight(supplier, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.suppliers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算单个供应商的重量
|
||||||
|
*/
|
||||||
|
private calculateSupplierWeight(
|
||||||
|
supplier: BusinessAPI.OrderSupplier,
|
||||||
|
index: number,
|
||||||
|
): void {
|
||||||
|
const isFirstSupplier = index === 0;
|
||||||
|
const isLastSupplier = supplier.isLast;
|
||||||
|
|
||||||
|
// 设置空磅重量
|
||||||
|
this.setEmptyWeight(supplier, index);
|
||||||
|
|
||||||
|
// 计算各类纸箱重量
|
||||||
|
const weights = this.calculateAllBoxWeights(
|
||||||
|
supplier.orderPackageList || [],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!supplier.isPaper) {
|
||||||
|
// 非纸箱包装的简化计算
|
||||||
|
this.calculateNonPaperSupplier(supplier, weights.used);
|
||||||
|
} else {
|
||||||
|
// 纸箱包装的复杂计算
|
||||||
|
this.calculatePaperSupplier(
|
||||||
|
supplier,
|
||||||
|
weights,
|
||||||
|
isFirstSupplier,
|
||||||
|
isLastSupplier,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算发票金额
|
||||||
|
this.calculateInvoiceAmount(supplier);
|
||||||
|
|
||||||
|
// 更新上一个供应商的总重量
|
||||||
|
this.previousTotalWeight = supplier.totalWeight || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置空磅重量
|
||||||
|
*/
|
||||||
|
private setEmptyWeight(
|
||||||
|
supplier: BusinessAPI.OrderSupplier,
|
||||||
|
index: number,
|
||||||
|
): void {
|
||||||
|
if (index === 0) {
|
||||||
|
// 第一个农户保持原有空磅重量
|
||||||
|
} else {
|
||||||
|
// 其他农户使用前一个农户的总磅重量
|
||||||
|
supplier.emptyWeight = this.suppliers[index - 1]?.totalWeight || 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算所有类型的纸箱重量
|
||||||
|
*/
|
||||||
|
private calculateAllBoxWeights(packages: BusinessAPI.OrderPackage[]) {
|
||||||
|
return {
|
||||||
|
used: this.calculateBoxWeightByType(packages, "USED"),
|
||||||
|
extra: this.calculateBoxWeightByType(packages, "EXTRA"),
|
||||||
|
remain: this.calculateBoxWeightByType(packages, "REMAIN"),
|
||||||
|
extraUsed: this.calculateBoxWeightByType(packages, "EXTRA_USED"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算非纸箱包装供应商的重量
|
||||||
|
*/
|
||||||
|
private calculateNonPaperSupplier(
|
||||||
|
supplier: BusinessAPI.OrderSupplier,
|
||||||
|
usedBoxesWeight: number,
|
||||||
|
): void {
|
||||||
|
// 毛重 = (总磅 - 空磅) × 2
|
||||||
|
supplier.grossWeight = DecimalUtils.multiply(
|
||||||
|
DecimalUtils.subtract(
|
||||||
|
supplier.totalWeight || 0,
|
||||||
|
supplier.emptyWeight || 0,
|
||||||
|
),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 净重 = 毛重 - 使用纸箱重量
|
||||||
|
supplier.netWeight = DecimalUtils.subtract(
|
||||||
|
supplier.grossWeight || 0,
|
||||||
|
usedBoxesWeight,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算纸箱包装供应商的重量
|
||||||
|
*/
|
||||||
|
private calculatePaperSupplier(
|
||||||
|
supplier: BusinessAPI.OrderSupplier,
|
||||||
|
weights: { used: number; extra: number; remain: number; extraUsed: number },
|
||||||
|
isFirstSupplier: boolean,
|
||||||
|
isLastSupplier: boolean,
|
||||||
|
): void {
|
||||||
|
const weightDiff = isFirstSupplier
|
||||||
|
? DecimalUtils.subtract(
|
||||||
|
supplier.totalWeight || 0,
|
||||||
|
this.initialEmptyWeight,
|
||||||
|
)
|
||||||
|
: DecimalUtils.subtract(
|
||||||
|
supplier.totalWeight || 0,
|
||||||
|
this.previousTotalWeight,
|
||||||
|
);
|
||||||
|
|
||||||
|
const weightDiffInJin = DecimalUtils.multiply(weightDiff, 2);
|
||||||
|
|
||||||
|
if (isFirstSupplier && isLastSupplier) {
|
||||||
|
// 单个农户情况
|
||||||
|
supplier.netWeight = DecimalUtils.add(
|
||||||
|
DecimalUtils.subtract(
|
||||||
|
DecimalUtils.add(weightDiffInJin, weights.remain),
|
||||||
|
weights.extraUsed,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (isLastSupplier) {
|
||||||
|
// 最后一个农户
|
||||||
|
supplier.netWeight = DecimalUtils.add(
|
||||||
|
DecimalUtils.subtract(weightDiffInJin, weights.extraUsed),
|
||||||
|
weights.remain,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 中间农户(包括第一个但不是最后一个)
|
||||||
|
supplier.netWeight = DecimalUtils.subtract(
|
||||||
|
weightDiffInJin,
|
||||||
|
weights.extra,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 毛重 = 净重 + 本次使用纸箱重量
|
||||||
|
supplier.grossWeight = DecimalUtils.add(
|
||||||
|
supplier.netWeight || 0,
|
||||||
|
weights.used,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取报价的重量
|
||||||
|
*/
|
||||||
|
private calculateQuoteWeight(supplier: BusinessAPI.OrderSupplier): number {
|
||||||
|
return supplier.pricingMethod === "BY_GROSS_WEIGHT"
|
||||||
|
? supplier.grossWeight
|
||||||
|
: supplier.netWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算发票金额
|
||||||
|
*/
|
||||||
|
private calculateInvoiceAmount(supplier: BusinessAPI.OrderSupplier): void {
|
||||||
|
supplier.invoiceAmount = DecimalUtils.multiply(
|
||||||
|
this.calculateQuoteWeight(supplier),
|
||||||
|
supplier.purchasePrice || 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据类型计算纸箱总重量(斤)
|
||||||
|
*/
|
||||||
|
private calculateBoxWeightByType(
|
||||||
|
packages: BusinessAPI.OrderPackage[],
|
||||||
|
boxType?: string,
|
||||||
|
): number {
|
||||||
|
const filteredPackages = boxType
|
||||||
|
? packages.filter((pkg) => pkg.boxType === boxType)
|
||||||
|
: packages;
|
||||||
|
|
||||||
|
return filteredPackages.reduce((total, pkg) => {
|
||||||
|
const weight = DecimalUtils.multiply(
|
||||||
|
pkg.boxCount || 0,
|
||||||
|
pkg.boxProductWeight || 0,
|
||||||
|
);
|
||||||
|
return DecimalUtils.add(total, weight);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取计算后的供应商列表
|
||||||
|
*/
|
||||||
|
getSuppliers(): BusinessAPI.OrderSupplier[] {
|
||||||
|
return this.suppliers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定供应商的净重
|
||||||
|
*/
|
||||||
|
getSupplierNetWeight(supplierId: string | number): number {
|
||||||
|
const supplier = this.suppliers.find((s) => s.supplierId === supplierId);
|
||||||
|
return supplier?.netWeight || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定供应商的毛重
|
||||||
|
*/
|
||||||
|
getSupplierGrossWeight(supplierId: string | number): number {
|
||||||
|
const supplier = this.suppliers.find((s) => s.supplierId === supplierId);
|
||||||
|
return supplier?.grossWeight || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取总净重
|
||||||
|
*/
|
||||||
|
getTotalNetWeight(): number {
|
||||||
|
return this.suppliers.reduce((total, supplier) => {
|
||||||
|
return DecimalUtils.add(total, supplier.netWeight || 0);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取总毛重
|
||||||
|
*/
|
||||||
|
getTotalGrossWeight(): number {
|
||||||
|
return this.suppliers.reduce((total, supplier) => {
|
||||||
|
return DecimalUtils.add(total, supplier.grossWeight || 0);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取总发票金额
|
||||||
|
*/
|
||||||
|
getTotalInvoiceAmount(): number {
|
||||||
|
return this.suppliers.reduce((total, supplier) => {
|
||||||
|
return DecimalUtils.add(total, supplier.invoiceAmount || 0);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证计算结果的合理性
|
||||||
|
*/
|
||||||
|
validate(): { isValid: boolean; errors: string[] } {
|
||||||
|
const errors: string[] = [];
|
||||||
|
|
||||||
|
for (const supplier of this.suppliers) {
|
||||||
|
if ((supplier.netWeight || 0) < 0) {
|
||||||
|
errors.push(`供应商 ${supplier.name} 的净重为负数`);
|
||||||
|
}
|
||||||
|
if ((supplier.grossWeight || 0) < 0) {
|
||||||
|
errors.push(`供应商 ${supplier.name} 的毛重为负数`);
|
||||||
|
}
|
||||||
|
if ((supplier.grossWeight || 0) < (supplier.netWeight || 0)) {
|
||||||
|
errors.push(`供应商 ${supplier.name} 的毛重小于净重`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isValid: errors.length === 0,
|
||||||
|
errors,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -35,10 +35,7 @@ export class SupplierWeightCalculator {
|
|||||||
/**
|
/**
|
||||||
* 计算单个供应商的重量
|
* 计算单个供应商的重量
|
||||||
*/
|
*/
|
||||||
private calculateSupplierWeight(
|
private calculateSupplierWeight(supplier: BusinessAPI.OrderSupplier, index: number): void {
|
||||||
supplier: BusinessAPI.OrderSupplier,
|
|
||||||
index: number,
|
|
||||||
): void {
|
|
||||||
const isFirstSupplier = index === 0;
|
const isFirstSupplier = index === 0;
|
||||||
const isLastSupplier = supplier.isLast;
|
const isLastSupplier = supplier.isLast;
|
||||||
|
|
||||||
@ -46,21 +43,14 @@ export class SupplierWeightCalculator {
|
|||||||
this.setEmptyWeight(supplier, index);
|
this.setEmptyWeight(supplier, index);
|
||||||
|
|
||||||
// 计算各类纸箱重量
|
// 计算各类纸箱重量
|
||||||
const weights = this.calculateAllBoxWeights(
|
const weights = this.calculateAllBoxWeights(supplier.orderPackageList || []);
|
||||||
supplier.orderPackageList || [],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!supplier.isPaper) {
|
if (!supplier.isPaper) {
|
||||||
// 不带纸箱包装的简化计算
|
// 不带纸箱包装的简化计算
|
||||||
this.calculateNonPaperSupplier(supplier, weights.used);
|
this.calculateNonPaperSupplier(supplier, weights.used);
|
||||||
} else {
|
} else {
|
||||||
// 纸箱包装的复杂计算
|
// 纸箱包装的复杂计算
|
||||||
this.calculatePaperSupplier(
|
this.calculatePaperSupplier(supplier, weights, isFirstSupplier, isLastSupplier);
|
||||||
supplier,
|
|
||||||
weights,
|
|
||||||
isFirstSupplier,
|
|
||||||
isLastSupplier,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算发票金额
|
// 计算发票金额
|
||||||
@ -73,10 +63,7 @@ export class SupplierWeightCalculator {
|
|||||||
/**
|
/**
|
||||||
* 设置空磅重量
|
* 设置空磅重量
|
||||||
*/
|
*/
|
||||||
private setEmptyWeight(
|
private setEmptyWeight(supplier: BusinessAPI.OrderSupplier, index: number): void {
|
||||||
supplier: BusinessAPI.OrderSupplier,
|
|
||||||
index: number,
|
|
||||||
): void {
|
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
// 第一个农户保持原有空磅重量
|
// 第一个农户保持原有空磅重量
|
||||||
} else {
|
} else {
|
||||||
@ -100,25 +87,19 @@ export class SupplierWeightCalculator {
|
|||||||
/**
|
/**
|
||||||
* 计算非纸箱包装供应商的重量
|
* 计算非纸箱包装供应商的重量
|
||||||
*/
|
*/
|
||||||
private calculateNonPaperSupplier(
|
private calculateNonPaperSupplier(supplier: BusinessAPI.OrderSupplier, usedBoxesWeight: number): void {
|
||||||
supplier: BusinessAPI.OrderSupplier,
|
if (supplier.type === 'FARMER') {
|
||||||
usedBoxesWeight: number,
|
|
||||||
): void {
|
|
||||||
if (supplier.type === "FARMER") {
|
|
||||||
// 毛重 = (总磅 - 空磅) × 2
|
// 毛重 = (总磅 - 空磅) × 2
|
||||||
supplier.grossWeight = DecimalUtils.multiply(
|
supplier.grossWeight = DecimalUtils.multiply(
|
||||||
DecimalUtils.subtract(
|
DecimalUtils.subtract(supplier.totalWeight || 0, supplier.emptyWeight || 0),
|
||||||
supplier.totalWeight || 0,
|
2
|
||||||
supplier.emptyWeight || 0,
|
|
||||||
),
|
|
||||||
2,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 净重 = 毛重 - 使用纸箱重量
|
// 净重 = 毛重 - 使用纸箱重量
|
||||||
supplier.netWeight = DecimalUtils.subtract(
|
supplier.netWeight = DecimalUtils.subtract(
|
||||||
supplier.grossWeight || 0,
|
supplier.grossWeight || 0,
|
||||||
usedBoxesWeight,
|
usedBoxesWeight
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,17 +110,11 @@ export class SupplierWeightCalculator {
|
|||||||
supplier: BusinessAPI.OrderSupplier,
|
supplier: BusinessAPI.OrderSupplier,
|
||||||
weights: { used: number; extra: number; remain: number; extraUsed: number },
|
weights: { used: number; extra: number; remain: number; extraUsed: number },
|
||||||
isFirstSupplier: boolean,
|
isFirstSupplier: boolean,
|
||||||
isLastSupplier: boolean,
|
isLastSupplier: boolean
|
||||||
): void {
|
): void {
|
||||||
const weightDiff = isFirstSupplier
|
const weightDiff = isFirstSupplier
|
||||||
? DecimalUtils.subtract(
|
? DecimalUtils.subtract(supplier.totalWeight || 0, this.initialEmptyWeight)
|
||||||
supplier.totalWeight || 0,
|
: DecimalUtils.subtract(supplier.totalWeight || 0, this.previousTotalWeight);
|
||||||
this.initialEmptyWeight,
|
|
||||||
)
|
|
||||||
: DecimalUtils.subtract(
|
|
||||||
supplier.totalWeight || 0,
|
|
||||||
this.previousTotalWeight,
|
|
||||||
);
|
|
||||||
|
|
||||||
const weightDiffInJin = DecimalUtils.multiply(weightDiff, 2);
|
const weightDiffInJin = DecimalUtils.multiply(weightDiff, 2);
|
||||||
|
|
||||||
@ -148,46 +123,37 @@ export class SupplierWeightCalculator {
|
|||||||
supplier.netWeight = DecimalUtils.add(
|
supplier.netWeight = DecimalUtils.add(
|
||||||
DecimalUtils.subtract(
|
DecimalUtils.subtract(
|
||||||
DecimalUtils.add(weightDiffInJin, weights.remain),
|
DecimalUtils.add(weightDiffInJin, weights.remain),
|
||||||
weights.extraUsed,
|
weights.extraUsed
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
} else if (isLastSupplier) {
|
} else if (isLastSupplier) {
|
||||||
// 最后一个农户
|
// 最后一个农户
|
||||||
supplier.netWeight = DecimalUtils.add(
|
supplier.netWeight = DecimalUtils.add(
|
||||||
DecimalUtils.subtract(weightDiffInJin, weights.extraUsed),
|
DecimalUtils.subtract(
|
||||||
weights.remain,
|
weightDiffInJin,
|
||||||
|
weights.extraUsed
|
||||||
|
),
|
||||||
|
weights.remain
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// 中间农户(包括第一个但不是最后一个)
|
// 中间农户(包括第一个但不是最后一个)
|
||||||
supplier.netWeight = DecimalUtils.subtract(
|
supplier.netWeight = DecimalUtils.subtract(weightDiffInJin, weights.extra);
|
||||||
weightDiffInJin,
|
|
||||||
weights.extra,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 毛重 = 净重 + 本次使用纸箱重量
|
// 毛重 = 净重 + 本次使用纸箱重量
|
||||||
supplier.grossWeight = DecimalUtils.add(
|
supplier.grossWeight = DecimalUtils.add(
|
||||||
supplier.netWeight || 0,
|
supplier.netWeight || 0,
|
||||||
weights.used,
|
weights.used
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* 获取报价的重量
|
|
||||||
*/
|
|
||||||
private calculateQuoteWeight(supplier: BusinessAPI.OrderSupplier): number {
|
|
||||||
console.log("quote weight:", supplier.pricingMethod);
|
|
||||||
return supplier.pricingMethod === "BY_GROSS_WEIGHT"
|
|
||||||
? supplier.grossWeight
|
|
||||||
: supplier.netWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算发票金额
|
* 计算发票金额
|
||||||
*/
|
*/
|
||||||
private calculateInvoiceAmount(supplier: BusinessAPI.OrderSupplier): void {
|
private calculateInvoiceAmount(supplier: BusinessAPI.OrderSupplier): void {
|
||||||
supplier.invoiceAmount = DecimalUtils.multiply(
|
supplier.invoiceAmount = DecimalUtils.multiply(
|
||||||
this.calculateQuoteWeight(supplier),
|
supplier.netWeight || 0,
|
||||||
supplier.purchasePrice || 0,
|
supplier.purchasePrice || 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,16 +162,16 @@ export class SupplierWeightCalculator {
|
|||||||
*/
|
*/
|
||||||
private calculateBoxWeightByType(
|
private calculateBoxWeightByType(
|
||||||
packages: BusinessAPI.OrderPackage[],
|
packages: BusinessAPI.OrderPackage[],
|
||||||
boxType?: string,
|
boxType?: string
|
||||||
): number {
|
): number {
|
||||||
const filteredPackages = boxType
|
const filteredPackages = boxType
|
||||||
? packages.filter((pkg) => pkg.boxType === boxType)
|
? packages.filter(pkg => pkg.boxType === boxType)
|
||||||
: packages;
|
: packages;
|
||||||
|
|
||||||
return filteredPackages.reduce((total, pkg) => {
|
return filteredPackages.reduce((total, pkg) => {
|
||||||
const weight = DecimalUtils.multiply(
|
const weight = DecimalUtils.multiply(
|
||||||
pkg.boxCount || 0,
|
pkg.boxCount || 0,
|
||||||
pkg.boxProductWeight || 0,
|
pkg.boxProductWeight || 0
|
||||||
);
|
);
|
||||||
return DecimalUtils.add(total, weight);
|
return DecimalUtils.add(total, weight);
|
||||||
}, 0);
|
}, 0);
|
||||||
@ -222,7 +188,7 @@ export class SupplierWeightCalculator {
|
|||||||
* 获取指定供应商的净重
|
* 获取指定供应商的净重
|
||||||
*/
|
*/
|
||||||
getSupplierNetWeight(supplierId: string | number): number {
|
getSupplierNetWeight(supplierId: string | number): number {
|
||||||
const supplier = this.suppliers.find((s) => s.supplierId === supplierId);
|
const supplier = this.suppliers.find(s => s.supplierId === supplierId);
|
||||||
return supplier?.netWeight || 0;
|
return supplier?.netWeight || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +196,7 @@ export class SupplierWeightCalculator {
|
|||||||
* 获取指定供应商的毛重
|
* 获取指定供应商的毛重
|
||||||
*/
|
*/
|
||||||
getSupplierGrossWeight(supplierId: string | number): number {
|
getSupplierGrossWeight(supplierId: string | number): number {
|
||||||
const supplier = this.suppliers.find((s) => s.supplierId === supplierId);
|
const supplier = this.suppliers.find(s => s.supplierId === supplierId);
|
||||||
return supplier?.grossWeight || 0;
|
return supplier?.grossWeight || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +247,7 @@ export class SupplierWeightCalculator {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
isValid: errors.length === 0,
|
isValid: errors.length === 0,
|
||||||
errors,
|
errors
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,4 +9,4 @@
|
|||||||
export { OrderCalculator, WeightCalculationService } from "./calculators";
|
export { OrderCalculator, WeightCalculationService } from "./calculators";
|
||||||
|
|
||||||
// 模板类
|
// 模板类
|
||||||
export { PdfTemplate, ProfitTableTemplate } from "./templates";
|
export { PdfTemplate } from "./templates";
|
||||||
|
|||||||
@ -8,48 +8,7 @@ export class PdfTemplate {
|
|||||||
// 将预览内容转换为HTML字符串的函数
|
// 将预览内容转换为HTML字符串的函数
|
||||||
generateHtmlString = () => {
|
generateHtmlString = () => {
|
||||||
let htmlString = `
|
let htmlString = `
|
||||||
<style>
|
<style> @page {size: 210mm 297mm;margin: 0;padding: 0;}* {outline: none;box-sizing: border-box;margin: 0;padding: 0;border: 0 solid;}body {background-color: #fff;color: #4d4d4d;font-size: 14px;font-style: normal;box-sizing: border-box;}.page-wrap {width: 210mm;min-height: 297mm;margin: 0 auto;}.page-content {position: relative;box-sizing: border-box;width: 100%;height: 100%;padding: 20mm 10mm 0;display: flex;flex-direction: column;gap: 2mm;}@media print {.print-controls {display: none !important;}body {padding: 0;margin: 0;}}.print-module {margin-bottom: 15px;text-align: center;}.print-controls {position: fixed;top: 10px;right: 10px;z-index: 9999;}.print-button,.close-button {padding: 8px 16px;margin-left: 10px;cursor: pointer;border: 1px solid #d9d9d9;border-radius: 4px;}.print-button {background-color: #1890ff;color: white;}.close-button {background-color: #fff;color: #000;}.preview {width: 19cm;div {height: 0.7cm;}}.table-border {border: 2px solid #000;}.table-border>div {border-bottom: 1px solid #000;}.table-border>div>div {border-right: 1px solid #000;}.table-border>div>div:last-child {border-right: none;}.table-border>div:last-child {border-bottom: none;}.col-span-1 {grid-column: span 1 / span 1;}.col-span-2 {grid-column: span 2 / span 2;}.col-span-3 {grid-column: span 3 / span 3;}.col-span-6 {grid-column: span 6 / span 6;}.col-span-8 {grid-column: span 8 / span 8;}.flex {display: flex;}.items-center {align-items: center;}.grid {display: grid;}.w-full {width: 100%;}.grid-cols-1 {grid-template-columns: repeat(1, minmax(0, 1fr));}.grid-cols-2 {grid-template-columns: repeat(2, minmax(0, 1fr));}.grid-cols-3 {grid-template-columns: repeat(3, minmax(0, 1fr));}.grid-cols-4 {grid-template-columns: repeat(4, minmax(0, 1fr));}.grid-cols-5 {grid-template-columns: repeat(5, minmax(0, 1fr));}.grid-cols-6 {grid-template-columns: repeat(6, minmax(0, 1fr));}.grid-cols-7 {grid-template-columns: repeat(7, minmax(0, 1fr));}.grid-cols-8 {grid-template-columns: repeat(8, minmax(0, 1fr));}.items-end {align-items: flex-end;}.justify-center {justify-content: center;}.border-t-0 {border-top-width: 0px;}.border-b {border-bottom-width: 1px;}.border-black {border-color: #000000;}.bg-white {background-color: #ffffff;}.text-2xl {font-size: 24px;line-height: 1;}.text-base {font-size: 16px;line-height: 1;}.text-lg {font-size: 18px;line-height: 1;}.font-bold {font-weight: bold;}.preview {width: 19cm;div {height: 0.69cm;}}.table-border {border: 2px solid #000;}.table-border>div {border-bottom: 1px solid #000;}.table-border>div>div {border-right: 1px solid #000;}.table-border>div>div:last-child {border-right: none;}.table-border>div:last-child {border-bottom: none;}.p-2 {padding:8px}</style>
|
||||||
@page {size: 210mm 297mm;margin: 0;padding: 0;}
|
|
||||||
* {outline: none;box-sizing: border-box;margin: 0;padding: 0;border: 0 solid;}
|
|
||||||
body {background-color: #fff;color: #4d4d4d;font-size: 14px;font-style: normal;box-sizing: border-box;}
|
|
||||||
.page-wrap {width: 210mm;min-height: 297mm;margin: 0 auto;}
|
|
||||||
.page-content {position: relative;box-sizing: border-box;width: 100%;height: 100%;padding: 20mm 10mm 0;display: flex;flex-direction: column;gap: 2mm;}
|
|
||||||
@media print {.print-controls {display: none !important;}body {padding: 0;margin: 0;}}
|
|
||||||
.col-span-1 {grid-column: span 1 / span 1;}
|
|
||||||
.col-span-2 {grid-column: span 2 / span 2;}
|
|
||||||
.col-span-3 {grid-column: span 3 / span 3;}
|
|
||||||
.col-span-6 {grid-column: span 6 / span 6;}
|
|
||||||
.col-span-8 {grid-column: span 8 / span 8;}
|
|
||||||
.flex {display: flex;}
|
|
||||||
.items-center {align-items: center;}
|
|
||||||
.grid {display: grid;}
|
|
||||||
.w-full {width: 100%;}
|
|
||||||
.grid-cols-1 {grid-template-columns: repeat(1, minmax(0, 1fr));}
|
|
||||||
.grid-cols-2 {grid-template-columns: repeat(2, minmax(0, 1fr));}
|
|
||||||
.grid-cols-3 {grid-template-columns: repeat(3, minmax(0, 1fr));}
|
|
||||||
.grid-cols-4 {grid-template-columns: repeat(4, minmax(0, 1fr));}
|
|
||||||
.grid-cols-5 {grid-template-columns: repeat(5, minmax(0, 1fr));}
|
|
||||||
.grid-cols-6 {grid-template-columns: repeat(6, minmax(0, 1fr));}
|
|
||||||
.grid-cols-7 {grid-template-columns: repeat(7, minmax(0, 1fr));}
|
|
||||||
.grid-cols-8 {grid-template-columns: repeat(8, minmax(0, 1fr));}
|
|
||||||
.items-end {align-items: flex-end;}
|
|
||||||
.justify-center {justify-content: center;}
|
|
||||||
.border-t-0 {border-top-width: 0px;}
|
|
||||||
.border-b {border-bottom-width: 1px;}
|
|
||||||
.border-black {border-color: #000000;}
|
|
||||||
.bg-white {background-color: #ffffff;}
|
|
||||||
.text-2xl {font-size: 24px;line-height: 1;}
|
|
||||||
.text-base {font-size: 16px;line-height: 1;}
|
|
||||||
.text-lg {font-size: 18px;line-height: 1;}
|
|
||||||
.font-bold {font-weight: bold;}
|
|
||||||
.preview {width: 19cm;div {height: 0.69cm;}}
|
|
||||||
.table-border {border: 2px solid #000;}
|
|
||||||
.table-border>div {border-bottom: 1px solid #000;}
|
|
||||||
.table-border>div>div {border-right: 1px solid #000;}
|
|
||||||
.table-border>div>div:last-child {border-right: none;}
|
|
||||||
.table-border>div:last-child {border-bottom: none;}
|
|
||||||
.p-2 {padding:8px}
|
|
||||||
</style>
|
|
||||||
<div class="page-wrap">
|
<div class="page-wrap">
|
||||||
<div class="page-content">
|
<div class="page-content">
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -1,107 +0,0 @@
|
|||||||
// 利润表数据接口
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import "dayjs/locale/zh-cn";
|
|
||||||
|
|
||||||
dayjs.locale("zh-cn");
|
|
||||||
|
|
||||||
export interface ProfitTableRow {
|
|
||||||
vehicleNo: string; // 车次
|
|
||||||
shippingDate: string; // 发货日期
|
|
||||||
originCost: number; // 产地成本
|
|
||||||
quoteAmount: number; // 报价金额
|
|
||||||
profit: number; // 利润
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ProfitTableTemplate {
|
|
||||||
private data: ProfitTableRow[];
|
|
||||||
private month: string;
|
|
||||||
|
|
||||||
constructor(data: ProfitTableRow[], month: string) {
|
|
||||||
this.data = data;
|
|
||||||
this.month = month;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将利润表内容转换为HTML字符串的函数
|
|
||||||
generateHtmlString = () => {
|
|
||||||
// 计算合计
|
|
||||||
const totalOriginCost = this.data.reduce(
|
|
||||||
(sum, row) => sum + row.originCost,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
const totalQuoteAmount = this.data.reduce(
|
|
||||||
(sum, row) => sum + row.quoteAmount,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
const totalProfit = this.data.reduce((sum, row) => sum + row.profit, 0);
|
|
||||||
|
|
||||||
return `
|
|
||||||
<style>
|
|
||||||
@page {size: 210mm 297mm;margin: 0;padding: 0;}
|
|
||||||
* {outline: none;box-sizing: border-box;margin: 0;padding: 0;border: 0 solid;}
|
|
||||||
body {background-color: #fff;color: #4d4d4d;font-size: 14px;font-style: normal;box-sizing: border-box;}
|
|
||||||
.page-wrap {width: 210mm;min-height: 297mm;margin: 0 auto;}
|
|
||||||
.page-content {position: relative;box-sizing: border-box;width: 100%;height: 100%;padding: 20mm 10mm 0;display: flex;flex-direction: column;gap: 2mm;}
|
|
||||||
@media print {.print-controls {display: none !important;}body {padding: 0;margin: 0;}}
|
|
||||||
.preview {width: 19cm;}
|
|
||||||
.table-border {border: 2px solid #000;border-collapse: collapse;width: 100%;}
|
|
||||||
.table-border th,
|
|
||||||
.table-border td {border: 1px solid #000;padding: 8px;text-align: center;}
|
|
||||||
.table-border th {font-weight: bold;background-color: #f5f5f5;}
|
|
||||||
.table-title {font-size: 20px;font-weight: bold;text-align: center;padding: 16px;border: 2px solid #000;border-bottom: none;}
|
|
||||||
.text-center {text-align: center;}
|
|
||||||
.text-right {text-align: right;}
|
|
||||||
.font-bold {font-weight: bold;}
|
|
||||||
.text-xl {font-size: 20px;}
|
|
||||||
.text-lg {font-size: 18px;}
|
|
||||||
.text-2xl {font-size: 24px;}
|
|
||||||
.mb-4 {margin-bottom: 16px;}
|
|
||||||
.p-4 {padding: 16px;}
|
|
||||||
.gap-4 {gap: 16px;}
|
|
||||||
.negative {color: #ff0000;}
|
|
||||||
.positive {color: #00ff00;}
|
|
||||||
.footer {background-color: yellow}
|
|
||||||
</style>
|
|
||||||
<div class="page-wrap">
|
|
||||||
<div class="page-content">
|
|
||||||
<div class="preview">
|
|
||||||
<div class="table-title">诚信志远利润明细</div>
|
|
||||||
<table class="table-border">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th style="width: 20%;">车次</th>
|
|
||||||
<th style="width: 20%;">发货日期</th>
|
|
||||||
<th style="width: 20%;">产地成本</th>
|
|
||||||
<th style="width: 20%;">报价金额</th>
|
|
||||||
<th style="width: 20%;">利润</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
${this.data
|
|
||||||
.map(
|
|
||||||
(row) => `
|
|
||||||
<tr>
|
|
||||||
<td>${row.vehicleNo}</td>
|
|
||||||
<td>${row.shippingDate}</td>
|
|
||||||
<td>${row.originCost}</td>
|
|
||||||
<td>${row.quoteAmount}</td>
|
|
||||||
<td>${row.profit.toFixed(2)}</td>
|
|
||||||
</tr>
|
|
||||||
`,
|
|
||||||
)
|
|
||||||
.join("")}
|
|
||||||
</tbody>
|
|
||||||
<tfoot class="footer">
|
|
||||||
<tr class="font-bold">
|
|
||||||
<td colspan="2">${dayjs(this.month).format("MMMM")}合计</td>
|
|
||||||
<td>${totalOriginCost.toFixed(2)}</td>
|
|
||||||
<td>${totalQuoteAmount.toFixed(2)}</td>
|
|
||||||
<td>${totalProfit.toFixed(2)}</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -5,5 +5,4 @@
|
|||||||
* import { PdfTemplate } from '@/utils/classes/templates'
|
* import { PdfTemplate } from '@/utils/classes/templates'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { PdfTemplate } from "./PdfTemplate";
|
export { PdfTemplate } from './PdfTemplate'
|
||||||
export { ProfitTableTemplate } from "./ProfitTableTemplate";
|
|
||||||
|
|||||||
@ -2,15 +2,6 @@ import Taro from "@tarojs/taro";
|
|||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { utils, write } from "xlsx";
|
import { utils, write } from "xlsx";
|
||||||
|
|
||||||
// 利润表行数据接口
|
|
||||||
export interface ProfitTableRow {
|
|
||||||
vehicleNo: string; // 车次
|
|
||||||
shippingDate: string; // 发货日期
|
|
||||||
originCost: number; // 产地成本
|
|
||||||
quoteAmount: number; // 报价金额
|
|
||||||
profit: number; // 利润
|
|
||||||
}
|
|
||||||
|
|
||||||
// 费用统计数据接口
|
// 费用统计数据接口
|
||||||
interface ExpenseStatistics {
|
interface ExpenseStatistics {
|
||||||
totalVehicles: number;
|
totalVehicles: number;
|
||||||
@ -345,99 +336,3 @@ export const exportExcel = async (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出利润表Excel文件
|
|
||||||
* @param data 利润表数据
|
|
||||||
* @param month 月份(格式:YYYY-MM)
|
|
||||||
* @returns Promise<string>
|
|
||||||
*/
|
|
||||||
export const exportProfitTableExcel = async (
|
|
||||||
data: ProfitTableRow[],
|
|
||||||
month: string,
|
|
||||||
): Promise<string> => {
|
|
||||||
// 创建工作簿
|
|
||||||
const wb = utils.book_new();
|
|
||||||
|
|
||||||
// 创建工作表数据
|
|
||||||
const wsData: (string | number)[][] = [];
|
|
||||||
|
|
||||||
// 添加标题
|
|
||||||
wsData.push([`诚信志远利润明细`]);
|
|
||||||
wsData.push([]); // 空行
|
|
||||||
|
|
||||||
// 添加表头
|
|
||||||
wsData.push(["车次", "发货日期", "产地成本", "报价金额", "利润"]);
|
|
||||||
|
|
||||||
// 添加数据行
|
|
||||||
data.forEach((row) => {
|
|
||||||
wsData.push([
|
|
||||||
row.vehicleNo,
|
|
||||||
row.shippingDate,
|
|
||||||
row.originCost,
|
|
||||||
row.quoteAmount,
|
|
||||||
row.profit,
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 添加合计行
|
|
||||||
const totalOriginCost = data.reduce((sum, row) => sum + row.originCost, 0);
|
|
||||||
const totalQuoteAmount = data.reduce((sum, row) => sum + row.quoteAmount, 0);
|
|
||||||
const totalProfit = data.reduce((sum, row) => sum + row.profit, 0);
|
|
||||||
|
|
||||||
wsData.push([]);
|
|
||||||
wsData.push([
|
|
||||||
dayjs(month).format("MMMM") + "合计",
|
|
||||||
"-",
|
|
||||||
totalOriginCost.toFixed(2),
|
|
||||||
totalQuoteAmount.toFixed(2),
|
|
||||||
totalProfit.toFixed(2),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 创建工作表
|
|
||||||
const ws = utils.aoa_to_sheet(wsData);
|
|
||||||
|
|
||||||
// 设置列宽
|
|
||||||
const wscols = [
|
|
||||||
{ wch: 15 }, // 车次
|
|
||||||
{ wch: 15 }, // 发货日期
|
|
||||||
{ wch: 15 }, // 产地成本
|
|
||||||
{ wch: 15 }, // 报价金额
|
|
||||||
{ wch: 15 }, // 利润
|
|
||||||
];
|
|
||||||
ws["!cols"] = wscols;
|
|
||||||
|
|
||||||
// 将工作表添加到工作簿
|
|
||||||
utils.book_append_sheet(wb, ws, "诚信志远利润明细");
|
|
||||||
|
|
||||||
// 生成文件名
|
|
||||||
const fileName = `诚信志远利润明细_${month}_${dayjs().format("YYYYMMDDHHmmss")}.xlsx`;
|
|
||||||
|
|
||||||
// 根据环境选择不同的导出方式
|
|
||||||
const processEnv = process.env.TARO_ENV;
|
|
||||||
|
|
||||||
if (processEnv === "h5") {
|
|
||||||
// H5环境:创建下载链接
|
|
||||||
const excelBuffer = write(wb, { type: "array", bookType: "xlsx" });
|
|
||||||
const blob = new Blob([excelBuffer], {
|
|
||||||
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
||||||
});
|
|
||||||
|
|
||||||
// 创建下载链接
|
|
||||||
return window.URL.createObjectURL(blob);
|
|
||||||
} else {
|
|
||||||
// 小程序环境:使用文件系统API
|
|
||||||
const excelBuffer = write(wb, { type: "array", bookType: "xlsx" });
|
|
||||||
|
|
||||||
// 将文件保存到本地
|
|
||||||
const filePath = `${Taro.env.USER_DATA_PATH}/${fileName}`;
|
|
||||||
console.log("filePath", filePath);
|
|
||||||
Taro.getFileSystemManager().writeFile({
|
|
||||||
filePath,
|
|
||||||
data: excelBuffer,
|
|
||||||
encoding: "binary",
|
|
||||||
});
|
|
||||||
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user