Compare commits
3 Commits
9c0c0de0c7
...
74623e6c1b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74623e6c1b | ||
|
|
5bdd8afdd6 | ||
|
|
761bc7c8ed |
@ -42,6 +42,11 @@ config = {
|
||||
root: "pages/delivery",
|
||||
pages: ["list", "document/delivery", "document/purchase"],
|
||||
},
|
||||
// 瓜农
|
||||
{
|
||||
root: "pages/supplier",
|
||||
pages: ["list", "purchase/invoice"],
|
||||
},
|
||||
],
|
||||
permission: {
|
||||
"scope.userLocation": {
|
||||
|
||||
@ -248,7 +248,7 @@ export default <T extends {}, Q extends Query = Query>(
|
||||
list={data}
|
||||
itemRender={(item, index) =>
|
||||
(toolbar?.selectRow && (
|
||||
<View className={"flex items-center justify-center"}>
|
||||
<View className={"flex items-center justify-center bg-white"}>
|
||||
<Checkbox
|
||||
className={"pl-2"}
|
||||
checked={selectRows.indexOf(item[rowId]) != -1}
|
||||
@ -302,7 +302,43 @@ export default <T extends {}, Q extends Query = Query>(
|
||||
onLoadMore={loadMore}
|
||||
onRefresh={refresh}
|
||||
>
|
||||
{data.map((item, index) => render(item as any, index))}
|
||||
{data.map(
|
||||
(item, index) =>
|
||||
(toolbar?.selectRow && (
|
||||
<View
|
||||
className={
|
||||
"mb-2.5 flex flex-1 items-start gap-2.5 rounded-md bg-white p-2.5 shadow-md"
|
||||
}
|
||||
key={index}
|
||||
>
|
||||
<Checkbox
|
||||
checked={selectRows.some(
|
||||
(item1) => item1[rowId] == item[rowId],
|
||||
)}
|
||||
value={item[rowId]}
|
||||
onClick={() => {
|
||||
if (
|
||||
selectRows.some(
|
||||
(item1) => item1[rowId] === item[rowId],
|
||||
)
|
||||
) {
|
||||
setSelectRows((prev) => {
|
||||
return prev.filter(
|
||||
(item1) => item1[rowId] !== item[rowId],
|
||||
);
|
||||
});
|
||||
} else {
|
||||
setSelectRows((prev) => {
|
||||
return [...prev, item];
|
||||
});
|
||||
}
|
||||
}}
|
||||
></Checkbox>
|
||||
{render(item as any, index)}
|
||||
</View>
|
||||
)) ||
|
||||
render(item as any, index),
|
||||
)}
|
||||
</InfiniteLoading>
|
||||
</View>
|
||||
)}
|
||||
@ -315,7 +351,7 @@ export default <T extends {}, Q extends Query = Query>(
|
||||
{toolbar?.actions && toolbar?.actions.map((item) => item)}
|
||||
|
||||
{toolbar?.selectRow?.onClick && (
|
||||
<View key={"confirm"} className={"flex justify-between gap-2"}>
|
||||
<View key={"confirm"} className={"flex justify-between gap-2 p-2.5"}>
|
||||
<View className={"flex flex-1 items-center justify-between gap-1"}>
|
||||
<View className={"flex items-center gap-2"}>
|
||||
<Checkbox
|
||||
@ -329,9 +365,13 @@ export default <T extends {}, Q extends Query = Query>(
|
||||
} else {
|
||||
setSelectAll("1");
|
||||
data?.forEach((item) => {
|
||||
if (selectRows.indexOf(item[rowId]) == -1) {
|
||||
if (
|
||||
!selectRows.some(
|
||||
(item1) => item1[rowId] === item[rowId],
|
||||
)
|
||||
) {
|
||||
setSelectRows((prev) => {
|
||||
return [...prev, item[rowId]];
|
||||
return [...prev, item];
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -343,12 +383,13 @@ export default <T extends {}, Q extends Query = Query>(
|
||||
</Text>
|
||||
</View>
|
||||
<Text className={"text-sm text-stone-950"}>
|
||||
共{selectRows.length || 0}张
|
||||
共{selectRows.length || 0}项
|
||||
</Text>
|
||||
</View>
|
||||
<Button
|
||||
type={"primary"}
|
||||
size={"large"}
|
||||
disabled={!selectRows.length}
|
||||
block={false}
|
||||
onClick={async () => toolbar?.selectRow?.onClick(selectRows)}
|
||||
>
|
||||
|
||||
@ -23,7 +23,7 @@ export type TabPane = {
|
||||
|
||||
export type ToolBar = {
|
||||
selectRow?: {
|
||||
onClick: (selectRow: string[]) => void;
|
||||
onClick: (selectRow: any[]) => void;
|
||||
};
|
||||
actions?: React.ReactNode[];
|
||||
tabs?: {
|
||||
|
||||
574
packages/app-client/src/components/delivery/Step1Form.tsx
Normal file
574
packages/app-client/src/components/delivery/Step1Form.tsx
Normal file
@ -0,0 +1,574 @@
|
||||
import { forwardRef, ReactNode, useImperativeHandle, useState } from "react";
|
||||
import { Text, View } from "@tarojs/components";
|
||||
import {
|
||||
DatePicker,
|
||||
Input,
|
||||
PickerOption,
|
||||
Toast,
|
||||
} from "@nutui/nutui-react-taro";
|
||||
import dayjs from "dayjs";
|
||||
import { Icon } from "@/components";
|
||||
|
||||
interface Step1FormProps {
|
||||
moduleList: any[];
|
||||
shipOrderVO: any;
|
||||
setShipOrderVO: (value: any) => void;
|
||||
}
|
||||
|
||||
export interface Step1FormRef {
|
||||
validateForm: () => boolean;
|
||||
}
|
||||
|
||||
const Step1Form = forwardRef<Step1FormRef, Step1FormProps>((props, ref) => {
|
||||
const { moduleList, shipOrderVO, setShipOrderVO } = props;
|
||||
|
||||
// 当天和未来10天
|
||||
const startDate = new Date();
|
||||
const endDate = new Date(startDate.getTime() + 86400000 * 10);
|
||||
const [show, setShow] = useState(false);
|
||||
|
||||
const formatter = (type: string, option: PickerOption) => {
|
||||
switch (type) {
|
||||
case "year":
|
||||
option.label += "年";
|
||||
break;
|
||||
case "month":
|
||||
option.label += "月";
|
||||
break;
|
||||
case "day":
|
||||
option.label += "日";
|
||||
break;
|
||||
case "hour":
|
||||
option.label += "时";
|
||||
break;
|
||||
case "minute":
|
||||
option.label += "分";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return option;
|
||||
};
|
||||
|
||||
// 表单错误状态
|
||||
const [formErrors, setFormErrors] = useState<{
|
||||
watermelonGrade?: boolean;
|
||||
shippingAddress?: boolean;
|
||||
estimatedArrivalDate?: boolean;
|
||||
remark?: boolean;
|
||||
itemGrades?: { [key: string]: boolean };
|
||||
}>({});
|
||||
|
||||
// 暴露方法给父组件
|
||||
useImperativeHandle(ref, () => ({
|
||||
validateForm,
|
||||
}));
|
||||
|
||||
// 渲染内容配置表单字段
|
||||
const renderContentFields = (module: any) => {
|
||||
const contentSchema = module.schemas.find(
|
||||
(schema: any) => schema.title === "内容配置",
|
||||
);
|
||||
if (
|
||||
!contentSchema ||
|
||||
!contentSchema.columns ||
|
||||
contentSchema.columns.length === 0
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const contentFields: ReactNode[] = [];
|
||||
|
||||
contentSchema.columns.forEach((column: any, index: number) => {
|
||||
if (
|
||||
column.dataIndex === "requiredWatermelonGrade" &&
|
||||
module.config.showWatermelonGrade
|
||||
) {
|
||||
contentFields.push(
|
||||
<View key={index} className="mb-2.5">
|
||||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||||
{column.title}
|
||||
</View>
|
||||
<View className="mb-2.5">
|
||||
<View
|
||||
className={`flex h-10 w-full items-center rounded-md ${formErrors.watermelonGrade ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||||
>
|
||||
<Input
|
||||
value={shipOrderVO?.watermelonGrade || ""}
|
||||
onChange={(value) => {
|
||||
// 清除错误状态
|
||||
if (formErrors.watermelonGrade && value) {
|
||||
setFormErrors((prev) => ({
|
||||
...prev,
|
||||
watermelonGrade: false,
|
||||
}));
|
||||
}
|
||||
|
||||
setShipOrderVO((prev: any) => {
|
||||
return {
|
||||
...prev!,
|
||||
watermelonGrade: value,
|
||||
};
|
||||
});
|
||||
}}
|
||||
onBlur={() => {
|
||||
// 失焦时校验
|
||||
if (!shipOrderVO?.watermelonGrade) {
|
||||
setFormErrors((prev) => ({
|
||||
...prev,
|
||||
watermelonGrade: true,
|
||||
}));
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title:
|
||||
column.fieldProps?.placeholder ||
|
||||
`请填写${column.title}`,
|
||||
});
|
||||
}
|
||||
}}
|
||||
placeholder={
|
||||
column.fieldProps?.placeholder || `请${column.title}`
|
||||
}
|
||||
type="text"
|
||||
className="flex-1"
|
||||
/>
|
||||
</View>
|
||||
|
||||
{formErrors.watermelonGrade && (
|
||||
<View className="mt-1 text-xs text-red-500">
|
||||
{`请${column.title}`}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
column.dataIndex === "requiredShippingFrom" &&
|
||||
module.config.showShippingFrom
|
||||
) {
|
||||
contentFields.push(
|
||||
<View key={index} className="mb-2.5">
|
||||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||||
{column.title}
|
||||
</View>
|
||||
<View className="mb-2.5">
|
||||
<View
|
||||
className={`flex h-10 w-full items-center rounded-md ${formErrors.shippingAddress ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||||
>
|
||||
<Input
|
||||
value={shipOrderVO?.shippingAddress || ""}
|
||||
onChange={(value) => {
|
||||
// 清除错误状态
|
||||
if (formErrors.shippingAddress && value) {
|
||||
setFormErrors((prev) => ({
|
||||
...prev,
|
||||
shippingAddress: false,
|
||||
}));
|
||||
}
|
||||
|
||||
setShipOrderVO((prev: any) => {
|
||||
return {
|
||||
...prev!,
|
||||
shippingAddress: value,
|
||||
};
|
||||
});
|
||||
}}
|
||||
onBlur={() => {
|
||||
// 失焦时校验
|
||||
if (!shipOrderVO?.shippingAddress) {
|
||||
setFormErrors((prev) => ({
|
||||
...prev,
|
||||
shippingAddress: true,
|
||||
}));
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title:
|
||||
column.fieldProps?.placeholder ||
|
||||
`请填写${column.title}`,
|
||||
});
|
||||
}
|
||||
}}
|
||||
placeholder={
|
||||
column.fieldProps?.placeholder || `请${column.title}`
|
||||
}
|
||||
type="text"
|
||||
className="flex-1"
|
||||
/>
|
||||
</View>
|
||||
|
||||
{formErrors.shippingAddress && (
|
||||
<View className="mt-1 text-xs text-red-500">
|
||||
{`请${column.title}`}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
column.dataIndex === "requiredEstimatedArrivalTime" &&
|
||||
module.config.showEstimatedArrivalTime
|
||||
) {
|
||||
contentFields.push(
|
||||
<View key={index} className="mb-2.5">
|
||||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||||
{column.title}
|
||||
</View>
|
||||
<View className="mb-2.5">
|
||||
<View
|
||||
className={`flex h-10 w-full items-center rounded-md ${formErrors.estimatedArrivalDate ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||||
>
|
||||
<View
|
||||
className={
|
||||
"flex flex-1 flex-row items-center justify-between px-5"
|
||||
}
|
||||
style={{
|
||||
color: "var(--nutui-color-title, #1a1a1a)",
|
||||
}}
|
||||
onClick={() => setShow(true)}
|
||||
>
|
||||
<View className={"text-sm"}>
|
||||
{shipOrderVO?.estimatedArrivalDate
|
||||
? dayjs(shipOrderVO?.estimatedArrivalDate).format(
|
||||
"YYYY年MM月DD日",
|
||||
)
|
||||
: column.fieldProps?.placeholder || `请${column.title}`}
|
||||
</View>
|
||||
<Icon name={"chevron-down"} />
|
||||
</View>
|
||||
<DatePicker
|
||||
title="发货时间选择"
|
||||
type="date"
|
||||
startDate={startDate}
|
||||
endDate={endDate}
|
||||
visible={show}
|
||||
defaultValue={new Date()}
|
||||
formatter={formatter}
|
||||
onClose={() => setShow(false)}
|
||||
onConfirm={(_, values) => {
|
||||
// 选择日期后清除错误状态
|
||||
if (formErrors.estimatedArrivalDate) {
|
||||
setFormErrors((prev) => ({
|
||||
...prev,
|
||||
estimatedArrivalDate: false,
|
||||
}));
|
||||
}
|
||||
|
||||
setShipOrderVO((prev: any) => {
|
||||
return {
|
||||
...prev!,
|
||||
estimatedArrivalDate: dayjs(values.join("-")).format(
|
||||
"YYYY-MM-DD",
|
||||
),
|
||||
};
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{formErrors.estimatedArrivalDate && (
|
||||
<View className="mt-1 text-xs text-red-500">
|
||||
{`请${column.title}`}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
}
|
||||
|
||||
if (column.dataIndex === "requiredRemarks" && module.config.showRemarks) {
|
||||
contentFields.push(
|
||||
<View key={index} className="mb-2.5">
|
||||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||||
{column.title}
|
||||
</View>
|
||||
<View className="mb-2.5">
|
||||
<View
|
||||
className={`flex h-10 w-full items-center rounded-md ${formErrors.remark ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||||
>
|
||||
<Input
|
||||
value={shipOrderVO?.remark || ""}
|
||||
onChange={(value) => {
|
||||
// 清除错误状态
|
||||
if (formErrors.remark && value) {
|
||||
setFormErrors((prev) => ({
|
||||
...prev,
|
||||
remark: false,
|
||||
}));
|
||||
}
|
||||
|
||||
setShipOrderVO((prev: any) => {
|
||||
return {
|
||||
...prev!,
|
||||
remark: value,
|
||||
};
|
||||
});
|
||||
}}
|
||||
onBlur={() => {
|
||||
// 失焦时校验
|
||||
if (!shipOrderVO?.remark) {
|
||||
setFormErrors((prev) => ({
|
||||
...prev,
|
||||
remark: true,
|
||||
}));
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title:
|
||||
column.fieldProps?.placeholder ||
|
||||
`请填写${column.title}`,
|
||||
});
|
||||
}
|
||||
}}
|
||||
placeholder={
|
||||
column.fieldProps?.placeholder || `请${column.title}`
|
||||
}
|
||||
type="text"
|
||||
className="flex-1"
|
||||
/>
|
||||
</View>
|
||||
|
||||
{formErrors.remark && (
|
||||
<View className="mt-1 text-xs text-red-500">
|
||||
{`请${column.title}`}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>,
|
||||
);
|
||||
}
|
||||
|
||||
if (column.dataIndex === "requiredGrade" && module.config.showGrade) {
|
||||
contentFields.push(
|
||||
<View key={index} className="mb-2.5">
|
||||
<View className="mb-1 block text-sm font-normal text-[#000000]">
|
||||
{column.title}
|
||||
</View>
|
||||
{shipOrderVO?.shipOrderItemList?.map(
|
||||
(shipOrderItem: any, index: number) => {
|
||||
return (
|
||||
<View key={"shipOrderItem" + index} className="mb-2.5">
|
||||
<View
|
||||
key={shipOrderItem.itemId}
|
||||
className={"flex flex-row gap-2.5"}
|
||||
>
|
||||
<View className="flex flex-1 items-center text-sm font-normal text-[#000000]">
|
||||
单价:{shipOrderItem.unitPrice} 元/斤
|
||||
</View>
|
||||
|
||||
<View
|
||||
className={`flex h-10 items-center rounded-md ${formErrors.itemGrades?.[shipOrderItem.itemId] ? "border-4 border-red-500" : "border-4 border-gray-300"}`}
|
||||
>
|
||||
<Input
|
||||
value={shipOrderItem.watermelonGrade || ""}
|
||||
onChange={(value) => {
|
||||
// 清除该项的错误状态
|
||||
if (
|
||||
formErrors.itemGrades?.[shipOrderItem.itemId] &&
|
||||
value
|
||||
) {
|
||||
setFormErrors((prev) => ({
|
||||
...prev,
|
||||
itemGrades: {
|
||||
...prev.itemGrades,
|
||||
[shipOrderItem.itemId]: false,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
setShipOrderVO((prev: any) => {
|
||||
return {
|
||||
...prev!,
|
||||
shipOrderItemList: prev?.shipOrderItemList?.map(
|
||||
(item: any) => {
|
||||
if (item.itemId === shipOrderItem.itemId) {
|
||||
return {
|
||||
...item,
|
||||
watermelonGrade: value,
|
||||
};
|
||||
}
|
||||
return item;
|
||||
},
|
||||
),
|
||||
};
|
||||
});
|
||||
}}
|
||||
onBlur={() => {
|
||||
// 失焦时校验
|
||||
if (!shipOrderItem.watermelonGrade) {
|
||||
setFormErrors((prev) => ({
|
||||
...prev,
|
||||
itemGrades: {
|
||||
...prev.itemGrades,
|
||||
[shipOrderItem.itemId]: true,
|
||||
},
|
||||
}));
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title:
|
||||
column.fieldProps?.placeholder ||
|
||||
`请填写第${index + 1}项的品级`,
|
||||
});
|
||||
}
|
||||
}}
|
||||
placeholder={
|
||||
column.fieldProps?.placeholder ||
|
||||
`请${column.title}`
|
||||
}
|
||||
type="text"
|
||||
className="flex-1"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{formErrors.itemGrades?.[shipOrderItem.itemId] && (
|
||||
<View className="mt-1 text-xs text-red-500">
|
||||
{`请${column.title}`}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</View>,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (contentFields.length > 0) {
|
||||
return contentFields;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
// 表单校验
|
||||
const validateForm = () => {
|
||||
const errors: any = {};
|
||||
let hasErrors = false;
|
||||
|
||||
// 检查各模块中的必填字段是否已填写
|
||||
for (const module of moduleList) {
|
||||
const contentSchema = module.schemas.find(
|
||||
(schema: any) => schema.title === "内容配置",
|
||||
);
|
||||
|
||||
if (
|
||||
!contentSchema ||
|
||||
!contentSchema.columns ||
|
||||
contentSchema.columns.length === 0
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const column of contentSchema.columns) {
|
||||
// 检查西瓜品级字段是否开启且已填写
|
||||
if (
|
||||
column.dataIndex === "requiredWatermelonGrade" &&
|
||||
module.config.showWatermelonGrade
|
||||
) {
|
||||
if (!shipOrderVO?.watermelonGrade) {
|
||||
errors.watermelonGrade = true;
|
||||
hasErrors = true;
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: column.fieldProps?.placeholder || `请填写${column.title}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
// 检查发货地字段是否开启且已填写
|
||||
else if (
|
||||
column.dataIndex === "requiredShippingFrom" &&
|
||||
module.config.showShippingFrom
|
||||
) {
|
||||
if (!shipOrderVO?.shippingAddress) {
|
||||
errors.shippingAddress = true;
|
||||
hasErrors = true;
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: column.fieldProps?.placeholder || `请填写${column.title}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
// 检查预计到仓时间字段是否开启且已填写
|
||||
else if (
|
||||
column.dataIndex === "requiredEstimatedArrivalTime" &&
|
||||
module.config.showEstimatedArrivalTime
|
||||
) {
|
||||
if (!shipOrderVO?.estimatedArrivalDate) {
|
||||
errors.estimatedArrivalDate = true;
|
||||
hasErrors = true;
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: column.fieldProps?.placeholder || `请选择${column.title}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
// 检查备注字段是否开启且已填写
|
||||
else if (
|
||||
column.dataIndex === "requiredRemarks" &&
|
||||
module.config.showRemarks
|
||||
) {
|
||||
if (!shipOrderVO?.remark) {
|
||||
errors.remark = true;
|
||||
hasErrors = true;
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: column.fieldProps?.placeholder || `请填写${column.title}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
// 检查品级字段是否开启且已填写
|
||||
else if (
|
||||
column.dataIndex === "requiredGrade" &&
|
||||
module.config.showGrade
|
||||
) {
|
||||
if (shipOrderVO?.shipOrderItemList) {
|
||||
const itemGradesErrors: { [key: string]: boolean } = {};
|
||||
for (let i = 0; i < shipOrderVO.shipOrderItemList.length; i++) {
|
||||
const item = shipOrderVO.shipOrderItemList[i];
|
||||
if (!item.watermelonGrade) {
|
||||
itemGradesErrors[item.itemId] = true;
|
||||
hasErrors = true;
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: `请填写第${i + 1}项的品级`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(itemGradesErrors).length > 0) {
|
||||
errors.itemGrades = itemGradesErrors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setFormErrors(errors);
|
||||
return !hasErrors;
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="flex flex-col rounded-lg bg-white p-2.5 shadow-md">
|
||||
{moduleList.map((module) => {
|
||||
const contentFields = renderContentFields(module);
|
||||
// 如果没有内容配置字段,则不渲染该模块
|
||||
if (!contentFields) return null;
|
||||
|
||||
return (
|
||||
<View key={module.id} className="flex flex-col gap-2.5">
|
||||
<View className="border-b border-b-gray-200 pb-2.5">
|
||||
<Text className="text-base font-semibold">{module.title}</Text>
|
||||
</View>
|
||||
{contentFields}
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
});
|
||||
|
||||
export default Step1Form;
|
||||
186
packages/app-client/src/components/delivery/Step2Preview.tsx
Normal file
186
packages/app-client/src/components/delivery/Step2Preview.tsx
Normal file
@ -0,0 +1,186 @@
|
||||
import { useState } from "react";
|
||||
import { Text, View } from "@tarojs/components";
|
||||
import { Button } from "@nutui/nutui-react-taro";
|
||||
import {
|
||||
DealerInfo,
|
||||
OtherFees,
|
||||
OtherInfo,
|
||||
PackingSpec,
|
||||
ShippingInfo,
|
||||
TitleInfo,
|
||||
TotalAmount,
|
||||
VehicleInfo,
|
||||
WeightInfo,
|
||||
} from "./section";
|
||||
|
||||
interface Step2PreviewProps {
|
||||
moduleList: any[];
|
||||
}
|
||||
|
||||
export default function Step2Preview(props: Step2PreviewProps) {
|
||||
const { moduleList } = props;
|
||||
|
||||
const [scale, setScale] = useState(0.5); // 缩放比例
|
||||
const [touchInfo, setTouchInfo] = useState({
|
||||
startDistance: 0,
|
||||
startScale: 0.5,
|
||||
}); // 触摸信息
|
||||
const [position, setPosition] = useState({ x: 0, y: -(29.7 * 37.8 * 0.5) }); // 当前位置
|
||||
const [startPosition, setStartPosition] = useState({ x: 0, y: 0 }); // 起始位置
|
||||
|
||||
// 放大
|
||||
const zoomIn = () => {
|
||||
setScale((prev) => Math.min(prev + 0.1, 3)); // 最大放大到3倍
|
||||
};
|
||||
|
||||
// 缩小
|
||||
const zoomOut = () => {
|
||||
setScale((prev) => Math.max(prev - 0.1, 0.5)); // 最小缩小到0.5倍
|
||||
};
|
||||
|
||||
// 重置缩放
|
||||
const resetZoom = () => {
|
||||
setScale(0.5);
|
||||
setPosition({ x: 0, y: -(29.7 * 37.8 * 0.5) }); // 重置位置
|
||||
};
|
||||
|
||||
// 计算两点间距离
|
||||
const getDistance = (touches: any) => {
|
||||
const dx = touches[0].clientX - touches[1].clientX;
|
||||
const dy = touches[0].clientY - touches[1].clientY;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
};
|
||||
|
||||
// 处理触摸开始事件
|
||||
const handleTouchStart = (e: any) => {
|
||||
const touches = e.touches;
|
||||
if (touches.length === 2) {
|
||||
// 双指触摸,记录初始距离和当前缩放值
|
||||
const distance = getDistance(touches);
|
||||
setTouchInfo({
|
||||
startDistance: distance,
|
||||
startScale: scale,
|
||||
});
|
||||
} else if (touches.length === 1) {
|
||||
// 单指触摸,记录起始位置
|
||||
setStartPosition({
|
||||
x: touches[0].clientX - position.x,
|
||||
y: touches[0].clientY - position.y,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 处理触摸移动事件
|
||||
const handleTouchMove = (e: any) => {
|
||||
const touches = e.touches;
|
||||
e.preventDefault(); // 阻止默认滚动行为
|
||||
|
||||
if (touches.length === 2) {
|
||||
// 双指触摸,计算缩放比例
|
||||
const currentDistance = getDistance(touches);
|
||||
const newScale =
|
||||
touchInfo.startScale * (currentDistance / touchInfo.startDistance);
|
||||
// 限制缩放范围在0.5到3之间
|
||||
setScale(Math.min(Math.max(0.5, newScale), 3));
|
||||
} else if (touches.length === 1 && scale > 0.5) {
|
||||
// 单指触摸且已放大,允许拖动
|
||||
setPosition({
|
||||
x: touches[0].clientX - startPosition.x,
|
||||
y: touches[0].clientY - startPosition.y,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 处理触摸结束事件
|
||||
const handleTouchEnd = (e: any) => {
|
||||
// 可以在这里添加触摸结束后的处理逻辑
|
||||
console.log("Touch ended", e);
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="flex flex-1 flex-col items-center overflow-hidden">
|
||||
{/* 缩放控制按钮 */}
|
||||
<View className="mb-2 flex w-full justify-center gap-2 bg-white p-2">
|
||||
<Button size="small" onClick={zoomOut}>
|
||||
-
|
||||
</Button>
|
||||
<Button size="small" onClick={resetZoom}>
|
||||
重置
|
||||
</Button>
|
||||
<Button size="small" onClick={zoomIn}>
|
||||
+
|
||||
</Button>
|
||||
<Text className="ml-2 flex items-center">
|
||||
{Math.round(scale * 100)}%
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* 预览区域 */}
|
||||
<View
|
||||
className="flex-1 overflow-auto"
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
onTouchStart={handleTouchStart}
|
||||
onTouchMove={handleTouchMove}
|
||||
onTouchEnd={handleTouchEnd}
|
||||
>
|
||||
<View
|
||||
id="preview"
|
||||
className="rounded-lg bg-white shadow-md"
|
||||
style={{
|
||||
width: "21cm",
|
||||
padding: "2cm 1cm 0 1cm",
|
||||
margin: "0 auto",
|
||||
height: "29.7cm", // A4纸高度
|
||||
transform: `scale(${scale}) translate(${position.x}px, ${position.y}px)`,
|
||||
transformOrigin: "center center",
|
||||
transition:
|
||||
scale === touchInfo.startScale ? "transform 0.2s ease" : "none",
|
||||
}}
|
||||
>
|
||||
{moduleList.map((module) => {
|
||||
if (module.type === "title") {
|
||||
return <TitleInfo key={module.id} module={module} />;
|
||||
}
|
||||
|
||||
if (module.type === "dealerInfo") {
|
||||
return <DealerInfo key={"dealerInfo"} module={module} />;
|
||||
}
|
||||
|
||||
if (module.type === "shippingInfo") {
|
||||
return <ShippingInfo key={module.id} module={module} />;
|
||||
}
|
||||
|
||||
if (module.type === "weightInfo") {
|
||||
return <WeightInfo key={"weightInfo"} module={module} />;
|
||||
}
|
||||
|
||||
if (module.type === "packingSpec") {
|
||||
return <PackingSpec key={module.id} module={module} />;
|
||||
}
|
||||
|
||||
if (module.type === "vehicleInfo") {
|
||||
return <VehicleInfo key={module.id} module={module} />;
|
||||
}
|
||||
|
||||
if (module.type === "otherFees") {
|
||||
return <OtherFees key={module.id} module={module} />;
|
||||
}
|
||||
|
||||
if (module.type === "totalAmount") {
|
||||
return <TotalAmount key={module.id} module={module} />;
|
||||
}
|
||||
|
||||
if (module.type === "otherInfo") {
|
||||
return <OtherInfo key={module.id} module={module} />;
|
||||
}
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
122
packages/app-client/src/components/delivery/Step3Success.tsx
Normal file
122
packages/app-client/src/components/delivery/Step3Success.tsx
Normal file
@ -0,0 +1,122 @@
|
||||
import { useState } from "react";
|
||||
import { Text, View } from "@tarojs/components";
|
||||
import { Button } from "@nutui/nutui-react-taro";
|
||||
import Taro from "@tarojs/taro";
|
||||
|
||||
interface Step3SuccessProps {
|
||||
document: string;
|
||||
}
|
||||
|
||||
export default function Step3Success(props: Step3SuccessProps) {
|
||||
const { document } = props;
|
||||
const [tempFilePath, setTempFilePath] = useState<string>();
|
||||
|
||||
// 查看文档
|
||||
const handleView = async () => {
|
||||
if (!tempFilePath) {
|
||||
Taro.showToast({
|
||||
title: "请先下载发货单据",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Taro.openDocument({
|
||||
filePath: tempFilePath,
|
||||
showMenu: true,
|
||||
});
|
||||
};
|
||||
|
||||
// 处理下载功能
|
||||
const handleDownload = async () => {
|
||||
Taro.showToast({
|
||||
title: "正在生成并下载发货单据",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
|
||||
// 下载文件
|
||||
Taro.downloadFile({
|
||||
url: document!,
|
||||
}).then((downloadRes) => {
|
||||
if (downloadRes.tempFilePath) {
|
||||
setTempFilePath(downloadRes.tempFilePath);
|
||||
Taro.showToast({
|
||||
title: "发货单据已下载成功,您可以将生成的PDF发送给好友",
|
||||
icon: "none",
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 处理分享功能
|
||||
const handleShare = async () => {
|
||||
if (!tempFilePath) {
|
||||
Taro.showToast({
|
||||
title: "请先下载发货单据",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Taro.showToast({
|
||||
title: "正在分享到微信",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
|
||||
// 下载完成后转发
|
||||
Taro.shareFileMessage({
|
||||
filePath: tempFilePath,
|
||||
fileName: `发货单据.pdf`,
|
||||
complete: (res) => {
|
||||
console.log("complete", res);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="flex flex-1 flex-col items-center justify-center rounded-lg bg-white p-4 shadow-md">
|
||||
<View className="mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-green-100">
|
||||
<Text className="text-2xl text-green-600">✓</Text>
|
||||
</View>
|
||||
<View className="mb-2 text-xl font-bold text-gray-800">
|
||||
发货单据生成成功
|
||||
</View>
|
||||
<View className="mb-8 text-gray-600">
|
||||
您的发货单据已生成,可以下载或转发给好友
|
||||
</View>
|
||||
|
||||
<View className="mb-6 flex w-full flex-row justify-center gap-4">
|
||||
{document && !tempFilePath && (
|
||||
<View className={"flex-1"}>
|
||||
<Button type="default" size="large" block onClick={handleDownload}>
|
||||
下载文档
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
{document && tempFilePath && (
|
||||
<>
|
||||
<View className={"flex-1"}>
|
||||
<Button type="default" size="large" block onClick={handleView}>
|
||||
查看文档
|
||||
</Button>
|
||||
</View>
|
||||
<View className={"flex-1"}>
|
||||
<Button type="primary" size="large" block onClick={handleShare}>
|
||||
转发好友
|
||||
</Button>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View className="text-sm text-gray-500">
|
||||
提示:您可以随时在发货单据列表中重新下载
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
4
packages/app-client/src/components/delivery/index.ts
Normal file
4
packages/app-client/src/components/delivery/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export { default as DeliveryStep1Form } from "./Step1Form";
|
||||
export type { Step1FormRef as DeliveryStep1FormRef } from "./Step1Form";
|
||||
export { default as DeliveryStep2Preview } from "./Step2Preview";
|
||||
export { default as DeliveryStep3Success } from "./Step3Success";
|
||||
@ -0,0 +1,32 @@
|
||||
import { View } from "@tarojs/components";
|
||||
|
||||
export default function DealerInfo(props: { module: any }) {
|
||||
const { module } = props;
|
||||
const { config } = module;
|
||||
return (
|
||||
<View
|
||||
key={module.id}
|
||||
className={"preview grid w-full grid-cols-8 gap-0 text-lg font-bold"}
|
||||
>
|
||||
<View className="col-span-1"></View>
|
||||
{config.showDealerName || config.showWatermelonGrade ? (
|
||||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||||
{config.showWatermelonGrade
|
||||
? `${config.dealerName}-${config.watermelonGrade}`
|
||||
: config.dealerName}
|
||||
</View>
|
||||
) : (
|
||||
<View className="col-span-3"></View>
|
||||
)}
|
||||
{config.showDestination || config.showVehicleNumber ? (
|
||||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||||
{config.destination}
|
||||
{config.vehicleNumber}
|
||||
</View>
|
||||
) : (
|
||||
<View className="col-span-3"></View>
|
||||
)}
|
||||
<View className="col-span-1"></View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
import { View } from "@tarojs/components";
|
||||
|
||||
export default function OtherFees(props: { module: any }) {
|
||||
const { module } = props;
|
||||
const { config } = module;
|
||||
|
||||
return (
|
||||
<View
|
||||
key={module.id}
|
||||
className={"preview grid w-full grid-cols-8 gap-0 text-base"}
|
||||
>
|
||||
{config.feeItems?.map((feeType: any) => (
|
||||
<>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
{config.feeLabels[feeType.itemId]}:
|
||||
</View>
|
||||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||||
{feeType.count * feeType.price}元
|
||||
</View>
|
||||
</>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
import { View } from "@tarojs/components";
|
||||
|
||||
export default function OtherInfo(props: { module: any }) {
|
||||
const { module } = props;
|
||||
const { config } = module;
|
||||
|
||||
return (
|
||||
<View key={module.id} className={"table-border"}>
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">车次:</View>
|
||||
<View className="col-span-2 p-2 text-left">{config.vehicleNumber}</View>
|
||||
</View>
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">收货地:</View>
|
||||
<View className="col-span-2 p-2 text-left">{config.destination}</View>
|
||||
</View>
|
||||
{config.showShippingFrom && (
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">产地:</View>
|
||||
<View className="col-span-2 p-2 text-left">
|
||||
{config.shippingFrom}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">供应商:</View>
|
||||
<View className="col-span-2 p-2 text-left">
|
||||
{config.accountCompany}
|
||||
</View>
|
||||
</View>
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">发车时间:</View>
|
||||
<View className="col-span-2 p-2 text-left">{config.date}</View>
|
||||
</View>
|
||||
{config.showEstimatedArrivalTime && (
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">到达时间:</View>
|
||||
<View className="col-span-2 p-2 text-left">
|
||||
{config.estimatedArrivalTime}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{config.data?.map((item: any) => {
|
||||
return (
|
||||
<>
|
||||
{config.showGrade && (
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">品名:</View>
|
||||
<View className="col-span-2 p-2 text-left">
|
||||
{item.watermelonGrade}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">发货重量:</View>
|
||||
<View className="col-span-2 p-2 text-left">
|
||||
以公司入库重量为准。
|
||||
</View>
|
||||
</View>
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">净瓜单价:</View>
|
||||
<View className="col-span-2 p-2 text-left">
|
||||
{item.unitPrice}
|
||||
{config.unitPriceUnit === "1" ? "元/斤" : "元/公斤"}
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
})}
|
||||
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">大约重量:</View>
|
||||
<View className="p-2 text-left">
|
||||
{config.data?.reduce(
|
||||
(acc: any, cur: any) => acc + cur.grossWeight,
|
||||
0,
|
||||
)}
|
||||
</View>
|
||||
<View className="p-2 text-left">斤</View>
|
||||
</View>
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">箱数</View>
|
||||
<View className="p-2 text-left">
|
||||
{config.data?.reduce((acc: any, cur: any) => acc + cur.boxCount, 0)}
|
||||
</View>
|
||||
<View className="p-2 text-left">件</View>
|
||||
</View>
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">车号:</View>
|
||||
<View className="col-span-2 p-2 text-left">{config.licensePlate}</View>
|
||||
</View>
|
||||
<View className="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<View className="p-2 text-left font-bold">手机号:</View>
|
||||
<View className="col-span-2 p-2 text-left">{config.driverPhone}</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,185 @@
|
||||
import { View } from "@tarojs/components";
|
||||
import classNames from "classnames";
|
||||
|
||||
export default function PackingSpec(props: { module: any }) {
|
||||
const { module } = props;
|
||||
const { config } = module;
|
||||
|
||||
// 计算需要显示的列数
|
||||
const visibleColumnCount =
|
||||
[
|
||||
config.showBoxType,
|
||||
config.showQuantity,
|
||||
config.showUnitPrice,
|
||||
config.showAmount,
|
||||
config.showUnitWeight,
|
||||
config.showWeight,
|
||||
].filter(Boolean).length + 1; // +1 是因为"规格:"列总是显示
|
||||
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
className={classNames(`grid w-full gap-0 text-base`, {
|
||||
"grid-cols-1": visibleColumnCount === 1,
|
||||
"grid-cols-2": visibleColumnCount === 2,
|
||||
"grid-cols-3": visibleColumnCount === 3,
|
||||
"grid-cols-4": visibleColumnCount === 4,
|
||||
"grid-cols-5": visibleColumnCount === 5,
|
||||
"grid-cols-6": visibleColumnCount === 6,
|
||||
"grid-cols-7": visibleColumnCount === 7,
|
||||
"grid-cols-8": visibleColumnCount === 8,
|
||||
})}
|
||||
>
|
||||
<div className={`grid-span-1 flex items-end justify-center`}>
|
||||
规格:
|
||||
</div>
|
||||
</View>
|
||||
|
||||
<View
|
||||
className={classNames(`grid w-full gap-0 text-base`, {
|
||||
"grid-cols-1": visibleColumnCount === 1,
|
||||
"grid-cols-2": visibleColumnCount === 2,
|
||||
"grid-cols-3": visibleColumnCount === 3,
|
||||
"grid-cols-4": visibleColumnCount === 4,
|
||||
"grid-cols-5": visibleColumnCount === 5,
|
||||
"grid-cols-6": visibleColumnCount === 6,
|
||||
"grid-cols-7": visibleColumnCount === 7,
|
||||
"grid-cols-8": visibleColumnCount === 8,
|
||||
})}
|
||||
>
|
||||
{config.columns.map((column: any, index: number) => {
|
||||
if (index === 0) {
|
||||
return (
|
||||
<div key={"title" + index} className="">
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
(column.dataIndex === "boxType" && config.showBoxType) ||
|
||||
(column.dataIndex === "quantity" && config.showQuantity) ||
|
||||
(column.dataIndex === "unitPrice" && config.showUnitPrice) ||
|
||||
(column.dataIndex === "amount" && config.showAmount) ||
|
||||
(column.dataIndex === "unitWeight" && config.showUnitWeight) ||
|
||||
(column.dataIndex === "weight" && config.showWeight)
|
||||
) {
|
||||
return (
|
||||
<div
|
||||
key={"title" + index}
|
||||
className="flex items-end justify-center"
|
||||
>
|
||||
{column.title}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <></>;
|
||||
})}
|
||||
</View>
|
||||
<View className={"table-border"}>
|
||||
{config.data?.map((item: any, index: number) => (
|
||||
<View
|
||||
key={index}
|
||||
className={classNames(`grid w-full gap-0 text-base`, {
|
||||
"grid-cols-1": visibleColumnCount === 1,
|
||||
"grid-cols-2": visibleColumnCount === 2,
|
||||
"grid-cols-3": visibleColumnCount === 3,
|
||||
"grid-cols-4": visibleColumnCount === 4,
|
||||
"grid-cols-5": visibleColumnCount === 5,
|
||||
"grid-cols-6": visibleColumnCount === 6,
|
||||
"grid-cols-7": visibleColumnCount === 7,
|
||||
"grid-cols-8": visibleColumnCount === 8,
|
||||
"border-t-0": index > 0,
|
||||
})}
|
||||
>
|
||||
<View className={"flex items-end justify-center"}>
|
||||
{item.boxSpecName}
|
||||
</View>
|
||||
|
||||
<View className={"flex items-end justify-center"}>
|
||||
{item.boxType}
|
||||
</View>
|
||||
|
||||
{config.showQuantity && (
|
||||
<View className={"flex items-end justify-center"}>
|
||||
{item.quantity}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{config.showUnitPrice && (
|
||||
<View className={"flex items-end justify-center"}>
|
||||
{item.unitPrice}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{config.showAmount && (
|
||||
<View className={"flex items-end justify-center"}>
|
||||
{item.amount}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{config.showUnitWeight && (
|
||||
<View className={"flex items-end justify-center"}>
|
||||
{item.unitWeight}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{config.showWeight && (
|
||||
<View className={"flex items-end justify-center"}>
|
||||
{item.weight}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
))}
|
||||
|
||||
<View
|
||||
className={classNames(`grid w-full gap-0 text-base`, {
|
||||
"grid-cols-1": visibleColumnCount === 1,
|
||||
"grid-cols-2": visibleColumnCount === 2,
|
||||
"grid-cols-3": visibleColumnCount === 3,
|
||||
"grid-cols-4": visibleColumnCount === 4,
|
||||
"grid-cols-5": visibleColumnCount === 5,
|
||||
"grid-cols-6": visibleColumnCount === 6,
|
||||
"grid-cols-7": visibleColumnCount === 7,
|
||||
"grid-cols-8": visibleColumnCount === 8,
|
||||
})}
|
||||
>
|
||||
<View className={`col-span-2 flex items-end justify-center`}>
|
||||
总件数
|
||||
</View>
|
||||
{config.showQuantity && (
|
||||
<View className={`col-span-1 flex items-end justify-center`}>
|
||||
{config.data?.reduce(
|
||||
(acc: any, cur: any) => acc + Number(cur.quantity),
|
||||
0,
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
{config.showUnitPrice && (
|
||||
<View className={`col-span-1 flex items-end justify-center`}></View>
|
||||
)}
|
||||
{config.showAmount && (
|
||||
<View className={`col-span-1 flex items-end justify-center`}>
|
||||
{config.data?.reduce(
|
||||
(acc: any, cur: any) => acc + Number(cur.amount),
|
||||
0,
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
{config.showUnitWeight && (
|
||||
<View className={`col-span-1 flex items-end justify-center`}></View>
|
||||
)}
|
||||
{config.showWeight && (
|
||||
<View className={`col-span-1 flex items-end justify-center`}>
|
||||
{config.data?.reduce(
|
||||
(acc: any, cur: any) => acc + Number(cur.weight),
|
||||
0,
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
import { View } from "@tarojs/components";
|
||||
|
||||
export default function ShippingInfo(props: { module: any }) {
|
||||
const { module } = props;
|
||||
const { config } = module;
|
||||
|
||||
return (
|
||||
<View
|
||||
key={module.id}
|
||||
className={"preview grid w-full grid-cols-8 gap-0 text-base"}
|
||||
>
|
||||
{config.showShippingFrom && (
|
||||
<>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
发货地:
|
||||
</View>
|
||||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||||
{config.shippingFrom}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
{config.showDate && (
|
||||
<>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
日期:
|
||||
</View>
|
||||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||||
{config.date}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
import { View } from "@tarojs/components";
|
||||
|
||||
export default function TitleInfo(props: { module: any }) {
|
||||
const { module } = props;
|
||||
const { config } = module;
|
||||
|
||||
return (
|
||||
<View
|
||||
key={module.id}
|
||||
className={"preview grid w-full grid-cols-8 gap-0 text-2xl font-bold"}
|
||||
>
|
||||
<View className="col-span-8 flex items-end justify-center">
|
||||
{config.title}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
import { View } from "@tarojs/components";
|
||||
|
||||
export default function TotalAmount(props: { module: any }) {
|
||||
const { module } = props;
|
||||
const { config } = module;
|
||||
|
||||
return (
|
||||
<View
|
||||
key={module.id}
|
||||
className={"preview grid w-full grid-cols-8 gap-0 text-base"}
|
||||
>
|
||||
{config.showTotalAmount && (
|
||||
<>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
{config.sumTitle || "合计金额"}:
|
||||
</View>
|
||||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||||
{config.amount}
|
||||
</View>
|
||||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||||
元
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
{config.showFarmer && (
|
||||
<>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
瓜农:
|
||||
</View>
|
||||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||||
{config.farmer}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
import { View } from "@tarojs/components";
|
||||
|
||||
export default function VehicleInfo(props: { module: any }) {
|
||||
const { module } = props;
|
||||
const { config } = module;
|
||||
|
||||
return (
|
||||
<View
|
||||
key={module.id}
|
||||
className={"preview grid w-full grid-cols-8 gap-0 text-base"}
|
||||
>
|
||||
{config.showDriverPhone && (
|
||||
<>
|
||||
<View className="col-span-2 flex items-end justify-center">
|
||||
司机号码:
|
||||
</View>
|
||||
<View className="col-span-6 flex items-end justify-center border-b border-black">
|
||||
{config.driverPhone}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
{config.showLicensePlate && (
|
||||
<>
|
||||
<View className="col-span-2 flex items-end justify-center">
|
||||
车牌:
|
||||
</View>
|
||||
<View className="col-span-6 flex items-end justify-center border-b border-black">
|
||||
{config.licensePlate}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
{config.showEstimatedArrivalTime && (
|
||||
<>
|
||||
<View className="col-span-2 flex items-end justify-center">
|
||||
预计到仓时间:
|
||||
</View>
|
||||
<View className="col-span-6 flex items-end justify-center border-b border-black">
|
||||
{config.estimatedArrivalTime}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
{config.showRemarks && (
|
||||
<>
|
||||
<View className="col-span-2 flex items-end justify-center">
|
||||
备注:
|
||||
</View>
|
||||
<View className="col-span-6 flex items-end justify-center border-b border-black">
|
||||
{config.remarks}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
{config.showFreightDebt && (
|
||||
<>
|
||||
<View className="col-span-2 flex items-end justify-center">
|
||||
{config.freightDebtTitle || "运费欠"}:
|
||||
</View>
|
||||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||||
{config.freightDebt}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
{config.showStrawMatDebt && (
|
||||
<>
|
||||
<View className="col-span-2 flex items-end justify-center">
|
||||
草帘欠:
|
||||
</View>
|
||||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||||
{config.strawMatDebt}
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,119 @@
|
||||
import { View } from "@tarojs/components";
|
||||
|
||||
export default function WeightInfo(props: { module: any }) {
|
||||
const { module } = props;
|
||||
const { config } = module;
|
||||
return (
|
||||
<>
|
||||
{config.data?.map((item: any, index: number) => {
|
||||
return (
|
||||
<View
|
||||
key={"weightInfo" + index}
|
||||
className={"preview grid w-full grid-cols-2 gap-0 text-base"}
|
||||
>
|
||||
{config.showNetWeight && (
|
||||
<View className={"col-span-1 grid grid-cols-4"}>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
净重:
|
||||
</View>
|
||||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||||
{item.netWeight}
|
||||
</View>
|
||||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||||
{config.netWeightUnit === "1" ? "斤" : "公斤"}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{config.showBoxWeight && (
|
||||
<View className={"col-span-1 grid grid-cols-4"}>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
箱重:
|
||||
</View>
|
||||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||||
{item.boxWeight}
|
||||
</View>
|
||||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||||
{config.boxWeightUnit === "1" ? "斤" : "公斤"}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{config.showGrossWeight && (
|
||||
<View className={"col-span-1 grid grid-cols-4"}>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
毛重:
|
||||
</View>
|
||||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||||
{item.grossWeight}
|
||||
</View>
|
||||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||||
{config.grossWeightUnit === "1" ? "斤" : "公斤"}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{config.showUnitPrice && (
|
||||
<View className={"col-span-1 grid grid-cols-4"}>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
单价:
|
||||
</View>
|
||||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||||
{item.unitPrice}
|
||||
</View>
|
||||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||||
{config.unitPriceUnit === "1" ? "元/斤" : "元/公斤"}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{config.showAmount && (
|
||||
<View className={"col-span-1 grid grid-cols-4"}>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
金额:
|
||||
</View>
|
||||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||||
{item.totalAmount}
|
||||
</View>
|
||||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||||
元
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{config.showGrade && (
|
||||
<View className={"col-span-1 grid grid-cols-4"}>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
品级:
|
||||
</View>
|
||||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||||
{item.watermelonGrade}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
<View className={"preview grid w-full grid-cols-2 gap-0 text-base"}>
|
||||
{config.showAccountCompany && (
|
||||
<View className={"col-span-1 grid grid-cols-4"}>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
入账公司:
|
||||
</View>
|
||||
<View className="col-span-3 flex items-end justify-center border-b border-black">
|
||||
{config.accountCompany}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
{config.showSumAmount && (
|
||||
<View className={"col-span-1 grid grid-cols-4"}>
|
||||
<View className="col-span-1 flex items-end justify-center">
|
||||
总计:
|
||||
</View>
|
||||
<View className="col-span-2 flex items-end justify-center border-b border-black">
|
||||
{config.sumAmount}
|
||||
</View>
|
||||
<View className="col-span-1 flex items-end justify-center border-b border-black">
|
||||
元
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
export {default as DealerInfo} from './DealerInfo'
|
||||
export {default as WeightInfo} from './WeightInfo'
|
||||
export {default as TitleInfo} from './TitleInfo'
|
||||
export {default as ShippingInfo} from './ShippingInfo'
|
||||
export {default as PackingSpec} from './PackingSpec'
|
||||
export {default as VehicleInfo} from './VehicleInfo'
|
||||
export {default as OtherFees} from './OtherFees'
|
||||
export {default as TotalAmount} from './TotalAmount'
|
||||
export {default as OtherInfo} from './OtherInfo'
|
||||
@ -3,6 +3,9 @@ import classNames from "classnames";
|
||||
import React from "react";
|
||||
|
||||
export type IconNames =
|
||||
| "eye"
|
||||
| "eye-slash"
|
||||
| "phone-flip"
|
||||
| "address-book"
|
||||
| "pen-to-square"
|
||||
| "location-dot"
|
||||
|
||||
@ -5,3 +5,4 @@ export * from "./purchase";
|
||||
export * from "./dealer";
|
||||
export * from "./supplier";
|
||||
export * from "./company";
|
||||
export * from "./delivery";
|
||||
|
||||
@ -36,3 +36,8 @@ export { default as CostDifferenceSection } from "./section/CostDifferenceSectio
|
||||
export { default as MaterialCostSection } from "./section/MaterialCostSection";
|
||||
export { default as ProductionAdvanceSection } from "./section/ProductionAdvanceSection";
|
||||
export { default as WorkerAdvanceSection } from "./section/WorkerAdvanceSection";
|
||||
|
||||
export { default as PurchaseStep1Form } from "./document/Step1Form";
|
||||
export type { Step1FormRef as PurchaseStep1FormRef } from "./document/Step1Form";
|
||||
export { default as PurchaseStep2Preview } from "./document/Step2Preview";
|
||||
export { default as PurchaseStep3Success } from "./document/Step3Success";
|
||||
|
||||
@ -553,15 +553,7 @@ export default forwardRef<OrderVehicleRef, IOrderVehicleProps>(
|
||||
if (dealerVO) {
|
||||
setOrderDealer({
|
||||
...orderDealer,
|
||||
dealerId: dealerVO.dealerId,
|
||||
shortName: dealerVO?.shortName!,
|
||||
dealerType: dealerVO.dealerType!,
|
||||
enableShare: dealerVO.enableShare,
|
||||
shareRatio: dealerVO.shareRatio,
|
||||
freightCostFlag: dealerVO.freightCostFlag,
|
||||
strawMatCostFlag: dealerVO.strawMatCostFlag,
|
||||
includePackingFlag: dealerVO.includePackingFlag,
|
||||
documentTypes: dealerVO.documentTypes,
|
||||
...dealerVO,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -5,34 +5,31 @@ import { validatePrice } from "@/utils/format";
|
||||
import { PurchaseOrderCalculator } from "@/utils/PurchaseOrderCalculator";
|
||||
|
||||
export default function CostDifferenceSection(props: {
|
||||
dealerVO: BusinessAPI.DealerVO;
|
||||
purchaseOrderVO: BusinessAPI.PurchaseOrderVO;
|
||||
onChange?: (purchaseOrderVO: BusinessAPI.PurchaseOrderVO) => void;
|
||||
readOnly?: boolean;
|
||||
}) {
|
||||
const { purchaseOrderVO, onChange, readOnly } = props;
|
||||
const orderDealer = purchaseOrderVO.orderDealer;
|
||||
const calculator = new PurchaseOrderCalculator(purchaseOrderVO);
|
||||
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
// 主状态,用于页面显示
|
||||
const [costDifference, setCostDifference] = useState<number>(
|
||||
purchaseOrderVO.orderDealer?.costDifference || 0,
|
||||
orderDealer?.costDifference || 0,
|
||||
);
|
||||
|
||||
// 弹窗内的临时状态
|
||||
const [tempCostDifference, setTempCostDifference] = useState<number>(
|
||||
purchaseOrderVO.orderDealer?.costDifference || 0,
|
||||
orderDealer?.costDifference || 0,
|
||||
);
|
||||
|
||||
const profitSharing =
|
||||
calculator.getDefaultNetProfit() ||
|
||||
purchaseOrderVO.orderDealer?.profitSharing ||
|
||||
0;
|
||||
calculator.getDefaultNetProfit() || orderDealer?.profitSharing || 0;
|
||||
|
||||
// 当dealerVO变化时,自动计算分成
|
||||
useEffect(() => {
|
||||
if (!purchaseOrderVO.orderDealer?.costDifference) {
|
||||
if (!orderDealer?.costDifference) {
|
||||
const defaultCostDifference = calculator.getCostDifference();
|
||||
setCostDifference(defaultCostDifference);
|
||||
setTempCostDifference(defaultCostDifference);
|
||||
@ -40,7 +37,7 @@ export default function CostDifferenceSection(props: {
|
||||
onChange?.({
|
||||
...purchaseOrderVO,
|
||||
orderDealer: {
|
||||
...purchaseOrderVO.orderDealer,
|
||||
...orderDealer,
|
||||
costDifference: defaultCostDifference,
|
||||
profitSharing: profitSharing,
|
||||
},
|
||||
@ -56,7 +53,7 @@ export default function CostDifferenceSection(props: {
|
||||
onChange?.({
|
||||
...purchaseOrderVO,
|
||||
orderDealer: {
|
||||
...purchaseOrderVO.orderDealer,
|
||||
...orderDealer,
|
||||
costDifference: tempCostDifference,
|
||||
profitSharing: profitSharing,
|
||||
},
|
||||
|
||||
@ -33,15 +33,7 @@ export default function (props: {
|
||||
if (readOnly) return;
|
||||
|
||||
const newOrderDealer: BusinessAPI.OrderDealer = {
|
||||
dealerId: dealerVO.dealerId,
|
||||
shortName: dealerVO?.shortName!,
|
||||
dealerType: dealerVO.dealerType!,
|
||||
enableShare: dealerVO.enableShare,
|
||||
shareRatio: dealerVO.shareRatio,
|
||||
freightCostFlag: dealerVO.freightCostFlag,
|
||||
strawMatCostFlag: dealerVO.strawMatCostFlag,
|
||||
includePackingFlag: dealerVO.includePackingFlag,
|
||||
documentTypes: dealerVO.documentTypes,
|
||||
...dealerVO,
|
||||
};
|
||||
|
||||
setOrderDealer(newOrderDealer);
|
||||
|
||||
@ -5,30 +5,30 @@ import { validatePrice } from "@/utils/format";
|
||||
import { PurchaseOrderCalculator } from "@/utils/PurchaseOrderCalculator";
|
||||
|
||||
export default function TaxProvisionSection(props: {
|
||||
dealerVO: BusinessAPI.DealerVO;
|
||||
purchaseOrderVO: BusinessAPI.PurchaseOrderVO;
|
||||
onChange?: (purchaseOrderVO: BusinessAPI.PurchaseOrderVO) => void;
|
||||
readOnly?: boolean;
|
||||
}) {
|
||||
const { purchaseOrderVO, onChange, readOnly, dealerVO } = props;
|
||||
const { purchaseOrderVO, onChange, readOnly } = props;
|
||||
const orderDealer = purchaseOrderVO.orderDealer;
|
||||
|
||||
const calculator = new PurchaseOrderCalculator(purchaseOrderVO);
|
||||
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
const [taxProvision, setTaxProvision] = useState<number>(
|
||||
purchaseOrderVO.orderDealer?.taxProvision || 0,
|
||||
orderDealer?.taxProvision || 0,
|
||||
);
|
||||
|
||||
// 当dealerVO变化时,自动计算计提税金
|
||||
useEffect(() => {
|
||||
if (!purchaseOrderVO.orderDealer?.taxProvision) {
|
||||
if (!orderDealer?.taxProvision) {
|
||||
const defaultValue = calculator.getDefaultTaxProvision();
|
||||
setTaxProvision(defaultValue);
|
||||
// 更新父组件的状态
|
||||
onChange?.({
|
||||
...purchaseOrderVO,
|
||||
orderDealer: {
|
||||
...purchaseOrderVO.orderDealer,
|
||||
...orderDealer,
|
||||
taxProvision: defaultValue,
|
||||
},
|
||||
});
|
||||
@ -48,7 +48,7 @@ export default function TaxProvisionSection(props: {
|
||||
onChange?.({
|
||||
...purchaseOrderVO,
|
||||
orderDealer: {
|
||||
...purchaseOrderVO.orderDealer,
|
||||
...orderDealer,
|
||||
taxProvision: taxProvision,
|
||||
},
|
||||
});
|
||||
@ -97,8 +97,8 @@ export default function TaxProvisionSection(props: {
|
||||
<View className="flex items-center justify-between">
|
||||
<Text className="text-sm text-gray-500">计提税率</Text>
|
||||
<Text className="text-sm font-medium">
|
||||
{dealerVO.accrualTaxRatio
|
||||
? dealerVO.accrualTaxRatio + "%"
|
||||
{orderDealer.accrualTaxRatio
|
||||
? orderDealer.accrualTaxRatio + "%"
|
||||
: "未设置"}
|
||||
</Text>
|
||||
</View>
|
||||
@ -151,7 +151,7 @@ export default function TaxProvisionSection(props: {
|
||||
</Button>
|
||||
<View className="ml-2 self-center text-xs text-gray-500">
|
||||
默认值: (市场报价 - 税费补贴) ×{" "}
|
||||
{dealerVO.accrualTaxRatio || "未设置"}%
|
||||
{orderDealer.accrualTaxRatio || "未设置"}%
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@ -5,30 +5,29 @@ import { validatePrice } from "@/utils/format";
|
||||
import { PurchaseOrderCalculator } from "@/utils/PurchaseOrderCalculator";
|
||||
|
||||
export default function TaxSubsidySection(props: {
|
||||
dealerVO: BusinessAPI.DealerVO;
|
||||
purchaseOrderVO: BusinessAPI.PurchaseOrderVO;
|
||||
onChange?: (purchaseOrderVO: BusinessAPI.PurchaseOrderVO) => void;
|
||||
readOnly?: boolean;
|
||||
}) {
|
||||
const { purchaseOrderVO, onChange, readOnly, dealerVO } = props;
|
||||
const { purchaseOrderVO, onChange, readOnly } = props;
|
||||
const orderDealer = purchaseOrderVO.orderDealer;
|
||||
const calculator = new PurchaseOrderCalculator(purchaseOrderVO);
|
||||
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
const [taxSubsidy, setTaxSubsidy] = useState<number>(
|
||||
purchaseOrderVO.orderDealer?.taxSubsidy || 0,
|
||||
orderDealer?.taxSubsidy || 0,
|
||||
);
|
||||
|
||||
// 当dealerVO变化时,自动计算税费补贴
|
||||
useEffect(() => {
|
||||
if (!purchaseOrderVO.orderDealer?.taxSubsidy) {
|
||||
if (!orderDealer?.taxSubsidy) {
|
||||
const defaultValue = calculator.getDefaultTaxSubsidy();
|
||||
setTaxSubsidy(defaultValue);
|
||||
// 更新父组件的状态
|
||||
onChange?.({
|
||||
...purchaseOrderVO,
|
||||
orderDealer: {
|
||||
...purchaseOrderVO.orderDealer,
|
||||
...orderDealer,
|
||||
taxSubsidy: defaultValue,
|
||||
},
|
||||
});
|
||||
@ -46,7 +45,7 @@ export default function TaxSubsidySection(props: {
|
||||
onChange?.({
|
||||
...purchaseOrderVO,
|
||||
orderDealer: {
|
||||
...purchaseOrderVO.orderDealer,
|
||||
...orderDealer,
|
||||
taxSubsidy,
|
||||
},
|
||||
});
|
||||
@ -95,8 +94,8 @@ export default function TaxSubsidySection(props: {
|
||||
<View className="flex items-center justify-between">
|
||||
<Text className="text-sm text-gray-500">返点百分比</Text>
|
||||
<Text className="text-sm font-medium">
|
||||
{dealerVO.companyRebateRatio
|
||||
? dealerVO.companyRebateRatio + "%"
|
||||
{orderDealer.companyRebateRatio
|
||||
? orderDealer.companyRebateRatio + "%"
|
||||
: "未设置"}
|
||||
</Text>
|
||||
</View>
|
||||
@ -148,7 +147,7 @@ export default function TaxSubsidySection(props: {
|
||||
按公式填入默认值
|
||||
</Button>
|
||||
<View className="ml-2 self-center text-xs text-gray-500">
|
||||
默认值: 市场报价 × {dealerVO.companyRebateRatio || "未设置"}%
|
||||
默认值: 市场报价 × {orderDealer.companyRebateRatio || "未设置"}%
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@ -3,19 +3,18 @@ import { Icon } from "@/components";
|
||||
import { ScrollView, View } from "@tarojs/components";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { business } from "@/services";
|
||||
import { SupplierVO } from "@/types/typings";
|
||||
|
||||
interface ISupplierPickerProps {
|
||||
trigger?: React.ReactNode;
|
||||
onFinish: (supplierVO: SupplierVO) => void;
|
||||
onFinish: (supplierVO: BusinessAPI.SupplierVO) => void;
|
||||
}
|
||||
|
||||
export default function SupplierPicker(props: ISupplierPickerProps) {
|
||||
const { onFinish, trigger } = props;
|
||||
|
||||
const [supplierVO, setSupplierVO] = useState<SupplierVO>();
|
||||
const [supplierVO, setSupplierVO] = useState<BusinessAPI.SupplierVO>();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [supplierList, setSupplierList] = useState<SupplierVO[]>();
|
||||
const [supplierList, setSupplierList] = useState<BusinessAPI.SupplierVO[]>();
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
@ -28,7 +27,7 @@ export default function SupplierPicker(props: ISupplierPickerProps) {
|
||||
const { data } = await business.supplier.listSupplier({
|
||||
supplierListQry: {
|
||||
name: value || undefined,
|
||||
status: true
|
||||
status: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -57,7 +56,7 @@ export default function SupplierPicker(props: ISupplierPickerProps) {
|
||||
position="bottom"
|
||||
onClose={async () => {
|
||||
if (visible) {
|
||||
setSupplierVO(undefined)
|
||||
setSupplierVO(undefined);
|
||||
setSearchText("");
|
||||
setVisible(false);
|
||||
} else if (supplierVO) {
|
||||
@ -88,7 +87,7 @@ export default function SupplierPicker(props: ISupplierPickerProps) {
|
||||
key={item.supplierId}
|
||||
onClick={async () => {
|
||||
setSupplierVO(item);
|
||||
setSearchText("")
|
||||
setSearchText("");
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
// App 相关常量
|
||||
export const APP_VERSION = "v0.0.12";
|
||||
export const APP_VERSION = "v0.0.19";
|
||||
|
||||
@ -126,6 +126,15 @@ const quickActionMap = {
|
||||
icon: "file-invoice",
|
||||
iconColor: "var(--color-orange-600)",
|
||||
bgColorClass: "bg-orange-100",
|
||||
path: "/pages/supplier/purchase/invoice",
|
||||
},
|
||||
{
|
||||
id: "supplierManage",
|
||||
title: "瓜农管理",
|
||||
icon: "clipboard-list",
|
||||
iconColor: "var(--color-green-600)",
|
||||
bgColorClass: "bg-green-100",
|
||||
path: "/pages/supplier/list",
|
||||
},
|
||||
],
|
||||
"market-buyer": [
|
||||
@ -145,13 +154,6 @@ const quickActionMap = {
|
||||
bgColorClass: "bg-green-100",
|
||||
path: "/pages/purchase/purchaser/history",
|
||||
},
|
||||
{
|
||||
id: "invoiceUpload",
|
||||
title: "上传发票",
|
||||
icon: "file-invoice",
|
||||
iconColor: "var(--color-orange-600)",
|
||||
bgColorClass: "bg-orange-100",
|
||||
},
|
||||
],
|
||||
reviewer: [
|
||||
{
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 5042354 */
|
||||
src: url('//at.alicdn.com/t/c/font_5042354_wqti51yo9xk.woff2?t=1762227792781') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_5042354_wqti51yo9xk.woff?t=1762227792781') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_5042354_wqti51yo9xk.ttf?t=1762227792781') format('truetype');
|
||||
src: url('//at.alicdn.com/t/c/font_5042354_hkkkrqw0kin.woff2?t=1763456511295') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_5042354_hkkkrqw0kin.woff?t=1763456511295') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_5042354_hkkkrqw0kin.ttf?t=1763456511295') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -13,6 +13,18 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-phone-flip:before {
|
||||
content: "\e624";
|
||||
}
|
||||
|
||||
.icon-eye:before {
|
||||
content: "\e62f";
|
||||
}
|
||||
|
||||
.icon-eye-slash:before {
|
||||
content: "\e62e";
|
||||
}
|
||||
|
||||
.icon-address-book:before {
|
||||
content: "\e623";
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -23,10 +23,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
const [state, setState] = useState<BusinessAPI.ShipOrderPageQry["state"]>();
|
||||
const [dealerVO, setDealerVO] = useState<BusinessAPI.DealerVO>();
|
||||
|
||||
const [canGenerateDocuments, setCanGenerateDocuments] = useState({
|
||||
shipDocument: false,
|
||||
purchaseDocument: false,
|
||||
});
|
||||
const [deliveryTemplate, setDeliveryTemplate] =
|
||||
useState<BusinessAPI.DealerVO["deliveryTemplate"]>();
|
||||
|
||||
@ -37,7 +33,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
useState<BusinessAPI.ShipOrderVO | null>(null);
|
||||
|
||||
// 生成发货单据
|
||||
const generateShipDocument = async () => {
|
||||
const generateDocument = async () => {
|
||||
if (!currentShipOrder?.shipOrderId) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
@ -66,36 +62,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
}
|
||||
};
|
||||
|
||||
// 生成采购底单单据
|
||||
const generatePurchaseDocument = () => {
|
||||
if (!currentShipOrder?.shipOrderId) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "未找到关联的发货单",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 跳转到发货单据生成页面
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/delivery/document/purchase", {
|
||||
shipOrderId: currentShipOrder.shipOrderId,
|
||||
}),
|
||||
success: () => {
|
||||
setPopupVisible(false);
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "跳转发货单据页面失败",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const actionRef = useRef<ActionType>();
|
||||
const toolbar: ToolBar = {
|
||||
search: {
|
||||
@ -176,37 +142,23 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
</View>
|
||||
|
||||
<View className="flex flex-col gap-3">
|
||||
{canGenerateDocuments.shipDocument && (
|
||||
<>
|
||||
{!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>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!canGenerateDocuments.purchaseDocument &&
|
||||
!canGenerateDocuments.shipDocument && (
|
||||
<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>
|
||||
{!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>
|
||||
)}
|
||||
@ -214,44 +166,27 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
|
||||
<View className={"flex w-full flex-col bg-white"}>
|
||||
<View className={"flex flex-row gap-2 p-3"}>
|
||||
{canGenerateDocuments.purchaseDocument && currentShipOrder && (
|
||||
<View className={"flex-1"}>
|
||||
<Button
|
||||
type="default"
|
||||
size={"xlarge"}
|
||||
block
|
||||
onClick={generatePurchaseDocument}
|
||||
>
|
||||
生成采购底单单据
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
{canGenerateDocuments.shipDocument && currentShipOrder && (
|
||||
<View className={"flex-1"}>
|
||||
<Button
|
||||
type="primary"
|
||||
size={"xlarge"}
|
||||
disabled={!deliveryTemplate}
|
||||
block
|
||||
onClick={generateShipDocument}
|
||||
>
|
||||
生成发货单据
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
{!canGenerateDocuments.purchaseDocument &&
|
||||
!canGenerateDocuments.shipDocument && (
|
||||
<View className={"flex-1"}>
|
||||
<Button
|
||||
type="default"
|
||||
size={"xlarge"}
|
||||
block
|
||||
onClick={() => setPopupVisible(false)}
|
||||
>
|
||||
关闭
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
<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>
|
||||
@ -300,36 +235,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
return {};
|
||||
});
|
||||
|
||||
// 生成发货单据
|
||||
const generateDocument = async (shipOrderVO: BusinessAPI.ShipOrderVO) => {
|
||||
setCurrentShipOrder(shipOrderVO);
|
||||
|
||||
const { data: dealerData } = await business.dealer.showDealer({
|
||||
dealerShowQry: {
|
||||
dealerId: shipOrderVO.dealerId,
|
||||
},
|
||||
});
|
||||
|
||||
if (dealerData.success) {
|
||||
const deliveryTemplate = dealerData.data?.deliveryTemplate;
|
||||
setDeliveryTemplate(deliveryTemplate);
|
||||
const documentTypes = dealerData.data?.documentTypes;
|
||||
if (documentTypes) {
|
||||
setCanGenerateDocuments({
|
||||
shipDocument: documentTypes.includes("delivery"),
|
||||
purchaseDocument: documentTypes.includes("purchase"),
|
||||
});
|
||||
} else {
|
||||
setCanGenerateDocuments({
|
||||
shipDocument: false,
|
||||
purchaseDocument: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setPopupVisible(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<PageList<BusinessAPI.ShipOrderVO, BusinessAPI.ShipOrderPageQry>
|
||||
rowId={"shipOrderId"}
|
||||
@ -410,16 +315,47 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-row justify-end gap-2"}>
|
||||
<Button
|
||||
type={"primary"}
|
||||
size={"small"}
|
||||
onClick={async (e) => {
|
||||
await generateDocument(shipOrderVO);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
生成单据
|
||||
</Button>
|
||||
{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>
|
||||
|
||||
@ -170,7 +170,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
<Image
|
||||
src={employeeVO?.avatar}
|
||||
mode={"aspectFill"}
|
||||
className={"rounded-full"}
|
||||
className={"h-full w-full overflow-hidden rounded-full"}
|
||||
/>
|
||||
</View>
|
||||
) : (
|
||||
|
||||
@ -13,10 +13,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
|
||||
const [purchaseOrder, setPurchaseOrder] =
|
||||
useState<BusinessAPI.PurchaseOrderVO>();
|
||||
const [canGenerateDocuments, setCanGenerateDocuments] = useState({
|
||||
shipDocument: false,
|
||||
purchaseDocument: false,
|
||||
});
|
||||
const [shipOrder, setShipOrder] = useState<BusinessAPI.ShipOrderVO>();
|
||||
const [deliveryTemplate, setDeliveryTemplate] =
|
||||
useState<BusinessAPI.DealerVO["deliveryTemplate"]>();
|
||||
@ -55,14 +51,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
},
|
||||
});
|
||||
|
||||
if (dealerData.success && dealerData.data?.documentTypes) {
|
||||
const documentTypes = dealerData.data.documentTypes;
|
||||
setDeliveryTemplate(dealerData.data.deliveryTemplate);
|
||||
setCanGenerateDocuments({
|
||||
shipDocument: documentTypes.includes("delivery"),
|
||||
purchaseDocument: documentTypes.includes("purchase"),
|
||||
});
|
||||
}
|
||||
setDeliveryTemplate(dealerData.data?.deliveryTemplate);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@ -83,16 +72,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
}, [orderId]);
|
||||
|
||||
// 生成发货单据
|
||||
const generateShipDocument = async () => {
|
||||
if (!canGenerateDocuments.shipDocument) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "当前经销商不支持生成发货单据",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const generateDocument = async () => {
|
||||
if (!shipOrder?.shipOrderId) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
@ -118,42 +98,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
}
|
||||
};
|
||||
|
||||
// 生成采购底单单据
|
||||
const generatePurchaseDocument = () => {
|
||||
if (!canGenerateDocuments.purchaseDocument) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "当前经销商不支持生成采购底单单据",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shipOrder?.shipOrderId) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "未找到关联的发货单",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 跳转到发货单据生成页面
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/delivery/document/purchase", {
|
||||
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">
|
||||
@ -215,31 +159,19 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
</View>
|
||||
|
||||
<View className="flex flex-col gap-3">
|
||||
{canGenerateDocuments.shipDocument &&
|
||||
(deliveryTemplate ? (
|
||||
<Button
|
||||
type="primary"
|
||||
size={"xlarge"}
|
||||
block
|
||||
onClick={generateShipDocument}
|
||||
>
|
||||
生成发货单据
|
||||
</Button>
|
||||
) : (
|
||||
<View className="mt-2.5 text-center text-sm text-red-500">
|
||||
未找到关联的发货单模板,请联系管理员
|
||||
</View>
|
||||
))}
|
||||
|
||||
{canGenerateDocuments.purchaseDocument && shipOrder && (
|
||||
{deliveryTemplate ? (
|
||||
<Button
|
||||
type="default"
|
||||
type="primary"
|
||||
size={"xlarge"}
|
||||
block
|
||||
onClick={generatePurchaseDocument}
|
||||
onClick={generateDocument}
|
||||
>
|
||||
生成采购底单单据
|
||||
生成发货单据
|
||||
</Button>
|
||||
) : (
|
||||
<View className="mt-2.5 text-center text-sm text-red-500">
|
||||
未找到关联的发货单模板,请联系管理员
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@ -5,7 +5,16 @@ import { business } from "@/services";
|
||||
import { useEffect, useState } from "react";
|
||||
import { View } from "@tarojs/components";
|
||||
import purchaseOrder from "@/constant/purchaseOrder";
|
||||
import { ActionSheet, Button, Dialog, Input, Popup, SafeArea, TextArea, Toast } from "@nutui/nutui-react-taro";
|
||||
import {
|
||||
ActionSheet,
|
||||
Button,
|
||||
Dialog,
|
||||
Input,
|
||||
Popup,
|
||||
SafeArea,
|
||||
TextArea,
|
||||
Toast,
|
||||
} from "@nutui/nutui-react-taro";
|
||||
import {
|
||||
BasicInfoSection,
|
||||
CompanyInfoSection,
|
||||
@ -22,7 +31,7 @@ import {
|
||||
State,
|
||||
TaxProvisionSection,
|
||||
TaxSubsidySection,
|
||||
WorkerAdvanceSection
|
||||
WorkerAdvanceSection,
|
||||
} from "@/components";
|
||||
import buildUrl from "@/utils/buildUrl";
|
||||
import { PurchaseOrderCalculator } from "@/utils/PurchaseOrderCalculator";
|
||||
@ -116,7 +125,7 @@ const sections = {
|
||||
};
|
||||
|
||||
export default hocAuth(function Page(props: CommonComponent) {
|
||||
const { router, isInitialized, setIsInitialized, role } = props;
|
||||
const { router, isInitialized, setIsInitialized, role, setLoading } = props;
|
||||
|
||||
const orderId = router.params
|
||||
.orderId as BusinessAPI.PurchaseOrderVO["orderId"];
|
||||
@ -216,17 +225,20 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
// 控制更多操作的ActionSheet显示状态
|
||||
const [moreActionVisible, setMoreActionVisible] = useState(false);
|
||||
|
||||
const [dealerVO, setDealerVO] = useState<BusinessAPI.DealerVO>();
|
||||
const [dealerRebateCustomerVOList, setDealerRebateCustomerVOList] =
|
||||
useState<BusinessAPI.DealerRebateCustomerVO[]>();
|
||||
|
||||
const initDealer = async (dealerId: BusinessAPI.DealerVO["dealerId"]) => {
|
||||
const { data } = await business.dealer.showDealer({
|
||||
dealerShowQry: {
|
||||
const {
|
||||
data: { data: dealerRebateCustomerVOList },
|
||||
} = await business.dealerRebateCustomer.listDealerRebateCustomer({
|
||||
dealerRebateCustomerListQry: {
|
||||
dealerId: dealerId,
|
||||
status: true,
|
||||
},
|
||||
});
|
||||
|
||||
setDealerVO(data.data);
|
||||
setDealerRebateCustomerVOList(dealerRebateCustomerVOList);
|
||||
};
|
||||
|
||||
// 暂存操作
|
||||
@ -357,8 +369,10 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
|
||||
useEffect(() => {
|
||||
if (orderId && !isInitialized) {
|
||||
setLoading(true);
|
||||
init(orderId).then(() => {
|
||||
setIsInitialized(true);
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
@ -369,7 +383,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
}
|
||||
});
|
||||
|
||||
if (!purchaseOrderVO) {
|
||||
if (!purchaseOrderVO || !dealerRebateCustomerVOList) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -436,16 +450,32 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
{/* 循环渲染各部分内容 */}
|
||||
{Object.keys(sections).map((sectionKey) => {
|
||||
const section = sections[sectionKey];
|
||||
const orderDealer = purchaseOrderVO.orderDealer;
|
||||
|
||||
if (!dealerVO?.enableCompanyRebate && sectionKey === "taxSubsidy") {
|
||||
if (
|
||||
!orderDealer?.enableCompanyRebate &&
|
||||
sectionKey === "taxSubsidy"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!dealerVO?.enableAccrualTax && sectionKey === "taxProvision") {
|
||||
if (
|
||||
!orderDealer?.enableAccrualTax &&
|
||||
sectionKey === "taxProvision"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!dealerVO?.enableShare && sectionKey === "costDifference") {
|
||||
if (!orderDealer?.enableShare && sectionKey === "costDifference") {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 如果没有返点人这个模块,则不渲染
|
||||
if (
|
||||
(!dealerRebateCustomerVOList ||
|
||||
dealerRebateCustomerVOList.length === 0) &&
|
||||
sectionKey === "rebateCalc"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -456,7 +486,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
className={`overflow-x-auto rounded-md rounded-b-lg bg-white p-2.5 shadow-sm`}
|
||||
>
|
||||
<section.component
|
||||
dealerVO={dealerVO}
|
||||
purchaseOrderVO={purchaseOrderVO}
|
||||
onChange={setPurchaseOrderVO}
|
||||
costItemVOList={costItemVOList}
|
||||
|
||||
4
packages/app-client/src/pages/supplier/list.config.ts
Normal file
4
packages/app-client/src/pages/supplier/list.config.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: "瓜农管理",
|
||||
navigationBarBackgroundColor: "#fff",
|
||||
});
|
||||
127
packages/app-client/src/pages/supplier/list.tsx
Normal file
127
packages/app-client/src/pages/supplier/list.tsx
Normal file
@ -0,0 +1,127 @@
|
||||
import { ActionType, PageList, ToolBar } from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import { useRef } from "react";
|
||||
import { business } from "@/services";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
import { Label, Text, View } from "@tarojs/components";
|
||||
import dayjs from "dayjs";
|
||||
import Phone from "../../components/biz/Phone";
|
||||
|
||||
export default hocAuth(function Page(props: CommonComponent) {
|
||||
const { shareOptions } = props;
|
||||
|
||||
const actionRef = useRef<ActionType>();
|
||||
const toolbar: ToolBar = {
|
||||
search: {
|
||||
activeKey: "name",
|
||||
defaultActiveKey: "name",
|
||||
items: [
|
||||
{
|
||||
key: "name",
|
||||
name: "瓜农名称",
|
||||
placeholder: "请输入瓜农名称",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
useShareAppMessage((res) => {
|
||||
console.log("useShareAppMessage1", res, shareOptions);
|
||||
// 如果是按钮触发的转发,使用默认配置
|
||||
if (res.from === "button") {
|
||||
return shareOptions;
|
||||
}
|
||||
// 页面转发使用设置的配置
|
||||
return {};
|
||||
});
|
||||
|
||||
return (
|
||||
<PageList<BusinessAPI.SupplierVO, BusinessAPI.SupplierPageQry>
|
||||
rowId={"supplierId"}
|
||||
itemHeight={182}
|
||||
type={"infinite"}
|
||||
actionRef={actionRef}
|
||||
render={(supplierVO: BusinessAPI.SupplierVO, 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"}
|
||||
>
|
||||
{supplierVO?.name}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</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"}>
|
||||
{dayjs(supplierVO.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>
|
||||
<View
|
||||
className={
|
||||
"flex flex-1 flex-row items-center justify-end gap-1"
|
||||
}
|
||||
>
|
||||
<Phone phone={supplierVO.phone} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-row justify-end gap-2"}></View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
toolbar={toolbar}
|
||||
request={async (params) => {
|
||||
const {
|
||||
data: { data, success, notEmpty },
|
||||
} = await business.supplier.pageSupplier({
|
||||
supplierPageQry: {
|
||||
...params,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
success,
|
||||
hasMore: notEmpty,
|
||||
};
|
||||
}}
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: "上传发票",
|
||||
navigationBarBackgroundColor: "#fff",
|
||||
});
|
||||
358
packages/app-client/src/pages/supplier/purchase/invoice.tsx
Normal file
358
packages/app-client/src/pages/supplier/purchase/invoice.tsx
Normal file
@ -0,0 +1,358 @@
|
||||
import {
|
||||
ActionType,
|
||||
Icon,
|
||||
PageList,
|
||||
SupplierPicker,
|
||||
ToolBar,
|
||||
} from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import { useRef, useState } from "react";
|
||||
import { business } from "@/services";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
import { View } from "@tarojs/components";
|
||||
import dayjs from "dayjs";
|
||||
import {
|
||||
Button,
|
||||
Popup,
|
||||
SafeArea,
|
||||
Toast,
|
||||
Uploader,
|
||||
UploaderFileItem,
|
||||
} from "@nutui/nutui-react-taro";
|
||||
import { uploadFile } from "@/utils/uploader";
|
||||
|
||||
export default hocAuth(function Page(props: CommonComponent) {
|
||||
const { shareOptions } = props;
|
||||
|
||||
const [supplierVO, setSupplierVO] = useState<BusinessAPI.SupplierVO>();
|
||||
const [popupVisible, setPopupVisible] = useState(false);
|
||||
const [selectedOrders, setSelectedOrders] = useState<
|
||||
BusinessAPI.OrderSupplierVO[]
|
||||
>([]);
|
||||
const [contractFiles, setContractFiles] = useState<any[]>([]);
|
||||
const [invoiceFiles, setInvoiceFiles] = useState<any[]>([]);
|
||||
|
||||
// 发票照片
|
||||
const [invoiceImgList, setInvoiceImgList] = useState<UploaderFileItem[]>([]);
|
||||
// 合同照片
|
||||
const [contractImgList, setContractImgList] = useState<UploaderFileItem[]>(
|
||||
[],
|
||||
);
|
||||
|
||||
// 发票照片变更处理函数
|
||||
const handleInvoiceImgChange = (files: UploaderFileItem[]) => {
|
||||
setInvoiceImgList(files);
|
||||
|
||||
// 如果有文件且上传成功,保存URL到supplierVO
|
||||
if (files.length > 0 && files[0].url) {
|
||||
setSupplierVO((prev) => ({
|
||||
...prev!,
|
||||
invoiceImg: [files[0].url!],
|
||||
invoiceUpload: true,
|
||||
}));
|
||||
} else {
|
||||
// 如果没有文件,清空URL
|
||||
setSupplierVO((prev) => ({
|
||||
...prev!,
|
||||
invoiceImg: undefined,
|
||||
invoiceUpload: false,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// 合同照片变更处理函数
|
||||
const handleContractImgChange = (files: UploaderFileItem[]) => {
|
||||
setContractImgList(files);
|
||||
|
||||
// 保存所有文件URL到supplierVO
|
||||
const urls = files.map((file) => file.url).filter((url) => url) as string[];
|
||||
setSupplierVO((prev) => ({
|
||||
...prev!,
|
||||
contractImg: urls,
|
||||
contractUpload: urls.length > 0,
|
||||
}));
|
||||
};
|
||||
|
||||
const actionRef = useRef<ActionType>();
|
||||
const toolbar: ToolBar = {
|
||||
selectRow: {
|
||||
onClick: async (orderSupplierVOList: BusinessAPI.OrderSupplierVO[]) => {
|
||||
console.log("orderSupplierVOList", orderSupplierVOList);
|
||||
// 点击弹出popup
|
||||
setSelectedOrders(orderSupplierVOList);
|
||||
setPopupVisible(true);
|
||||
},
|
||||
},
|
||||
search: {
|
||||
activeKey: "vehicleNo",
|
||||
defaultActiveKey: "vehicleNo",
|
||||
items: [
|
||||
{
|
||||
key: "vehicleNo",
|
||||
name: "车次号",
|
||||
placeholder: "请输入车次号",
|
||||
},
|
||||
{
|
||||
key: "plate",
|
||||
name: "车牌号",
|
||||
placeholder: "请输入车牌号",
|
||||
},
|
||||
],
|
||||
},
|
||||
render: () => (
|
||||
<>
|
||||
{/* Popup 弹窗 */}
|
||||
<Popup
|
||||
visible={popupVisible}
|
||||
position="bottom"
|
||||
onClose={() => setPopupVisible(false)}
|
||||
onOverlayClick={() => setPopupVisible(false)}
|
||||
lockScroll
|
||||
round
|
||||
>
|
||||
<View className="border-t border-green-100 bg-green-50 p-3">
|
||||
{/* 统计信息 */}
|
||||
<View className="mb-2 flex items-center justify-between">
|
||||
<View className="text-sm font-medium text-gray-800">
|
||||
已选{" "}
|
||||
<View className="text-primary inline">
|
||||
{selectedOrders.length}
|
||||
</View>{" "}
|
||||
车次
|
||||
</View>
|
||||
<View className="text-sm font-medium text-gray-800">
|
||||
总重量:
|
||||
<View className="text-primary inline">{totalWeight}</View> 斤
|
||||
</View>
|
||||
<View className="text-sm font-medium text-gray-800">
|
||||
总金额:{" "}
|
||||
<View className="text-primary inline">
|
||||
{totalAmount.toFixed(2)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 上传发票 */}
|
||||
<View className="mb-2 flex items-center justify-between">
|
||||
<View className="flex-1">
|
||||
<Uploader
|
||||
className={"w-full"}
|
||||
value={invoiceImgList}
|
||||
onChange={handleInvoiceImgChange}
|
||||
sourceType={["album", "camera"]}
|
||||
uploadIcon={<Icon name={"camera"} size={36} />}
|
||||
uploadLabel={
|
||||
<View className={"flex flex-col items-center"}>
|
||||
<View className="text-sm">拍照上传发票</View>
|
||||
<View className="mt-1 text-xs text-gray-400">
|
||||
仅支持单张照片
|
||||
</View>
|
||||
</View>
|
||||
}
|
||||
maxCount={1}
|
||||
//@ts-ignore
|
||||
upload={uploadFile}
|
||||
multiple
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 上传合同 */}
|
||||
<View className="mb-2 flex items-center justify-between">
|
||||
<View className="flex-1">
|
||||
<Uploader
|
||||
className={"w-full"}
|
||||
value={contractImgList}
|
||||
onChange={handleContractImgChange}
|
||||
sourceType={["album", "camera"]}
|
||||
uploadIcon={<Icon name={"camera"} size={36} />}
|
||||
uploadLabel={
|
||||
<View className={"flex flex-col items-center"}>
|
||||
<View className="text-sm">拍照上传合同</View>
|
||||
<View className="mt-1 text-xs text-gray-400">
|
||||
支持多张照片
|
||||
</View>
|
||||
</View>
|
||||
}
|
||||
maxCount={9}
|
||||
//@ts-ignore
|
||||
upload={uploadFile}
|
||||
multiple
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className={"flex flex-1 flex-row gap-2.5"}>
|
||||
<View className={"flex-1"}>
|
||||
<Button
|
||||
size={"xlarge"}
|
||||
block
|
||||
type="default"
|
||||
onClick={() => setPopupVisible(false)}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
</View>
|
||||
{/* 提交按钮 */}
|
||||
<View className={"flex-1"}>
|
||||
<Button
|
||||
size={"xlarge"}
|
||||
block
|
||||
type="primary"
|
||||
disabled={
|
||||
contractFiles.length === 0 || invoiceFiles.length === 0
|
||||
}
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
提交申请
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
<SafeArea position={"bottom"} />
|
||||
</View>
|
||||
</Popup>
|
||||
<View className={"flex flex-row gap-2.5"}>
|
||||
<SupplierPicker
|
||||
onFinish={(supplierVO) => {
|
||||
setSupplierVO(supplierVO);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
trigger={
|
||||
<View
|
||||
className={`"border-2 border-primary flex h-6 items-center rounded-md px-2.5`}
|
||||
>
|
||||
<View className={"text-primary text-xs"}>
|
||||
{supplierVO?.name || "瓜农"}
|
||||
</View>
|
||||
{supplierVO?.name ? (
|
||||
<Icon
|
||||
name={"circle-xmark"}
|
||||
size={16}
|
||||
onClick={(event) => {
|
||||
setSupplierVO(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 {};
|
||||
});
|
||||
|
||||
// 计算选中车次的总重量和总金额
|
||||
const calculateTotals = () => {
|
||||
return selectedOrders.reduce(
|
||||
(totals, order) => {
|
||||
totals.totalWeight += order.netWeight || 0;
|
||||
totals.totalAmount += order.invoiceAmount || 0;
|
||||
return totals;
|
||||
},
|
||||
{ totalWeight: 0, totalAmount: 0 },
|
||||
);
|
||||
};
|
||||
|
||||
const { totalWeight, totalAmount } = calculateTotals();
|
||||
|
||||
// 提交申请
|
||||
const handleSubmit = async () => {
|
||||
// 这里添加提交申请的逻辑
|
||||
Toast.show("提交申请成功", { duration: 1500 });
|
||||
setPopupVisible(false);
|
||||
// 重置状态
|
||||
setContractFiles([]);
|
||||
setInvoiceFiles([]);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<PageList<BusinessAPI.OrderSupplierVO, BusinessAPI.OrderSupplierPageQry>
|
||||
rowId={"orderSupplierId"}
|
||||
itemHeight={182}
|
||||
type={"infinite"}
|
||||
actionRef={actionRef}
|
||||
render={(orderSupplierVO: BusinessAPI.OrderSupplierVO, index) => (
|
||||
<View className={"flex-1"} key={index}>
|
||||
<View
|
||||
className={"relative flex flex-col divide-y-2 divide-neutral-100"}
|
||||
>
|
||||
<View className="flex-1">
|
||||
<View className="flex items-start justify-between">
|
||||
<View>
|
||||
<View className="text-base font-medium text-gray-800">
|
||||
{orderSupplierVO.name} (
|
||||
{orderSupplierVO.orderVehicle?.origin}-
|
||||
{orderSupplierVO.orderVehicle?.destination})
|
||||
</View>
|
||||
</View>
|
||||
{/*<View className="rounded bg-gray-100 px-2 py-1 text-xs text-gray-800">*/}
|
||||
{/* 草稿*/}
|
||||
{/*</View>*/}
|
||||
</View>
|
||||
<View className="my-1 flex flex-row flex-wrap gap-1 text-sm text-gray-600">
|
||||
<View className="text-primary">
|
||||
{orderSupplierVO.orderVehicle?.vehicleNo
|
||||
? "第" + orderSupplierVO.orderVehicle?.vehicleNo + "车"
|
||||
: "暂未生成车次"}
|
||||
</View>
|
||||
<View>
|
||||
{dayjs(orderSupplierVO.orderVehicle?.deliveryTime).format(
|
||||
"MM-DD",
|
||||
)}
|
||||
</View>
|
||||
<View>|</View>
|
||||
<View>{orderSupplierVO.netWeight}斤</View>
|
||||
<View>|</View>
|
||||
<View>¥{orderSupplierVO.invoiceAmount}</View>
|
||||
</View>
|
||||
<View className="text-xs text-gray-500">
|
||||
{`${orderSupplierVO.productName} | 品种:`}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
toolbar={toolbar}
|
||||
request={async (params) => {
|
||||
const {
|
||||
data: { data, success, notEmpty },
|
||||
} = await business.orderSupplier.pageOrderSupplier({
|
||||
orderSupplierPageQry: {
|
||||
...params,
|
||||
...(supplierVO
|
||||
? {
|
||||
supplierId: supplierVO.supplierId,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
success,
|
||||
hasMore: notEmpty,
|
||||
};
|
||||
}}
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
@ -9,6 +9,7 @@ import * as setting from "./setting";
|
||||
import * as purchaseOrder from "./purchaseOrder";
|
||||
import * as product from "./product";
|
||||
import * as platform from "./platform";
|
||||
import * as orderSupplier from "./orderSupplier";
|
||||
import * as menu from "./menu";
|
||||
import * as material from "./material";
|
||||
import * as materialCategory from "./materialCategory";
|
||||
@ -39,6 +40,7 @@ export default {
|
||||
purchaseOrder,
|
||||
product,
|
||||
platform,
|
||||
orderSupplier,
|
||||
menu,
|
||||
material,
|
||||
materialCategory,
|
||||
|
||||
59
packages/app-client/src/services/business/orderSupplier.ts
Normal file
59
packages/app-client/src/services/business/orderSupplier.ts
Normal file
@ -0,0 +1,59 @@
|
||||
// @ts-ignore
|
||||
/* eslint-disable */
|
||||
import request from "../request";
|
||||
|
||||
/** 订单供应商列表 GET /operation/pageOrderSupplier */
|
||||
export async function pageOrderSupplier(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: BusinessAPI.pageOrderSupplierParams,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.PageResponseOrderSupplierVO>(
|
||||
"/operation/pageOrderSupplier",
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
orderSupplierPageQry: undefined,
|
||||
...params["orderSupplierPageQry"],
|
||||
},
|
||||
...(options || {}),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** 订单供应商更新 PUT /operation/updateOrderSupplier */
|
||||
export async function updateOrderSupplier(
|
||||
body: BusinessAPI.OrderSupplierUpdateCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.SingleResponseOrderSupplierVO>(
|
||||
"/operation/updateOrderSupplier",
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** 订单供应商更新 PATCH /operation/updateOrderSupplier */
|
||||
export async function updateOrderSupplier1(
|
||||
body: BusinessAPI.OrderSupplierUpdateCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.SingleResponseOrderSupplierVO>(
|
||||
"/operation/updateOrderSupplier",
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -1083,8 +1083,6 @@ declare namespace BusinessAPI {
|
||||
strawMatCostFlag?: boolean;
|
||||
/** 发货单合计金额是否含包装费 */
|
||||
includePackingFlag?: boolean;
|
||||
/** 单据类型:delivery-发货单, purchase-采购底单, cost-成本单 */
|
||||
documentTypes?: string;
|
||||
/** 应收金额 */
|
||||
receivable?: number;
|
||||
/** 备注 */
|
||||
@ -1401,8 +1399,6 @@ declare namespace BusinessAPI {
|
||||
strawMatCostFlag?: boolean;
|
||||
/** 发货单合计金额是否含包装费 */
|
||||
includePackingFlag?: boolean;
|
||||
/** 单据类型:delivery-发货单, purchase-采购底单, cost-成本单 */
|
||||
documentTypes?: string;
|
||||
/** 应收金额 */
|
||||
receivable?: number;
|
||||
/** 备注 */
|
||||
@ -1440,8 +1436,6 @@ declare namespace BusinessAPI {
|
||||
strawMatCostFlag?: boolean;
|
||||
/** 发货单合计金额是否含包装费 */
|
||||
includePackingFlag?: boolean;
|
||||
/** 单据类型:delivery-发货单, purchase-采购底单, cost-成本单 */
|
||||
documentTypes?: string;
|
||||
/** 应收金额 */
|
||||
receivable?: number;
|
||||
/** 备注 */
|
||||
@ -2534,8 +2528,6 @@ declare namespace BusinessAPI {
|
||||
enableCompanyRebate?: boolean;
|
||||
/** 公司返点比例 */
|
||||
companyRebateRatio?: number;
|
||||
/** 单据类型:delivery-发货单, purchase-采购底单, cost-成本单 */
|
||||
documentTypes?: string;
|
||||
/** 税费补贴 */
|
||||
taxSubsidy?: number;
|
||||
/** 计提税金 */
|
||||
@ -2549,6 +2541,8 @@ declare namespace BusinessAPI {
|
||||
type OrderPackage = {
|
||||
/** 记录ID */
|
||||
orderPackageId?: string;
|
||||
/** 采购订单记录ID */
|
||||
orderId?: string;
|
||||
/** 供应商记录ID */
|
||||
orderSupplierId?: string;
|
||||
/** 箱子品牌ID */
|
||||
@ -2575,7 +2569,7 @@ declare namespace BusinessAPI {
|
||||
boxCostPrice?: number;
|
||||
/** 销售单价(元/个) */
|
||||
boxSalePrice?: number;
|
||||
/** 箱子类型:1_本次使用;2_额外运输;3_已使用额外运输;4_车上剩余; */
|
||||
/** 箱子类型:1_本次使用;2_额外运输;3_已使用额外运输;4_车上剩余;5_瓜农纸箱;6_空箱; */
|
||||
boxType: "USED" | "EXTRA" | "EXTRA_USED" | "REMAIN" | "OWN" | "EMPTY";
|
||||
};
|
||||
|
||||
@ -2653,6 +2647,106 @@ declare namespace BusinessAPI {
|
||||
productName?: string;
|
||||
/** 采购订单包装箱信息 */
|
||||
orderPackageList?: OrderPackage[];
|
||||
/** 采购订单车辆信息 */
|
||||
orderVehicle?: OrderVehicle;
|
||||
};
|
||||
|
||||
type OrderSupplierPageQry = {
|
||||
pageSize?: number;
|
||||
pageIndex?: number;
|
||||
orderBy?: string;
|
||||
orderDirection?: string;
|
||||
groupBy?: string;
|
||||
needTotalCount?: boolean;
|
||||
/** 自定义字段key */
|
||||
customFieldKey?: string;
|
||||
/** 自定义字段value */
|
||||
customFieldValue?: string;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 状态:1_启用;0_禁用; */
|
||||
status?: boolean;
|
||||
/** 订单供应商ID */
|
||||
orderSupplierId?: string;
|
||||
/** 订单ID */
|
||||
orderId?: string;
|
||||
/** 供应商id */
|
||||
supplierId?: string;
|
||||
/** 发货日期 */
|
||||
deliveryTime?: string[];
|
||||
offset?: number;
|
||||
};
|
||||
|
||||
type OrderSupplierUpdateCmd = {
|
||||
/** 订单供应商ID */
|
||||
orderSupplierId: string;
|
||||
/** 是否上传票证 */
|
||||
invoiceUpload?: boolean;
|
||||
/** 发票照片 */
|
||||
invoiceImg?: string[];
|
||||
/** 是否上传合同 */
|
||||
contractUpload?: boolean;
|
||||
/** 合同照片 */
|
||||
contractImg?: string[];
|
||||
};
|
||||
|
||||
type OrderSupplierVO = {
|
||||
/** 记录ID */
|
||||
orderSupplierId: string;
|
||||
/** 订单ID */
|
||||
orderId: string;
|
||||
/** 供应商ID */
|
||||
supplierId?: string;
|
||||
/** 供应商姓名 */
|
||||
name?: string;
|
||||
/** 身份证号 */
|
||||
idCard?: string;
|
||||
/** 银行卡号 */
|
||||
bankCard?: string;
|
||||
/** 手机号 */
|
||||
phone?: string;
|
||||
/** 微信二维码 */
|
||||
wechatQr?: string;
|
||||
/** 是否最后一家 */
|
||||
isLast?: boolean;
|
||||
/** 空磅是否包含纸箱 */
|
||||
isPaper?: boolean;
|
||||
/** 产品id */
|
||||
productId?: string;
|
||||
/** 产品名称 */
|
||||
productName?: string;
|
||||
/** 空车重量(kg) */
|
||||
emptyWeight?: number;
|
||||
/** 总重量(kg) */
|
||||
totalWeight?: number;
|
||||
/** 毛重(斤) */
|
||||
grossWeight?: number;
|
||||
/** 净重(斤) */
|
||||
netWeight?: number;
|
||||
/** 采购单价(元/斤) */
|
||||
purchasePrice?: number;
|
||||
/** 销售单价(元/斤) */
|
||||
salePrice?: number;
|
||||
/** 报价方式:1_按毛重报价;2_按净重报价; */
|
||||
pricingMethod?: boolean;
|
||||
/** 发票金额 */
|
||||
invoiceAmount?: number;
|
||||
/** 空车照片 */
|
||||
emptyWeightImg?: string;
|
||||
/** 满载照片 */
|
||||
totalWeightImg?: string;
|
||||
/** 是否上传票证 */
|
||||
invoiceUpload?: boolean;
|
||||
/** 发票照片 */
|
||||
invoiceImg?: string[];
|
||||
/** 是否上传合同 */
|
||||
contractUpload?: boolean;
|
||||
/** 合同照片 */
|
||||
contractImg?: string[];
|
||||
/** 创建时间 */
|
||||
createdAt?: string;
|
||||
/** 车辆信息 */
|
||||
orderVehicle?: OrderVehicle;
|
||||
};
|
||||
|
||||
type OrderVehicle = {
|
||||
@ -2761,6 +2855,10 @@ declare namespace BusinessAPI {
|
||||
materialPageQry: MaterialPageQry;
|
||||
};
|
||||
|
||||
type pageOrderSupplierParams = {
|
||||
orderSupplierPageQry: OrderSupplierPageQry;
|
||||
};
|
||||
|
||||
type pagePermissionParams = {
|
||||
permissionPageQry: PermissionPageQry;
|
||||
};
|
||||
@ -2985,6 +3083,19 @@ declare namespace BusinessAPI {
|
||||
totalPages?: number;
|
||||
};
|
||||
|
||||
type PageResponseOrderSupplierVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
errMessage?: string;
|
||||
totalCount?: number;
|
||||
pageSize?: number;
|
||||
pageIndex?: number;
|
||||
data?: OrderSupplierVO[];
|
||||
empty?: boolean;
|
||||
notEmpty?: boolean;
|
||||
totalPages?: number;
|
||||
};
|
||||
|
||||
type PageResponsePermissionVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
@ -3323,6 +3434,8 @@ declare namespace BusinessAPI {
|
||||
orderSupplierList: OrderSupplier[];
|
||||
/** 采购订单费用信息 */
|
||||
orderCostList: OrderCost[];
|
||||
/** 采购订单包装箱信息 */
|
||||
orderPackageList: OrderPackage[];
|
||||
/** 是否是暂存 */
|
||||
draft: boolean;
|
||||
pricingMethod?: "BY_GROSS_WEIGHT" | "BY_NET_WEIGHT";
|
||||
@ -3362,7 +3475,7 @@ declare namespace BusinessAPI {
|
||||
orderSupplierList: OrderSupplier[];
|
||||
/** 采购订单费用信息 */
|
||||
orderCostList: OrderCost[];
|
||||
/** 采购订单空箱费用 */
|
||||
/** 采购订单包装箱信息 */
|
||||
orderPackageList: OrderPackage[];
|
||||
};
|
||||
|
||||
@ -3469,7 +3582,7 @@ declare namespace BusinessAPI {
|
||||
active?: number;
|
||||
/** 采购订单费用信息 */
|
||||
orderCostList: OrderCost[];
|
||||
/** 采购订单空箱费用 */
|
||||
/** 采购订单包装箱信息 */
|
||||
orderPackageList: OrderPackage[];
|
||||
};
|
||||
|
||||
@ -3495,6 +3608,8 @@ declare namespace BusinessAPI {
|
||||
orderSupplierList: OrderSupplier[];
|
||||
/** 采购订单费用信息 */
|
||||
orderCostList: OrderCost[];
|
||||
/** 采购订单包装箱信息 */
|
||||
orderPackageList: OrderPackage[];
|
||||
};
|
||||
|
||||
type PurchaseOrderVO = {
|
||||
@ -3556,7 +3671,7 @@ declare namespace BusinessAPI {
|
||||
orderSupplierList: OrderSupplier[];
|
||||
/** 采购订单费用信息 */
|
||||
orderCostList: OrderCost[];
|
||||
/** 采购订单空箱费用 */
|
||||
/** 采购订单包装箱信息 */
|
||||
orderPackageList: OrderPackage[];
|
||||
};
|
||||
|
||||
@ -3846,11 +3961,7 @@ declare namespace BusinessAPI {
|
||||
/** 发货单明细 */
|
||||
shipOrderItemList?: ShipOrderItem[];
|
||||
/** 发货单据 */
|
||||
shipDocument?: string;
|
||||
/** 采购底单 */
|
||||
purchaseDocument?: string;
|
||||
/** 成本单据 */
|
||||
costDocument?: string;
|
||||
document?: string;
|
||||
};
|
||||
|
||||
type ShipOrderItem = {
|
||||
@ -3972,11 +4083,7 @@ declare namespace BusinessAPI {
|
||||
/** 发货单明细 */
|
||||
shipOrderItemList?: ShipOrderItem[];
|
||||
/** 发货单据 */
|
||||
shipDocument?: string;
|
||||
/** 采购底单 */
|
||||
purchaseDocument?: string;
|
||||
/** 成本单据 */
|
||||
costDocument?: string;
|
||||
document?: string;
|
||||
};
|
||||
|
||||
type ShipOrderVO = {
|
||||
@ -4035,11 +4142,7 @@ declare namespace BusinessAPI {
|
||||
/** 瓜农姓名逗号隔开 */
|
||||
farmerInfo?: string;
|
||||
/** 发货单据 */
|
||||
shipDocument?: string;
|
||||
/** 采购底单 */
|
||||
purchaseDocument?: string;
|
||||
/** 成本单据 */
|
||||
costDocument?: string;
|
||||
document?: string;
|
||||
/** 发货单状态:1_待回款;2_部分回款;3_已回款;4_拒收完结;5_已完结; */
|
||||
state?:
|
||||
| "WAIT_PAYMENT"
|
||||
@ -4304,6 +4407,13 @@ declare namespace BusinessAPI {
|
||||
data?: MenuVO;
|
||||
};
|
||||
|
||||
type SingleResponseOrderSupplierVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
errMessage?: string;
|
||||
data?: OrderSupplierVO;
|
||||
};
|
||||
|
||||
type SingleResponseOssTokenVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
|
||||
@ -30,6 +30,10 @@ export class PurchaseOrderCalculator {
|
||||
getTotalPackagingCost(): number {
|
||||
const costItemsCost = this.purchaseOrderVO.orderCostList.reduce(
|
||||
(sum, cost) => {
|
||||
// 先过滤一下
|
||||
if (cost.name === "纸箱费") {
|
||||
return new Decimal(sum).toNumber();
|
||||
}
|
||||
return new Decimal(sum)
|
||||
.plus(new Decimal(cost.price || 0).mul(cost.count || 0))
|
||||
.toNumber();
|
||||
@ -84,6 +88,8 @@ export class PurchaseOrderCalculator {
|
||||
getTotalPurchaseCost(): number {
|
||||
const supplierPurchaseCost = this.getSupplierPurchaseCost();
|
||||
const totalPackagingCost = this.getTotalPackagingCost();
|
||||
console.log("supplierPurchaseCost", supplierPurchaseCost);
|
||||
console.log("totalPackagingCost", totalPackagingCost);
|
||||
return new Decimal(supplierPurchaseCost)
|
||||
.plus(totalPackagingCost)
|
||||
.toNumber();
|
||||
@ -389,9 +395,7 @@ export class PurchaseOrderCalculator {
|
||||
const includePackingFlag =
|
||||
this.purchaseOrderVO.orderDealer?.includePackingFlag;
|
||||
if (includePackingFlag) {
|
||||
return decimal
|
||||
.plus(this.getTotalPackagingCost())
|
||||
.toNumber();
|
||||
return decimal.plus(this.getTotalPackagingCost()).toNumber();
|
||||
}
|
||||
|
||||
return decimal.toNumber();
|
||||
|
||||
617
packages/app-client/src/utils/Template.ts
Normal file
617
packages/app-client/src/utils/Template.ts
Normal file
@ -0,0 +1,617 @@
|
||||
class Template {
|
||||
private moduleList: any[];
|
||||
|
||||
constructor(moduleList: any[]) {
|
||||
this.moduleList = moduleList;
|
||||
}
|
||||
|
||||
// 将预览内容转换为HTML字符串的函数
|
||||
generateHtmlString = () => {
|
||||
let htmlString = `
|
||||
<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>
|
||||
<div class="page-wrap">
|
||||
<div class="page-content">
|
||||
`;
|
||||
|
||||
this.moduleList.forEach((module) => {
|
||||
const config = module.config;
|
||||
|
||||
if (module.type === "title") {
|
||||
htmlString += `
|
||||
<div class="preview grid w-full grid-cols-8 gap-0 text-2xl font-bold">
|
||||
<div class="col-span-8 flex items-end justify-center">
|
||||
${config.title || ""}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (module.type === "dealerInfo") {
|
||||
htmlString += `
|
||||
<div class="preview grid w-full grid-cols-8 gap-0 text-lg font-bold">
|
||||
<div class="col-span-1"></div>
|
||||
`;
|
||||
|
||||
if (config.showDealerName || config.showWatermelonGrade) {
|
||||
htmlString += `
|
||||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||||
${
|
||||
config.showWatermelonGrade
|
||||
? `${config.dealerName || ""}-${config.watermelonGrade || ""}`
|
||||
: config.dealerName || ""
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
htmlString += `<div class="col-span-3"></div>`;
|
||||
}
|
||||
|
||||
if (config.showDestination || config.showVehicleNumber) {
|
||||
htmlString += `
|
||||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||||
${config.destination || ""} ${config.vehicleNumber || ""}
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
htmlString += `<div class="col-span-3"></div>`;
|
||||
}
|
||||
|
||||
htmlString += `
|
||||
<div class="col-span-1"></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (module.type === "shippingInfo") {
|
||||
htmlString += `<div class="preview grid w-full grid-cols-8 gap-0 text-base">`;
|
||||
|
||||
if (config.showShippingFrom) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">发货地:</div>
|
||||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||||
${config.shippingFrom || ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showDate) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">日期:</div>
|
||||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||||
${config.date || ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlString += `</div>`;
|
||||
}
|
||||
|
||||
if (module.type === "weightInfo") {
|
||||
if (config.data) {
|
||||
config.data.forEach((item: any) => {
|
||||
htmlString += `<div class="preview grid w-full grid-cols-2 gap-0 text-base">`;
|
||||
|
||||
if (config.showNetWeight) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 grid grid-cols-4">
|
||||
<div class="col-span-1 flex items-end justify-center">净重:</div>
|
||||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||||
${item.netWeight || ""}
|
||||
</div>
|
||||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||||
${config.netWeightUnit === "1" ? "斤" : "公斤"}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showBoxWeight) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 grid grid-cols-4">
|
||||
<div class="col-span-1 flex items-end justify-center">箱重:</div>
|
||||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||||
${item.boxWeight || ""}
|
||||
</div>
|
||||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||||
${config.boxWeightUnit === "1" ? "斤" : "公斤"}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showGrossWeight) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 grid grid-cols-4">
|
||||
<div class="col-span-1 flex items-end justify-center">毛重:</div>
|
||||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||||
${item.grossWeight || ""}
|
||||
</div>
|
||||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||||
${config.grossWeightUnit === "1" ? "斤" : "公斤"}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showUnitPrice) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 grid grid-cols-4">
|
||||
<div class="col-span-1 flex items-end justify-center">单价:</div>
|
||||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||||
${item.unitPrice || ""}
|
||||
</div>
|
||||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||||
${config.unitPriceUnit === "1" ? "元/斤" : "元/公斤"}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showAmount) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 grid grid-cols-4">
|
||||
<div class="col-span-1 flex items-end justify-center">金额:</div>
|
||||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||||
${item.totalAmount || ""}
|
||||
</div>
|
||||
<div class="col-span-1 flex items-end justify-center border-b border-black">元</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showGrade) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 grid grid-cols-4">
|
||||
<div class="col-span-1 flex items-end justify-center">品级:</div>
|
||||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||||
${item.watermelonGrade || ""}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlString += `</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
htmlString += `<div class="preview grid w-full grid-cols-2 gap-0 text-base">`;
|
||||
|
||||
if (config.showAccountCompany) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 grid grid-cols-4">
|
||||
<div class="col-span-1 flex items-end justify-center">入账公司:</div>
|
||||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||||
${config.accountCompany || ""}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showSumAmount) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 grid grid-cols-4">
|
||||
<div class="col-span-1 flex items-end justify-center">总计:</div>
|
||||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||||
${config.sumAmount || ""}
|
||||
</div>
|
||||
<div class="col-span-1 flex items-end justify-center border-b border-black">元</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlString += `</div>`;
|
||||
}
|
||||
|
||||
if (module.type === "packingSpec") {
|
||||
htmlString += `<div>`;
|
||||
// 计算需要显示的列数
|
||||
const visibleColumnCount =
|
||||
[
|
||||
config.showBoxType,
|
||||
config.showQuantity,
|
||||
config.showUnitPrice,
|
||||
config.showAmount,
|
||||
config.showUnitWeight,
|
||||
config.showWeight,
|
||||
].filter(Boolean).length + 1; // +1 是因为"规格:"列总是显示
|
||||
|
||||
const gridClass = `grid w-full gap-0 text-base grid-cols-${visibleColumnCount}`;
|
||||
|
||||
htmlString += `
|
||||
<div class="${gridClass}">
|
||||
<div class="grid-span-1 flex items-end justify-center">规格:</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
htmlString += `<div class="${gridClass}">`;
|
||||
|
||||
if (config.columns) {
|
||||
config.columns.forEach((column: any, index: number) => {
|
||||
if (index === 0) {
|
||||
htmlString += `<div class=""> </div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
(column.dataIndex === "boxType" && config.showBoxType) ||
|
||||
(column.dataIndex === "quantity" && config.showQuantity) ||
|
||||
(column.dataIndex === "unitPrice" && config.showUnitPrice) ||
|
||||
(column.dataIndex === "amount" && config.showAmount) ||
|
||||
(column.dataIndex === "unitWeight" && config.showUnitWeight) ||
|
||||
(column.dataIndex === "weight" && config.showWeight)
|
||||
) {
|
||||
htmlString += `
|
||||
<div class="flex items-end justify-center">${column.title || ""}</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
htmlString += `</div>`;
|
||||
htmlString += `<div class="table-border">`;
|
||||
|
||||
if (config.data) {
|
||||
config.data.forEach((item: any, index: number) => {
|
||||
htmlString += `
|
||||
<div class="${gridClass} ${index > 0 ? "border-t-0" : ""}">
|
||||
<div class="flex items-end justify-center">
|
||||
${item.boxSpecName}
|
||||
</div>
|
||||
`;
|
||||
|
||||
htmlString += `
|
||||
<div class="flex items-end justify-center">${item.boxType || ""}</div>
|
||||
`;
|
||||
|
||||
if (config.showQuantity) {
|
||||
htmlString += `
|
||||
<div class="flex items-end justify-center">${item.quantity || ""}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showUnitPrice) {
|
||||
htmlString += `
|
||||
<div class="flex items-end justify-center">${item.unitPrice || ""}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showAmount) {
|
||||
htmlString += `
|
||||
<div class="flex items-end justify-center">${item.amount || ""}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showUnitWeight) {
|
||||
htmlString += `
|
||||
<div class="flex items-end justify-center">${item.unitWeight || ""}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showWeight) {
|
||||
htmlString += `
|
||||
<div class="flex items-end justify-center">${item.weight || ""}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlString += `</div>`;
|
||||
});
|
||||
}
|
||||
|
||||
htmlString += `
|
||||
<div class="${gridClass}">
|
||||
<div class="col-span-2 flex items-end justify-center">总件数</div>
|
||||
`;
|
||||
|
||||
if (config.showQuantity) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">
|
||||
${
|
||||
config.data?.reduce(
|
||||
(acc: any, cur: any) => acc + Number(cur.quantity || 0),
|
||||
0,
|
||||
) || 0
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showUnitPrice) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showAmount) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">
|
||||
${
|
||||
config.data?.reduce(
|
||||
(acc: any, cur: any) => acc + Number(cur.amount || 0),
|
||||
0,
|
||||
) || 0
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showUnitWeight) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showWeight) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">
|
||||
${
|
||||
config.data?.reduce(
|
||||
(acc: any, cur: any) => acc + Number(cur.weight || 0),
|
||||
0,
|
||||
) || 0
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlString += `
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
htmlString += `</div>`;
|
||||
}
|
||||
|
||||
if (module.type === "vehicleInfo") {
|
||||
htmlString += `<div class="preview grid w-full grid-cols-8 gap-0 text-base">`;
|
||||
|
||||
if (config.showDriverPhone) {
|
||||
htmlString += `
|
||||
<div class="col-span-2 flex items-end justify-center">司机号码:</div>
|
||||
<div class="col-span-6 flex items-end justify-center border-b border-black">
|
||||
${config.driverPhone || ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showLicensePlate) {
|
||||
htmlString += `
|
||||
<div class="col-span-2 flex items-end justify-center">车牌:</div>
|
||||
<div class="col-span-6 flex items-end justify-center border-b border-black">
|
||||
${config.licensePlate || ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showEstimatedArrivalTime) {
|
||||
htmlString += `
|
||||
<div class="col-span-2 flex items-end justify-center">预计到仓时间:</div>
|
||||
<div class="col-span-6 flex items-end justify-center border-b border-black">
|
||||
${config.estimatedArrivalTime || ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showRemarks) {
|
||||
htmlString += `
|
||||
<div class="col-span-2 flex items-end justify-center">备注:</div>
|
||||
<div class="col-span-6 flex items-end justify-center border-b border-black">
|
||||
${config.remarks || ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showFreightDebt) {
|
||||
htmlString += `
|
||||
<div class="col-span-2 flex items-end justify-center">
|
||||
${config.freightDebtTitle || "运费欠"}:
|
||||
</div>
|
||||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||||
${config.freightDebt || ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showStrawMatDebt) {
|
||||
htmlString += `
|
||||
<div class="col-span-2 flex items-end justify-center">草帘欠:</div>
|
||||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||||
${config.strawMatDebt || ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlString += `</div>`;
|
||||
}
|
||||
|
||||
if (module.type === "otherFees") {
|
||||
htmlString += `<div class="preview grid w-full grid-cols-8 gap-0 text-base">`;
|
||||
|
||||
if (config.feeItems) {
|
||||
config.feeItems.forEach((feeType: any) => {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">
|
||||
${(config.feeLabels && config.feeLabels[feeType]) || ""}:
|
||||
</div>
|
||||
<div class="col-span-1 flex items-end justify-center border-b border-black">
|
||||
${config[feeType] || ""}元
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
htmlString += `</div>`;
|
||||
}
|
||||
|
||||
if (module.type === "totalAmount") {
|
||||
htmlString += `<div class="preview grid w-full grid-cols-8 gap-0 text-base">`;
|
||||
|
||||
if (config.showTotalAmount) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">
|
||||
${config.sumTitle || "合计金额"}:
|
||||
</div>
|
||||
<div class="col-span-2 flex items-end justify-center border-b border-black">
|
||||
${config.amount || ""}
|
||||
</div>
|
||||
<div class="col-span-1 flex items-end justify-center border-b border-black">元</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.showFarmer) {
|
||||
htmlString += `
|
||||
<div class="col-span-1 flex items-end justify-center">瓜农:</div>
|
||||
<div class="col-span-3 flex items-end justify-center border-b border-black">
|
||||
${config.farmer || ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlString += `</div>`;
|
||||
}
|
||||
|
||||
if (module.type === "otherInfo") {
|
||||
htmlString += `
|
||||
<div class="table-border">
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">车次:</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${config.vehicleNumber}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
收货地:
|
||||
</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${config.destination}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (config.showShippingFrom) {
|
||||
htmlString += `
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
产地:
|
||||
</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${config.shippingFrom}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlString += `<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
供应商:
|
||||
</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${config.accountCompany}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
发车时间:
|
||||
</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${config.date}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (config.showEstimatedArrivalTime) {
|
||||
htmlString += `<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
到达时间:
|
||||
</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${config.estimatedArrivalTime}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (config.data) {
|
||||
config.data?.forEach((item: any) => {
|
||||
if (config.showGrade) {
|
||||
htmlString += `
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
品名:
|
||||
</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${item.watermelonGrade}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
htmlString += `
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
发货重量:
|
||||
</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
以公司入库重量为准。
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
净瓜单价:
|
||||
</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${item.unitPrice}
|
||||
${config.unitPriceUnit === "1" ? "元/斤" : "元/公斤"}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
htmlString += `
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
大约重量:
|
||||
</div>
|
||||
<div class="p-2 text-left">
|
||||
${config.data?.reduce(
|
||||
(acc: any, cur: any) => acc + cur.grossWeight,
|
||||
0,
|
||||
)}
|
||||
</div>
|
||||
<div class="p-2 text-left">斤</div>
|
||||
</div>
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">箱数</div>
|
||||
<div class="p-2 text-left">
|
||||
${config.data?.reduce(
|
||||
(acc: any, cur: any) => acc + cur.boxCount,
|
||||
0,
|
||||
)}
|
||||
</div>
|
||||
<div class="p-2 text-left">件</div>
|
||||
</div>
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">车号:</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${config.licensePlate}
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid w-full grid-cols-3 gap-0 text-base">
|
||||
<div class="p-2 text-left font-bold">
|
||||
手机号:
|
||||
</div>
|
||||
<div class="col-span-2 p-2 text-left">
|
||||
${config.driverPhone}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
htmlString += `</div></div>`;
|
||||
return htmlString;
|
||||
};
|
||||
}
|
||||
1690
pnpm-lock.yaml
1690
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user