refactor(delivery): 重构发货单相关功能实现

- 优化 State 组件渲染逻辑,增加状态判断避免无效渲染
- 在 Step1Form 组件中添加调试日志便于排查问题
- 调整 DeliveryFormSection 中 convertShipOrderVOToExamplesFormat 方法参数
- 重命名常量文件 shipOrder.ts 为 orderShip.ts 并扩展状态枚举值
- 新增草稿(DRAFT)和待发货(WAIT_SHIPMENT)两种订单状态配置
- 更新发货单页面导入模块路径并调整数据处理逻辑
- 修改发货单文档页面初始化方法参数并增强类型安全
- 重构发货单列表页删除冗余弹窗及生成单据逻辑
- 调整发票上传页面筛选条件限制仅允许特定状态下操作
- 优化审批结果页面发货单据下载流程简化交互步骤
- 补充业务接口定义完善 OrderShip 和 OrderSupplier 类型声明
- 更新工具函数中 purchaseOrderConverter 和 shipOrderConverter 实现细节
- 调整应用路由配置同步页面文件名变更影响范围
This commit is contained in:
shenyifei 2025-12-16 14:48:21 +08:00
parent 8bca8c2476
commit 72a0e06da6
18 changed files with 390 additions and 549 deletions

View File

@ -35,7 +35,7 @@
#### 命名规范
- **组件**: PascalCase (如: CustomTabBar, PurchaseSection)
- **文件**: kebab-case (如: purchase-order-list.tsx)
- **文件**: kebab-case (如: purchase-order-all.tsx)
- **变量/函数**: camelCase (如: getUserInfo, handleSubmit)
- **常量**: SCREAMING_SNAKE_CASE (如: API_BASE_URL)
- **CSS类**: TailwindCSS原子类 + 自定义kebab-case类

View File

@ -57,7 +57,7 @@ config = {
// 发货单
{
root: "pages/delivery",
pages: ["list", "document/delivery", "document/purchase"],
pages: ["all", "document/delivery", "document/purchase"],
},
// 瓜农
{

View File

@ -14,6 +14,7 @@ export default function State({
const statusInfo = stateMap[state];
return (
statusInfo && (
<View
className={classNames(
"flex items-center justify-center rounded-full px-3 py-1 shadow-sm",
@ -27,9 +28,13 @@ export default function State({
boxShadow: `0 0 0 1px ${statusInfo.color}20, 0 1px 3px 0 ${statusInfo.color}30`,
}}
>
<Text className="text-xs font-medium" style={{ color: statusInfo.color }}>
<Text
className="text-xs font-medium"
style={{ color: statusInfo.color }}
>
{statusInfo.label}
</Text>
</View>
)
);
}

View File

@ -22,6 +22,7 @@ export interface Step1FormRef {
const Step1Form = forwardRef<Step1FormRef, Step1FormProps>((props, ref) => {
const { moduleList, orderShip, setOrderShip, readOnly = false } = props;
console.log("moduleList", moduleList, orderShip);
// 当天和未来10天
const startDate = new Date();

View File

@ -34,10 +34,7 @@ export default forwardRef<
if (data.data?.deliveryTemplate!) {
const template = JSON.parse(data.data?.deliveryTemplate!);
// 将 shipOrderVO 转换为 examples 的数据格式,然后再替换 moduleList 里面的 config 数据
const convertedData = convertShipOrderVOToExamplesFormat(
purchaseOrderVO,
orderShip!,
);
const convertedData = convertShipOrderVOToExamplesFormat(purchaseOrderVO);
const updatedTemplate = await updateTemplateConfig(
template,
convertedData,

View File

@ -3,6 +3,14 @@ const stateList = [
title: "全部",
value: "ALL",
},
{
title: "草稿",
value: "DRAFT",
},
{
title: "待发货",
value: "WAIT_SHIPMENT",
},
{
title: "待回款",
value: "WAIT_PAYMENT",
@ -27,6 +35,18 @@ const stateList = [
// 定义需求状态映射 - 优化颜色方案
const stateMap = {
DRAFT: {
label: "草稿",
color: "#6B7280",
bgColor: "#F3F4F6",
borderColor: "#D1D5DB",
},
WAIT_SHIPMENT: {
label: "待发货",
color: "#EA580C",
bgColor: "#FEF3C7",
borderColor: "#D97706",
},
WAIT_PAYMENT: {
label: "待回款",
color: "#1E40AF",

View File

@ -0,0 +1,228 @@
import {
ActionType,
DealerPicker,
Icon,
PageList,
State,
ToolBar,
} from "@/components";
import Taro, { useShareAppMessage } from "@tarojs/taro";
import { useRef, useState } from "react";
import { business } from "@/services";
import hocAuth from "@/hocs/auth";
import { CommonComponent } from "@/types/typings";
import { Label, Text, View } from "@tarojs/components";
import { buildUrl } from "@/utils";
import dayjs from "dayjs";
import shipOrder from "@/constant/orderShip";
import { Button } from "@nutui/nutui-react-taro";
export default hocAuth(function Page(props: CommonComponent) {
const { shareOptions } = props;
const [state, setState] = useState<BusinessAPI.OrderShipPageQry["state"]>();
const [dealerVO, setDealerVO] = useState<BusinessAPI.DealerVO>();
const actionRef = useRef<ActionType>();
const toolbar: ToolBar = {
search: {
activeKey: "vehicleNo",
defaultActiveKey: "vehicleNo",
items: [
{
key: "vehicleNo",
name: "车次号",
placeholder: "请输入车次号",
},
{
key: "plate",
name: "车牌号",
placeholder: "请输入车牌号",
},
],
},
tabs: {
activeKey: "state",
defaultActiveKey: state || "ALL",
items: shipOrder.stateList,
onChange: (item) => {
setState(item as BusinessAPI.OrderShipPageQry["state"]);
actionRef.current?.reload();
},
},
render: () => (
<>
<View className={"flex flex-row gap-2.5"}>
<DealerPicker
onFinish={(dealerVO) => {
setDealerVO(dealerVO);
actionRef.current?.reload();
}}
trigger={
<View
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
>
<View className={"text-primary text-xs"}>
{dealerVO?.shortName || "经销商"}
</View>
{dealerVO?.shortName ? (
<Icon
name={"circle-xmark"}
size={16}
onClick={(event) => {
setDealerVO(undefined);
actionRef.current?.reload();
event.stopPropagation();
}}
/>
) : (
<Icon name={"chevron-down"} size={16} />
)}
</View>
}
/>
</View>
</>
),
};
useShareAppMessage((res) => {
console.log("useShareAppMessage1", res, shareOptions);
// 如果是按钮触发的转发,使用默认配置
if (res.from === "button") {
return shareOptions;
}
// 页面转发使用设置的配置
return {};
});
return (
<PageList<BusinessAPI.OrderShipVO, BusinessAPI.OrderShipPageQry>
rowId={"shipOrderId"}
itemHeight={182}
type={"infinite"}
actionRef={actionRef}
render={(shipOrderVO: BusinessAPI.OrderShipVO, index) => (
<View className={"mb-2.5"} key={index}>
<View
className={
"relative flex flex-col divide-y-2 divide-neutral-100 rounded-lg bg-white px-2.5"
}
>
<View className={"flex flex-col divide-y-2 divide-neutral-100"}>
<View className={"py-2.5"}>
<View className={"flex flex-row items-center"}>
<View className={"flex flex-1 flex-col gap-2"}>
<View className={"flex flex-row gap-1"}>
{/* 复制 */}
<Text
className={"text-neutral-darkest text-xl font-bold"}
>
{shipOrderVO?.orderVehicle?.vehicleNo
? "第" + shipOrderVO.orderVehicle.vehicleNo + "车"
: "暂未生成车次"}
</Text>
</View>
<Text className={"text-neutral-dark text-sm"}>
{shipOrderVO.orderSn}
</Text>
</View>
<State
state={shipOrderVO.state}
stateMap={shipOrder.stateMap}
/>
</View>
</View>
<View className={"py-2.5"}>
<View className={"flex flex-col gap-2"}>
<View
className={
"flex flex-row items-center justify-between gap-2.5"
}
>
<Label className={"text-neutral-dark text-sm"}>
</Label>
<Text className={"text-neutral-darkest text-sm"}>
{shipOrderVO.createdByName}
</Text>
</View>
<View
className={
"flex flex-row items-center justify-between gap-2.5"
}
>
<Label className={"text-neutral-dark text-sm"}>
</Label>
<Text className={"text-neutral-darkest text-sm"}>
{dayjs(shipOrderVO.createdAt).format("MM-DD HH:mm")}
</Text>
</View>
<View
className={
"flex flex-row items-center justify-between gap-2.5"
}
>
<Label className={"text-neutral-dark text-sm"}>
</Label>
<Text className={"text-neutral-darkest text-sm"}>
{shipOrderVO.dealerName}
</Text>
</View>
</View>
</View>
</View>
<View className={"py-2.5"}>
<View className={"flex flex-row justify-end gap-2"}>
<Button
type={"primary"}
size={"small"}
onClick={async (e) => {
// 跳转到发货单据生成页面
await Taro.navigateTo({
url: buildUrl("/pages/delivery/document/delivery", {
orderShipId: shipOrderVO.orderShipId,
orderId: shipOrderVO.orderId,
}),
});
e.stopPropagation();
}}
>
</Button>
</View>
</View>
</View>
</View>
)}
toolbar={toolbar}
request={async (params) => {
const {
data: { data, success, notEmpty },
} = await business.orderShip.pageOrderShip({
orderShipPageQry: {
...params,
//@ts-ignore
state: state !== "ALL" ? state : undefined,
...(dealerVO
? {
dealerId: dealerVO.dealerId,
}
: {}),
},
});
return {
data,
success,
hasMore: notEmpty,
};
}}
pagination={{
pageSize: 10,
}}
/>
);
});

View File

@ -3,7 +3,7 @@ import { CommonComponent } from "@/types/typings";
import { useEffect, useRef, useState } from "react";
import { View } from "@tarojs/components";
import { Button, Dialog, SafeArea, Step, Steps } from "@nutui/nutui-react-taro";
import shipOrder from "@/constant/shipOrder";
import orderShip from "@/constant/orderShip";
import Taro from "@tarojs/taro";
import classNames from "classnames";
import { business, poster } from "@/services";
@ -22,7 +22,7 @@ import {
// 特殊处理:其他费用要实时获取费用项目
const updateOtherFeesModule = async (
module: any,
orderShipVO: BusinessAPI.OrderShipVO,
purchaseOrderVO: BusinessAPI.PurchaseOrderVO,
) => {
const {
data: { data },
@ -40,7 +40,7 @@ const updateOtherFeesModule = async (
...module,
config: {
...module.config,
feeItems: orderShipVO.orderCostList?.filter(
feeItems: purchaseOrderVO.orderCostList?.filter(
(item) => item.type !== "ARTIFICIAL_TYPE",
),
feeLabels: costItems.reduce((acc: any, item: any) => {
@ -70,28 +70,38 @@ const updateOtherFeesModule = async (
export default hocAuth(function Page(props: CommonComponent) {
const { router, setLoading } = props;
const shipOrderId = router.params
.shipOrderId as BusinessAPI.OrderShipVO["orderShipId"];
const orderShipId = router.params
.orderShipId as BusinessAPI.OrderShipVO["orderShipId"];
const orderId = router.params.orderId as BusinessAPI.OrderShipVO["orderId"];
const [step, setStep] = useState(1);
const [moduleList, setModuleList] = useState<any[]>([]);
const [height, setHeight] = useState<number>();
const [shipOrderVO, setShipOrderVO] = useState<BusinessAPI.OrderShipVO>();
const [purchaseOrderVO, setPurchaseOrderVO] =
useState<BusinessAPI.PurchaseOrderVO>();
const [orderShipVO, setOrderShipVO] = useState<BusinessAPI.OrderShip>();
const [deliveryTemplate, setDeliveryTemplate] = useState<string>();
const [document, setDocument] = useState<string>();
const step1FormRef = useRef<DeliveryStep1FormRef>(null);
const init = async (orderShipId: BusinessAPI.OrderShipVO["orderShipId"]) => {
const init = async (
orderId: BusinessAPI.OrderShipVO["orderId"],
orderShipId: BusinessAPI.OrderShipVO["orderShipId"],
) => {
setLoading(true);
const { data } = await business.orderShip.showOrderShip({
orderShipShowQry: {
const { data } = await business.purchaseOrder.showPurchaseOrder({
purchaseOrderShowQry: {
orderId,
orderShipId,
},
});
const shipOrderVO = data.data;
if (shipOrderVO) {
setShipOrderVO(shipOrderVO);
const purchaseOrderVO = data.data;
if (purchaseOrderVO) {
setPurchaseOrderVO(purchaseOrderVO);
const shipOrderVO = purchaseOrderVO.orderShipList[0];
setOrderShipVO(shipOrderVO);
if (shipOrderVO.document) {
setStep(3);
setDocument(shipOrderVO.document);
@ -99,7 +109,7 @@ export default hocAuth(function Page(props: CommonComponent) {
const { data } = await business.dealer.showDealer({
dealerShowQry: {
dealerId: shipOrderVO.dealerId,
dealerId: shipOrderVO?.dealerId,
},
});
@ -110,38 +120,39 @@ export default hocAuth(function Page(props: CommonComponent) {
};
useEffect(() => {
if (shipOrderId) {
init(shipOrderId).then();
if (orderId && orderShipId) {
init(orderId, orderShipId).then();
}
}, [shipOrderId]);
}, [orderId, orderShipId]);
const refresh = async (
deliveryTemplate: string,
shipOrderVO: BusinessAPI.OrderShipVO,
purchaseOrderVO: BusinessAPI.PurchaseOrderVO,
) => {
const template = JSON.parse(deliveryTemplate);
// 将 shipOrderVO 转换为 examples 的数据格式,然后再替换 moduleList 里面的 config 数据
const convertedData = convertShipOrderVOToExamplesFormat(shipOrderVO);
const convertedData = convertShipOrderVOToExamplesFormat(purchaseOrderVO);
console.log("convertedData", convertedData);
const updatedTemplate = await updateTemplateConfig(
template,
convertedData,
shipOrderVO,
purchaseOrderVO,
);
console.log("updatedTemplate", updatedTemplate);
setModuleList(updatedTemplate);
};
useEffect(() => {
if (deliveryTemplate && shipOrderVO) {
refresh(deliveryTemplate, shipOrderVO).then();
if (deliveryTemplate && purchaseOrderVO) {
refresh(deliveryTemplate, purchaseOrderVO).then();
}
}, [shipOrderVO, deliveryTemplate]);
}, [purchaseOrderVO, deliveryTemplate]);
// 更新模板配置
const updateTemplateConfig = async (
template: any[],
data: any,
shipOrderVO: BusinessAPI.OrderShipVO,
purchaseOrderVO: BusinessAPI.PurchaseOrderVO,
) => {
let templateList: any[] = [];
template.map(async (module: any) => {
@ -151,7 +162,7 @@ export default hocAuth(function Page(props: CommonComponent) {
}
// 特殊处理: otherFees 要更新为最新的数据
if (module.type === "otherFees") {
newModule = await updateOtherFeesModule(module, shipOrderVO);
newModule = await updateOtherFeesModule(module, purchaseOrderVO);
}
templateList.push(newModule);
});
@ -224,10 +235,11 @@ export default hocAuth(function Page(props: CommonComponent) {
html: template.generateHtmlString(),
});
const orderShip = purchaseOrderVO?.orderShipList[0];
// 存储 至 shipOrder previewUrl
if (shipOrderVO) {
if (orderShip) {
let formData: BusinessAPI.OrderShipGenerateDocumentCmd = {
orderShipId: shipOrderVO?.orderShipId,
orderShipId: orderShip?.orderShipId,
document: data?.data?.path,
};
// 检查各模块中的必填字段是否已填写
@ -247,23 +259,23 @@ export default hocAuth(function Page(props: CommonComponent) {
for (const column of contentSchema.columns) {
// 检查西瓜品级字段是否开启且已填写
if (column.dataIndex === "requiredWatermelonGrade") {
formData.watermelonGrade = shipOrderVO?.watermelonGrade;
formData.watermelonGrade = orderShip?.watermelonGrade;
}
// 检查发货地字段是否开启且已填写
else if (column.dataIndex === "requiredShippingFrom") {
formData.shippingAddress = shipOrderVO?.shippingAddress;
formData.shippingAddress = orderShip?.shippingAddress;
}
// 检查预计到仓时间字段是否开启且已填写
else if (column.dataIndex === "requiredEstimatedArrivalTime") {
formData.estimatedArrivalDate = shipOrderVO?.estimatedArrivalDate;
formData.estimatedArrivalDate = orderShip?.estimatedArrivalDate;
}
// 检查备注字段是否开启且已填写
else if (column.dataIndex === "requiredRemarks") {
formData.remark = shipOrderVO?.remark;
formData.remark = orderShip?.remark;
}
// 检查品级字段是否开启且已填写
else if (column.dataIndex === "requiredGrade") {
formData.orderShipItemList = shipOrderVO?.orderShipItemList;
formData.orderShipItemList = orderShip?.orderShipItemList;
}
}
}
@ -286,8 +298,8 @@ export default hocAuth(function Page(props: CommonComponent) {
const resetForm = () => {
setStep(1);
// 重新加载初始数据
if (shipOrderId) {
init(shipOrderId).then();
if (orderId && orderShipId) {
init(orderId, orderShipId).then();
}
};
@ -340,7 +352,7 @@ export default hocAuth(function Page(props: CommonComponent) {
<View className={"p-2.5"}>
<View className={"rounded-lg bg-white p-4 shadow-md"}>
<Steps value={step} status="dynamic" layout="single">
{shipOrder.steps.map((item, index) => (
{orderShip.steps.map((item, index) => (
<Step key={index} {...item} />
))}
</Steps>
@ -361,8 +373,8 @@ export default hocAuth(function Page(props: CommonComponent) {
<DeliveryStep1Form
ref={step1FormRef}
moduleList={moduleList}
orderShip={shipOrderVO}
setOrderShip={setShipOrderVO}
orderShip={orderShipVO}
setOrderShip={setOrderShipVO}
/>
</View>
)}

View File

@ -3,11 +3,11 @@ import { CommonComponent } from "@/types/typings";
import { useEffect, useRef, useState } from "react";
import { View } from "@tarojs/components";
import { Button, Dialog, SafeArea, Step, Steps } from "@nutui/nutui-react-taro";
import shipOrder from "@/constant/shipOrder";
import shipOrder from "@/constant/orderShip";
import Taro from "@tarojs/taro";
import classNames from "classnames";
import { business, poster } from "@/services";
import { buildUrl, PdfTemplate, PurchaseOrderCalculator } from "@/utils";
import { buildUrl, PdfTemplate } from "@/utils";
import {
Icon,
PurchaseStep1Form,
@ -226,8 +226,6 @@ export default hocAuth(function Page(props: CommonComponent) {
return;
}
const calculator = new PurchaseOrderCalculator(purchaseOrderVO);
return (
<View
className={

View File

@ -1,392 +0,0 @@
import {
ActionType,
DealerPicker,
Icon,
PageList,
State,
ToolBar,
} from "@/components";
import Taro, { useShareAppMessage } from "@tarojs/taro";
import { useRef, useState } from "react";
import { business } from "@/services";
import hocAuth from "@/hocs/auth";
import { CommonComponent } from "@/types/typings";
import { Label, Text, View } from "@tarojs/components";
import { buildUrl } from "@/utils";
import dayjs from "dayjs";
import shipOrder from "@/constant/shipOrder";
import { Button, Popup, SafeArea, Toast } from "@nutui/nutui-react-taro";
export default hocAuth(function Page(props: CommonComponent) {
const { shareOptions } = props;
const [state, setState] = useState<BusinessAPI.ShipOrderPageQry["state"]>();
const [dealerVO, setDealerVO] = useState<BusinessAPI.DealerVO>();
const [deliveryTemplate, setDeliveryTemplate] =
useState<BusinessAPI.DealerVO["deliveryTemplate"]>();
// 控制弹窗显示状态
const [popupVisible, setPopupVisible] = useState(false);
// 当前选中的发货单
const [currentShipOrder, setCurrentShipOrder] =
useState<BusinessAPI.ShipOrderVO | null>(null);
// 生成发货单据
const generateDocument = async () => {
if (!currentShipOrder?.shipOrderId) {
Toast.show("toast", {
icon: "fail",
title: "提示",
content: "未找到关联的发货单",
});
return;
}
try {
// 跳转到发货单据生成页面
Taro.navigateTo({
url: buildUrl("/pages/delivery/document/delivery", {
shipOrderId: currentShipOrder.shipOrderId,
}),
success: () => {
setPopupVisible(false);
},
});
} catch (error) {
Toast.show("toast", {
icon: "fail",
title: "提示",
content: "跳转发货单据页面失败",
});
}
};
const actionRef = useRef<ActionType>();
const toolbar: ToolBar = {
search: {
activeKey: "vehicleNo",
defaultActiveKey: "vehicleNo",
items: [
{
key: "vehicleNo",
name: "车次号",
placeholder: "请输入车次号",
},
{
key: "plate",
name: "车牌号",
placeholder: "请输入车牌号",
},
],
},
tabs: {
activeKey: "state",
defaultActiveKey: state || "ALL",
items: shipOrder.stateList,
onChange: (item) => {
setState(item as BusinessAPI.ShipOrderPageQry["state"]);
actionRef.current?.reload();
},
},
render: () => (
<>
{/* 生成单据弹窗 */}
<Popup
duration={150}
style={{
minHeight: "auto",
}}
visible={popupVisible}
className={"flex flex-col"}
position="bottom"
title={"生成单据"}
onClose={() => setPopupVisible(false)}
onOverlayClick={() => setPopupVisible(false)}
lockScroll
>
<View className={"flex flex-col gap-3 p-2.5"}>
<View className="mb-2.5 border-b border-gray-200 pb-2">
<Text className="text-lg font-semibold"></Text>
</View>
{currentShipOrder && (
<View className="mb-2.5 flex flex-col gap-2.5">
<View className="flex flex-row justify-between">
<Text className="text-sm text-gray-600">:</Text>
<Text className="text-sm font-medium">
{currentShipOrder.orderSn || "-"}
</Text>
</View>
<View className="flex flex-row justify-between">
<Text className="text-sm text-gray-600">:</Text>
<Text className="text-sm font-medium">
{currentShipOrder.vehicleNo || "-"}
</Text>
</View>
<View className="flex flex-row justify-between">
<Text className="text-sm text-gray-600">:</Text>
<Text className="text-sm font-medium">
{currentShipOrder.dealerName || "-"}
</Text>
</View>
</View>
)}
{currentShipOrder && (
<View className="border-t border-gray-200 pt-2.5">
<View className="mb-2">
<Text className="text-lg font-semibold"></Text>
</View>
<View className="flex flex-col gap-3">
{!deliveryTemplate ? (
<View className="border-t border-gray-200 pt-2.5">
<View className="flex flex-col gap-3">
<View className="mt-2.5 text-center text-sm text-red-500">
</View>
</View>
</View>
) : (
<View className="border-t border-gray-200 pt-2.5">
<View className="flex flex-col gap-3">
<View className="text-primary mt-2.5 text-center text-sm">
</View>
</View>
</View>
)}
</View>
</View>
)}
</View>
<View className={"flex w-full flex-col bg-white"}>
<View className={"flex flex-row gap-2 p-3"}>
<View className={"flex-1"}>
<Button
type="default"
size={"xlarge"}
block
onClick={() => setPopupVisible(false)}
>
</Button>
</View>
<View className={"flex-1"}>
<Button
type="primary"
size={"xlarge"}
disabled={!deliveryTemplate}
block
onClick={generateDocument}
>
</Button>
</View>
</View>
<SafeArea position={"bottom"} />
</View>
</Popup>
<View className={"flex flex-row gap-2.5"}>
<DealerPicker
onFinish={(dealerVO) => {
setDealerVO(dealerVO);
actionRef.current?.reload();
}}
trigger={
<View
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
>
<View className={"text-primary text-xs"}>
{dealerVO?.shortName || "经销商"}
</View>
{dealerVO?.shortName ? (
<Icon
name={"circle-xmark"}
size={16}
onClick={(event) => {
setDealerVO(undefined);
actionRef.current?.reload();
event.stopPropagation();
}}
/>
) : (
<Icon name={"chevron-down"} size={16} />
)}
</View>
}
/>
</View>
</>
),
};
useShareAppMessage((res) => {
console.log("useShareAppMessage1", res, shareOptions);
// 如果是按钮触发的转发,使用默认配置
if (res.from === "button") {
return shareOptions;
}
// 页面转发使用设置的配置
return {};
});
return (
<PageList<BusinessAPI.OrderShipVO, BusinessAPI.OrderShipPageQry>
rowId={"shipOrderId"}
itemHeight={182}
type={"infinite"}
actionRef={actionRef}
render={(shipOrderVO: BusinessAPI.OrderShipVO, index) => (
<View className={"mb-2.5"} key={index}>
<View
className={
"relative flex flex-col divide-y-2 divide-neutral-100 rounded-lg bg-white px-2.5"
}
>
<View className={"flex flex-col divide-y-2 divide-neutral-100"}>
<View className={"py-2.5"}>
<View className={"flex flex-row items-center"}>
<View className={"flex flex-1 flex-col gap-2"}>
<View className={"flex flex-row gap-1"}>
{/* 复制 */}
<Text
className={"text-neutral-darkest text-xl font-bold"}
>
{shipOrderVO?.vehicleNo
? "第" + shipOrderVO.vehicleNo + "车"
: "暂未生成车次"}
</Text>
</View>
<Text className={"text-neutral-dark text-sm"}>
{shipOrderVO.orderSn}
</Text>
</View>
<State
state={shipOrderVO.state}
stateMap={shipOrder.stateMap}
/>
</View>
</View>
<View className={"py-2.5"}>
<View className={"flex flex-col gap-2"}>
<View
className={
"flex flex-row items-center justify-between gap-2.5"
}
>
<Label className={"text-neutral-dark text-sm"}>
</Label>
<Text className={"text-neutral-darkest text-sm"}>
{shipOrderVO.createdByName}
</Text>
</View>
<View
className={
"flex flex-row items-center justify-between gap-2.5"
}
>
<Label className={"text-neutral-dark text-sm"}>
</Label>
<Text className={"text-neutral-darkest text-sm"}>
{dayjs(shipOrderVO.createdAt).format("MM-DD HH:mm")}
</Text>
</View>
<View
className={
"flex flex-row items-center justify-between gap-2.5"
}
>
<Label className={"text-neutral-dark text-sm"}>
</Label>
<Text className={"text-neutral-darkest text-sm"}>
{shipOrderVO.dealerName}
</Text>
</View>
</View>
</View>
</View>
<View className={"py-2.5"}>
<View className={"flex flex-row justify-end gap-2"}>
{shipOrderVO.document ? (
<Button
type={"primary"}
size={"small"}
onClick={() => {
Taro.navigateTo({
url: buildUrl("/pages/delivery/document/delivery", {
shipOrderId: shipOrderVO.shipOrderId,
}),
});
}}
>
</Button>
) : (
<Button
type={"primary"}
size={"small"}
onClick={async (e) => {
setCurrentShipOrder(shipOrderVO);
const { data: dealerData } =
await business.dealer.showDealer({
dealerShowQry: {
dealerId: shipOrderVO.dealerId,
},
});
if (dealerData.success) {
const deliveryTemplate =
dealerData.data?.deliveryTemplate;
setDeliveryTemplate(deliveryTemplate);
}
setPopupVisible(true);
e.stopPropagation();
}}
>
</Button>
)}
</View>
</View>
</View>
</View>
)}
toolbar={toolbar}
request={async (params) => {
const {
data: { data, success, notEmpty },
} = await business.orderShip.pageOrderShip({
orderShipPageQry: {
...params,
//@ts-ignore
state: state !== "ALL" ? state : undefined,
...(dealerVO
? {
dealerId: dealerVO.dealerId,
}
: {}),
},
});
return {
data,
success,
hasMore: notEmpty,
};
}}
pagination={{
pageSize: 10,
}}
/>
);
});

View File

@ -411,7 +411,9 @@ export default hocAuth(function Page(props: CommonComponent) {
</View>
<View className={"py-2.5"}>
<View className={"flex flex-row justify-end gap-2"}>
{!orderSupplierVO.invoiceUpload && (
{!orderSupplierVO.invoiceUpload &&
(orderSupplierVO.poState === "WAITING_AUDIT" ||
orderSupplierVO.poState === "COMPLETED") && (
<Button
size={"small"}
type={"primary"}
@ -436,7 +438,7 @@ export default hocAuth(function Page(props: CommonComponent) {
orderSupplierPageQry: {
...params,
invoiceUpload: false,
poStates: ["WAITING_AUDIT", "COMPLETED", "REJECTED"],
poStates: ["WAITING_AUDIT", "COMPLETED"],
...(supplierVO
? {
supplierId: supplierVO.supplierId,

View File

@ -424,7 +424,7 @@ export default hocAuth(function Page(props: CommonComponent) {
orderSupplierPageQry: {
...params,
invoiceUpload: false,
poStates: ["WAITING_AUDIT", "COMPLETED", "REJECTED"],
poStates: ["WAITING_AUDIT", "COMPLETED"],
...(supplierVO
? {
supplierId: supplierVO.supplierId,

View File

@ -14,46 +14,25 @@ export default hocAuth(function Page(props: CommonComponent) {
const [purchaseOrder, setPurchaseOrder] =
useState<BusinessAPI.PurchaseOrderVO>();
const [shipOrder, setShipOrder] = useState<BusinessAPI.ShipOrderVO>();
const [deliveryTemplate, setDeliveryTemplate] =
useState<BusinessAPI.DealerVO["deliveryTemplate"]>();
const [orderShip, setOrderShip] = useState<BusinessAPI.OrderShip>();
console.log("orderShip", orderShip);
const init = async (orderId: string) => {
setLoading(true);
try {
// 获取采购单信息
const { data: purchaseData } =
await business.purchaseOrder.showPurchaseOrder({
const {
data: { data: purchaseOrder, success },
} = await business.purchaseOrder.showPurchaseOrder({
purchaseOrderShowQry: {
orderId: orderId,
},
});
if (purchaseData.success) {
setPurchaseOrder(purchaseData.data);
// 获取关联的发货单信息
// 使用 showShipOrder 替代 listShipOrder
const { data: shipData } = await business.shipOrder.showShipOrder({
shipOrderShowQry: {
purchaseOrderId: orderId,
},
});
if (shipData.success && shipData.data) {
setShipOrder(shipData.data);
}
// 检查经销商支持的单据类型
if (purchaseData.data?.orderDealer?.dealerId) {
const { data: dealerData } = await business.dealer.showDealer({
dealerShowQry: {
dealerId: purchaseData.data.orderDealer.dealerId,
},
});
setDeliveryTemplate(dealerData.data?.deliveryTemplate);
}
if (success) {
setPurchaseOrder(purchaseOrder);
const orderShip = purchaseOrder?.orderShipList[0];
setOrderShip(orderShip);
}
} catch (error) {
Toast.show("toast", {
@ -72,33 +51,6 @@ export default hocAuth(function Page(props: CommonComponent) {
}
}, [orderId]);
// 生成发货单据
const generateDocument = async () => {
if (!shipOrder?.shipOrderId) {
Toast.show("toast", {
icon: "fail",
title: "提示",
content: "未找到关联的发货单",
});
return;
}
try {
// 跳转到发货单据生成页面
Taro.navigateTo({
url: buildUrl("/pages/delivery/document/delivery", {
shipOrderId: shipOrder.shipOrderId,
}),
});
} catch (error) {
Toast.show("toast", {
icon: "fail",
title: "提示",
content: "跳转发货单据页面失败",
});
}
};
return (
<View className="flex flex-1 flex-col gap-2.5">
<View className="flex flex-1 flex-col items-center justify-start bg-gray-100 p-2.5">
@ -155,27 +107,29 @@ export default hocAuth(function Page(props: CommonComponent) {
</View>
</View>
{shipOrder && (
{orderShip && (
<View className="border-t border-gray-200 pt-2.5">
<View className="mb-2">
<Text className="text-lg font-semibold"></Text>
</View>
<View className="flex flex-col gap-3">
{deliveryTemplate ? (
<Button
type="primary"
size={"xlarge"}
block
onClick={generateDocument}
onClick={async () => {
// 跳转到发货单据生成页面
await Taro.navigateTo({
url: buildUrl("/pages/delivery/document/delivery", {
orderShipId: orderShip.orderShipId,
orderId: orderShip.orderId,
}),
});
}}
>
</Button>
) : (
<View className="mt-2.5 text-center text-sm text-red-500">
</View>
)}
</View>
</View>
)}

View File

@ -2788,6 +2788,10 @@ declare namespace BusinessAPI {
orderId: string;
/** 发货单编号 */
orderSn: string;
/** 经销商ID */
dealerId?: string;
/** 经销商名称 */
dealerName?: string;
/** 仓库ID */
warehouseId?: string;
/** 仓库名称 */
@ -2986,6 +2990,10 @@ declare namespace BusinessAPI {
orderShipId: string;
/** 采购单ID */
orderId: string;
/** 经销商ID */
dealerId?: string;
/** 经销商名称 */
dealerName?: string;
/** 发货单编号 */
orderSn?: string;
/** 仓库ID */
@ -3032,6 +3040,8 @@ declare namespace BusinessAPI {
orderShipItemList?: OrderShipItem[];
/** 发货单成本项目信息 */
orderCostList?: OrderCost[];
/** 采购订单车辆运输信息 */
orderVehicle?: OrderVehicle;
};
type OrderSupplier = {
@ -3105,11 +3115,13 @@ declare namespace BusinessAPI {
orderVehicle?: OrderVehicle;
/** 是否选中 */
selected: boolean;
/** 采购订单状态: 0_草稿1_审核中2_已完成3_已驳回4_已关闭 */
poState?: "DRAFT" | "WAITING_AUDIT" | "COMPLETED" | "REJECTED" | "CLOSED";
};
type OrderSupplierBatchInvoiceUploadCmd = {
/** 供应商ID列表 */
orderSupplierIdList: string[];
orderSupplierIdList: number[];
/** 是否上传票证 */
invoiceUpload?: boolean;
/** 发票照片 */
@ -4078,6 +4090,8 @@ declare namespace BusinessAPI {
status?: boolean;
/** 采购订单ID */
orderId?: string;
/** 发货订单ID */
orderShipId?: string;
};
type PurchaseOrderStep1Cmd = {

View File

@ -69,6 +69,8 @@ export const convertPurchaseOrderToOrderShip = (
orderId: purchaseOrderVO.orderId,
orderSn: "",
watermelonGrade: "",
dealerId: purchaseOrderVO.orderVehicle?.dealerId!,
dealerName: purchaseOrderVO.orderVehicle?.dealerName!,
companyId: purchaseOrderVO.orderCompany?.companyId,
companyName: purchaseOrderVO.orderCompany?.fullName,
shippingAddress: purchaseOrderVO.orderVehicle?.origin,

View File

@ -23,15 +23,15 @@ const groupBy = <T>(
/**
* ShipOrder转换为示例数据格式
* @param purchaseOrderVO
* @param shipOrder
* @returns
*/
export const convertShipOrderVOToExamplesFormat = (
purchaseOrderVO: BusinessAPI.PurchaseOrderVO,
shipOrder: BusinessAPI.OrderShip,
) => {
const calculator = new PurchaseOrderCalculator(purchaseOrderVO);
const shipOrder = purchaseOrderVO.orderShipList[0]!;
// 转换包装信息,根据 boxSpecId 分组
const allPackages: BusinessAPI.OrderPackage[] = [];
purchaseOrderVO.orderSupplierList?.forEach((supplier) => {

File diff suppressed because one or more lines are too long