feat(purchase): 优化采购模块人工费用和车辆信息处理逻辑
- 调整API域名配置,区分h5和小程序环境 - 重构OrderCost组件,支持多种费用类型筛选和展示 - 优化OrderVehicle组件,简化经销商信息赋值逻辑 - Weigh组件新增西瓜品种选择功能,包含弹窗和校验逻辑 - 重写LaborInfoSection组件,支持新增和编辑人工费用项 - 改进费用承担方和工头信息的处理流程 - 优化UI布局和交互体验
This commit is contained in:
parent
a62ca1fb95
commit
3f8c6d962a
@ -10,7 +10,10 @@ export default {
|
||||
},
|
||||
defineConstants: {
|
||||
"process.env.TARO_APP_ID": '"wxa080848726642f73"',
|
||||
"process.env.TARO_API_DOMAIN": '"/api"',
|
||||
"process.env.TARO_API_DOMAIN":
|
||||
process.env.TARO_ENV === "h5"
|
||||
? '"/api"'
|
||||
: '"https://api.erp.qilincloud168.com"',
|
||||
},
|
||||
mini: {
|
||||
miniCssExtractPluginOption: {
|
||||
|
||||
@ -18,7 +18,10 @@ export default {
|
||||
},
|
||||
defineConstants: {
|
||||
"process.env.TARO_APP_ID": '"wxa080848726642f73"',
|
||||
"process.env.TARO_API_DOMAIN": '"https://api.erp.qilincloud168.com"',
|
||||
"process.env.TARO_API_DOMAIN":
|
||||
process.env.TARO_ENV === "h5"
|
||||
? '"/api"'
|
||||
: '"https://api.erp.qilincloud168.com"',
|
||||
},
|
||||
mini: {
|
||||
miniCssExtractPluginOption: {
|
||||
|
||||
@ -18,4 +18,12 @@ export default [
|
||||
projectName: "business",
|
||||
namespace: "BusinessAPI",
|
||||
},
|
||||
{
|
||||
requestLibPath: "import request from '../poster-request';",
|
||||
// schemaPath: 'http://localhost:8080/mdb-business/v3/api-docs',
|
||||
schemaPath: path.resolve(__dirname, "../../swagger/poster.json"),
|
||||
serversPath: "./src/services",
|
||||
projectName: "poster",
|
||||
namespace: "PosterAPI",
|
||||
},
|
||||
];
|
||||
|
||||
@ -40,7 +40,7 @@ config = {
|
||||
// 发货单
|
||||
{
|
||||
root: "pages/delivery",
|
||||
pages: ["list", "document"],
|
||||
pages: ["list", "document/delivery", "document/purchase"],
|
||||
},
|
||||
],
|
||||
permission: {
|
||||
@ -49,7 +49,7 @@ config = {
|
||||
},
|
||||
},
|
||||
tabBar: {
|
||||
custom: false,
|
||||
custom: process.env.TARO_ENV === "weapp",
|
||||
color: "#000000",
|
||||
selectedColor: "#DC143C",
|
||||
backgroundColor: "#ffffff",
|
||||
|
||||
@ -36,15 +36,29 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
|
||||
showInEntry: true,
|
||||
},
|
||||
});
|
||||
const costItemList = data.data;
|
||||
|
||||
if (costItemList) {
|
||||
// 人工辅料选中
|
||||
const initialList =
|
||||
data.data?.map((item) => {
|
||||
costItemList
|
||||
?.filter(
|
||||
(item) =>
|
||||
item.costType === "HUMAN_COST" ||
|
||||
item.costType === "PACKAGING_MATERIALS",
|
||||
)
|
||||
.map((item) => {
|
||||
// 查找是否在purchaseOrder中已有该item的记录
|
||||
const existingItem = value?.find(
|
||||
(costItem) => costItem.itemId === item.itemId,
|
||||
);
|
||||
|
||||
console.log("existingItem", existingItem, value)
|
||||
|
||||
return {
|
||||
orderCostId: generateShortId(),
|
||||
orderCostId: existingItem
|
||||
? existingItem.orderCostId
|
||||
: generateShortId(),
|
||||
itemId: item.itemId,
|
||||
name: item.name,
|
||||
price: item.price,
|
||||
@ -57,7 +71,29 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
|
||||
};
|
||||
}) || [];
|
||||
|
||||
setCostItemVOList(initialList as CostItem[]);
|
||||
setCostItemVOList([
|
||||
...(initialList || []),
|
||||
...(value
|
||||
?.filter(
|
||||
(item) =>
|
||||
item.costType === "WORKER_ADVANCE" ||
|
||||
item.costType === "PRODUCTION_ADVANCE",
|
||||
)
|
||||
.map((item) => {
|
||||
return {
|
||||
orderCostId: item.orderCostId,
|
||||
itemId: item.itemId,
|
||||
name: item.name,
|
||||
price: item.price,
|
||||
unit: item.unit,
|
||||
selected: item.selected,
|
||||
count: item.count,
|
||||
payerType: item.payerType,
|
||||
principal: item.principal,
|
||||
costType: item.costType,
|
||||
};
|
||||
}) || []),
|
||||
]);
|
||||
|
||||
// 初始化总的工头姓名(如果有启用且费用承担方为"我方"的项目)
|
||||
const enabledUsItems = initialList.filter(
|
||||
@ -69,6 +105,7 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
|
||||
if (enabledUsItems.length > 0 && enabledUsItems[0].principal) {
|
||||
setPrincipal(enabledUsItems[0].principal || "");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 当传入的value发生变化时,重新初始化列表
|
||||
@ -253,7 +290,7 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
|
||||
// 渲染项目列表
|
||||
const renderItemList = (items: CostItem[], type: string) => {
|
||||
return items.map((item) => (
|
||||
<View className="mb-2.5" key={item.orderCostId}>
|
||||
<View key={item.orderCostId}>
|
||||
<View className={"flex flex-col gap-2.5 rounded-lg bg-white p-2.5"}>
|
||||
<View className={"flex flex-row justify-between"}>
|
||||
<View className="block text-sm font-normal text-[#000000]">
|
||||
@ -384,10 +421,10 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="flex flex-1 flex-col bg-[#D1D5DB] px-2.5 pt-2.5">
|
||||
<View className={"mb-2.5"}>
|
||||
<View className="mb-2.5 text-sm font-bold">人工费用</View>
|
||||
<View className="mb-2.5 flex items-center rounded-lg border border-blue-200 bg-blue-50 p-2.5">
|
||||
<View className="flex flex-1 flex-col bg-[#D1D5DB] p-2.5 pt-2.5 gap-2.5">
|
||||
<View className={"flex flex-1 flex-col gap-2.5"}>
|
||||
<View className="text-sm font-bold">人工费用</View>
|
||||
<View className="flex items-center rounded-lg border border-blue-200 bg-blue-50 p-2.5">
|
||||
<Icon
|
||||
className={"mr-1"}
|
||||
name="circle-info"
|
||||
@ -400,7 +437,7 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
|
||||
|
||||
{/* 总的工头姓名输入框 */}
|
||||
{shouldShowPrincipalInput() && (
|
||||
<View className="mt-2.5">
|
||||
<View>
|
||||
<View className="mb-1 text-sm font-medium">工头叫什么名字</View>
|
||||
<View
|
||||
className={`flex h-12 items-center rounded-md px-3 ${principalError ? "border-2 border-red-500 bg-red-100" : "border-2 border-gray-300 bg-white"}`}
|
||||
@ -424,9 +461,9 @@ export default forwardRef<OrderCostRef, IOrderCostProps>(
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View className={"mb-2.5"}>
|
||||
<View className="mb-2.5 text-sm font-bold">辅料费用</View>
|
||||
<View className="mb-2.5 flex items-center rounded-lg border border-blue-200 bg-blue-50 p-2.5">
|
||||
<View className={"flex flex-1 flex-col gap-2.5"}>
|
||||
<View className="text-sm font-bold">辅料费用</View>
|
||||
<View className="flex items-center rounded-lg border border-blue-200 bg-blue-50 p-2.5">
|
||||
<Icon
|
||||
className={"mr-1"}
|
||||
name="circle-info"
|
||||
|
||||
@ -77,15 +77,7 @@ export default forwardRef<OrderVehicleRef, IOrderVehicleProps>(
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
// 校验经销商信息
|
||||
@ -485,7 +477,7 @@ export default forwardRef<OrderVehicleRef, IOrderVehicleProps>(
|
||||
|
||||
const { data } = await business.extraction.vehicleExtraction({
|
||||
message: message,
|
||||
dealerNames: '',
|
||||
dealerNames: "",
|
||||
});
|
||||
|
||||
const newVehicle = data.data as BusinessAPI.VehicleExtractionVO;
|
||||
|
||||
@ -5,12 +5,14 @@ import {
|
||||
Toast,
|
||||
Uploader,
|
||||
UploaderFileItem,
|
||||
Popup,
|
||||
} from "@nutui/nutui-react-taro";
|
||||
import { Icon } from "@/components";
|
||||
import { SupplierVO } from "@/types/typings";
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
||||
import { uploadFile } from "@/utils/uploader";
|
||||
import { validatePrice } from "@/utils/format";
|
||||
import { business } from "@/services";
|
||||
|
||||
// 定义ref暴露的方法接口
|
||||
export interface WeighRef {
|
||||
@ -22,13 +24,30 @@ interface IWeightProps {
|
||||
onChange: (supplierVO: SupplierVO) => void;
|
||||
isFirst?: boolean;
|
||||
changePaper: (isPaper: boolean) => void;
|
||||
changeProduct: (productVO: BusinessAPI.ProductVO) => void;
|
||||
}
|
||||
|
||||
export default forwardRef<WeighRef, IWeightProps>(function Weigh(props, ref) {
|
||||
const { value, onChange, isFirst, changePaper } = props;
|
||||
const { value, onChange, isFirst, changePaper, changeProduct } = props;
|
||||
|
||||
const [supplierVO, setSupplierVO] = useState<SupplierVO>();
|
||||
|
||||
useEffect(() => {
|
||||
// 获取产品列表
|
||||
business.product
|
||||
.listProduct({
|
||||
productListQry: {
|
||||
status: true,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
if (data.success) {
|
||||
const products = data.data || [];
|
||||
setProductList(products);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
// 初始化数据
|
||||
useEffect(() => {
|
||||
setSupplierVO(value);
|
||||
@ -69,10 +88,19 @@ export default forwardRef<WeighRef, IWeightProps>(function Weigh(props, ref) {
|
||||
UploaderFileItem[]
|
||||
>([]);
|
||||
|
||||
const [isProductIdError, setProductIdError] = useState<{
|
||||
[key: string]: boolean;
|
||||
}>({}); // 添加瓜农是否选择西瓜品牌的错误状态
|
||||
|
||||
const [isPaperError, setIsPaperError] = useState<{
|
||||
[key: string]: boolean;
|
||||
}>({}); // 添加是否为最后一个瓜农的错误状态
|
||||
|
||||
const [productPopupVisible, setProductPopupVisible] = useState(false);
|
||||
const [selectedProduct, setSelectedProduct] = useState("");
|
||||
const [customProduct, setCustomProduct] = useState("");
|
||||
const [productList, setProductList] = useState<BusinessAPI.ProductVO[]>([]);
|
||||
|
||||
// 添加三个字段的错误状态
|
||||
const [emptyWeightError, setEmptyWeightError] = useState<{
|
||||
[key: string]: boolean;
|
||||
@ -136,6 +164,23 @@ export default forwardRef<WeighRef, IWeightProps>(function Weigh(props, ref) {
|
||||
return isPaper !== undefined && isPaper !== null;
|
||||
};
|
||||
|
||||
// 校验西瓜品种
|
||||
const validateProductId = (productId: any) => {
|
||||
if (productId === "" || productId === undefined || productId === null) {
|
||||
setProductIdError((prev) => ({
|
||||
...prev,
|
||||
[supplierVO.orderSupplierId]: true,
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
|
||||
setProductIdError((prev) => ({
|
||||
...prev,
|
||||
[supplierVO.orderSupplierId]: false,
|
||||
}));
|
||||
return true;
|
||||
};
|
||||
|
||||
// 校验空磅重量
|
||||
const validateEmptyWeight = (value: any) => {
|
||||
if (value === "" || value === undefined || value === null) {
|
||||
@ -225,6 +270,7 @@ export default forwardRef<WeighRef, IWeightProps>(function Weigh(props, ref) {
|
||||
supplierVO.purchasePrice,
|
||||
);
|
||||
const isPaperValid = validateIsPaper(supplierVO.isPaper);
|
||||
const isProductIdValid = validateProductId(supplierVO.productId);
|
||||
|
||||
// 更新错误状态
|
||||
setIsPaperError((prev) => ({
|
||||
@ -232,6 +278,12 @@ export default forwardRef<WeighRef, IWeightProps>(function Weigh(props, ref) {
|
||||
[id]: !isPaperValid,
|
||||
}));
|
||||
|
||||
// 更新错误状态
|
||||
setProductIdError((prev) => ({
|
||||
...prev,
|
||||
[id]: !isProductIdValid,
|
||||
}));
|
||||
|
||||
setPriceError((prev) => ({
|
||||
...prev,
|
||||
[id]: !isPurchasePriceValid,
|
||||
@ -251,6 +303,7 @@ export default forwardRef<WeighRef, IWeightProps>(function Weigh(props, ref) {
|
||||
isEmptyWeightValid &&
|
||||
isTotalWeightValid &&
|
||||
isPurchasePriceValid &&
|
||||
isProductIdValid &&
|
||||
isPaperValid;
|
||||
|
||||
if (!isValid) {
|
||||
@ -266,7 +319,121 @@ export default forwardRef<WeighRef, IWeightProps>(function Weigh(props, ref) {
|
||||
|
||||
return (
|
||||
<View className="flex flex-1 flex-col gap-2.5 p-2.5">
|
||||
{/* 西瓜品种选择弹窗 */}
|
||||
<Popup
|
||||
visible={productPopupVisible}
|
||||
position="bottom"
|
||||
title="请选择具体品种"
|
||||
onClose={() => setProductPopupVisible(false)}
|
||||
round
|
||||
closeable
|
||||
>
|
||||
<View className="p-4">
|
||||
<View id="sub-options" className="slide-in mt-3">
|
||||
<View className="mb-3 text-sm font-medium text-gray-500">
|
||||
请选择具体品种
|
||||
</View>
|
||||
<View className="grid grid-cols-2 gap-2">
|
||||
{productList.map((product) => (
|
||||
<View
|
||||
className={`cursor-pointer rounded-lg border p-3 text-center hover:bg-gray-50 ${selectedProduct === product.name ? "border-primary border-2" : "border-gray-200"}`}
|
||||
key={product.productId}
|
||||
onClick={() => setSelectedProduct(product.name)}
|
||||
>
|
||||
<View
|
||||
className={
|
||||
selectedProduct === product.name
|
||||
? "text-primary font-medium"
|
||||
: ""
|
||||
}
|
||||
>
|
||||
{product.name}
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
{selectedProduct === "其他(请注明)" && (
|
||||
<View className="mt-4">
|
||||
<View
|
||||
className={`flex h-10 w-full items-center rounded-md ${selectedProduct === "其他(请注明)" && customProduct ? "border-primary border-4" : "border-4 border-gray-300"}`}
|
||||
>
|
||||
<Input
|
||||
placeholder="请输入品种"
|
||||
type="text"
|
||||
value={customProduct}
|
||||
onChange={(value) => {
|
||||
setCustomProduct(value);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
<View className="mt-6 flex gap-3">
|
||||
<View
|
||||
className="border-primary text-primary flex-1 cursor-pointer rounded-md border py-3 text-center"
|
||||
onClick={() => {
|
||||
setProductPopupVisible(false);
|
||||
setSelectedProduct("");
|
||||
setCustomProduct("");
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</View>
|
||||
<View
|
||||
className="bg-primary flex-1 cursor-pointer rounded-md py-3 text-center text-white"
|
||||
onClick={() => {
|
||||
let finalProduct = "";
|
||||
if (selectedProduct === "其他(请注明)") {
|
||||
finalProduct = customProduct;
|
||||
} else if (selectedProduct) {
|
||||
// 从产品列表中找到选中产品的ID
|
||||
const selectedProductObj = productList.find(
|
||||
(p) => p.name === selectedProduct,
|
||||
);
|
||||
if (selectedProductObj) {
|
||||
finalProduct = selectedProductObj.productId;
|
||||
}
|
||||
}
|
||||
|
||||
if (finalProduct) {
|
||||
// 找到选中的产品对象
|
||||
const productObj = productList.find(
|
||||
(p) => p.name === selectedProduct,
|
||||
);
|
||||
|
||||
if (productObj) {
|
||||
setSupplierVO({
|
||||
...supplierVO,
|
||||
productId: productObj.productId,
|
||||
productName:
|
||||
selectedProduct === "其他(请注明)"
|
||||
? customProduct
|
||||
: productObj.name,
|
||||
});
|
||||
|
||||
changeProduct({
|
||||
...productObj,
|
||||
name:
|
||||
selectedProduct === "其他(请注明)"
|
||||
? customProduct
|
||||
: productObj.name,
|
||||
});
|
||||
}
|
||||
|
||||
setProductPopupVisible(false);
|
||||
setSelectedProduct("");
|
||||
setCustomProduct("");
|
||||
}
|
||||
}}
|
||||
>
|
||||
确定
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Popup>
|
||||
{isFirst && (
|
||||
<>
|
||||
<View className="border-primary rounded-lg border-4 bg-white p-2.5 shadow-sm">
|
||||
<View className={"flex items-center justify-between gap-2.5"}>
|
||||
<View className="text-sm">空车过磅时带纸箱了吗?</View>
|
||||
@ -313,6 +480,61 @@ export default forwardRef<WeighRef, IWeightProps>(function Weigh(props, ref) {
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{productList.length > 0 && (
|
||||
<View className="border-primary rounded-lg border-4 bg-white p-2.5 shadow-sm">
|
||||
<View className={"flex items-center justify-between gap-2.5"}>
|
||||
<View className="text-sm">西瓜品种</View>
|
||||
<View className="text-neutral-darkest text-sm font-medium">
|
||||
<Radio.Group
|
||||
direction="horizontal"
|
||||
value={supplierVO.productId}
|
||||
onChange={(value) => {
|
||||
// 清除错误状态
|
||||
setProductIdError((prev) => ({
|
||||
...prev,
|
||||
[supplierVO.orderSupplierId]: false,
|
||||
}));
|
||||
|
||||
if (value === "other") {
|
||||
// 点击"其他"时打开弹窗
|
||||
setProductPopupVisible(true);
|
||||
} else {
|
||||
// 根据用户选择设置西瓜品种
|
||||
const productId = value as string;
|
||||
const productVO = productList.find(
|
||||
(p) => p.productId === productId,
|
||||
);
|
||||
|
||||
if (productVO) {
|
||||
setSupplierVO({
|
||||
...supplierVO,
|
||||
productId: productVO?.productId,
|
||||
productName: productVO?.name,
|
||||
});
|
||||
|
||||
changeProduct(productVO);
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Radio
|
||||
value={supplierVO.productId || productList?.[0].productId}
|
||||
>
|
||||
{supplierVO.productName || productList?.[0].name}
|
||||
</Radio>
|
||||
<Radio value="other">其他</Radio>
|
||||
</Radio.Group>
|
||||
</View>
|
||||
</View>
|
||||
{isProductIdError[supplierVO.orderSupplierId] && (
|
||||
<View className="mt-1 text-xs text-red-500">
|
||||
请选择西瓜品种
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<View className="border-primary rounded-lg border-4 bg-white p-2.5 shadow-sm">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,16 @@
|
||||
import { Text, View } from "@tarojs/components";
|
||||
import { Button, Input, Popup, SafeArea } from "@nutui/nutui-react-taro";
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
Picker,
|
||||
Popup,
|
||||
SafeArea,
|
||||
} from "@nutui/nutui-react-taro";
|
||||
import { useEffect, useState } from "react";
|
||||
import { validatePrice } from "@/utils/format";
|
||||
import { generateShortId } from "@/utils/generateShortId";
|
||||
import { business } from "@/services";
|
||||
import { Icon } from "@/components";
|
||||
|
||||
export default function MaterialCostSection(props: {
|
||||
purchaseOrderVO: BusinessAPI.PurchaseOrderVO;
|
||||
@ -15,6 +24,28 @@ export default function MaterialCostSection(props: {
|
||||
{},
|
||||
);
|
||||
|
||||
// 新增辅料费弹窗状态
|
||||
const [showAddCostPopup, setShowAddCostPopup] = useState(false);
|
||||
|
||||
// 新增辅料费表单数据
|
||||
const [newCostData, setNewCostData] = useState<any>({
|
||||
itemId: "", // 费用项目ID
|
||||
name: "", // 费用名称
|
||||
quantity: 0, // 数量
|
||||
unit: "", // 单位
|
||||
unitPrice: "", // 单价
|
||||
amount: "", // 金额
|
||||
requireQuantityAndPrice: false,
|
||||
});
|
||||
|
||||
// Picker可见状态
|
||||
const [pickerVisible, setPickerVisible] = useState({
|
||||
costItem: false, // 费用项目Picker
|
||||
});
|
||||
|
||||
// 费用项目列表
|
||||
const [costItems, setCostItems] = useState<BusinessAPI.CostItemVO[]>([]);
|
||||
|
||||
// 编辑值的状态
|
||||
const [editValues, setEditValues] = useState<{
|
||||
[key: string]: {
|
||||
@ -81,6 +112,26 @@ export default function MaterialCostSection(props: {
|
||||
return updates;
|
||||
};
|
||||
|
||||
// 获取费用项目列表
|
||||
useEffect(() => {
|
||||
const fetchCostItems = async () => {
|
||||
try {
|
||||
const { data } = await business.costItem.listCostItem({
|
||||
costItemListQry: {
|
||||
status: true,
|
||||
showInEntry: true,
|
||||
costType: "PACKAGING_MATERIALS", // 只获取辅料费用项目
|
||||
},
|
||||
});
|
||||
setCostItems(data.data || []);
|
||||
} catch (error) {
|
||||
console.error("获取费用项目列表失败:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchCostItems();
|
||||
}, []);
|
||||
|
||||
// 辅料费(商标费和网套费)
|
||||
const packagingMaterials =
|
||||
purchaseOrderVO.orderCostList?.filter(
|
||||
@ -230,7 +281,7 @@ export default function MaterialCostSection(props: {
|
||||
<Text className="text-sm text-gray-500">元</Text>
|
||||
</View>
|
||||
<View className="relative flex">
|
||||
<Text className="text-red-500 border-red-500 w-full border-b-2 pb-2 text-3xl font-bold focus:outline-none">
|
||||
<Text className="w-full border-b-2 border-red-500 pb-2 text-3xl font-bold text-red-500 focus:outline-none">
|
||||
{amount.toFixed(2) || "0.00"}
|
||||
</Text>
|
||||
</View>
|
||||
@ -268,8 +319,292 @@ export default function MaterialCostSection(props: {
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
|
||||
{!readOnly && (
|
||||
<Button
|
||||
type={"primary"}
|
||||
block
|
||||
size={"large"}
|
||||
onClick={() => setShowAddCostPopup(true)}
|
||||
>
|
||||
新增其他辅料费用
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 新增其他辅料费 */}
|
||||
<Popup
|
||||
visible={showAddCostPopup}
|
||||
position="bottom"
|
||||
title="新增其他辅料费用"
|
||||
onClose={() => setShowAddCostPopup(false)}
|
||||
onOverlayClick={() => setShowAddCostPopup(false)}
|
||||
lockScroll
|
||||
>
|
||||
<View className="flex flex-col gap-3 p-2.5">
|
||||
{/* 辅料项目 */}
|
||||
<View className="text-neutral-darkest text-sm font-medium">
|
||||
辅料项目
|
||||
</View>
|
||||
<View
|
||||
className="border-neutral-base relative flex h-10 w-full items-center rounded-md border border-solid"
|
||||
onClick={() =>
|
||||
setPickerVisible((prev) => ({ ...prev, costItem: true }))
|
||||
}
|
||||
>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="请选择辅料项目"
|
||||
value={newCostData.name || ""}
|
||||
disabled
|
||||
/>
|
||||
<Icon name="chevron-down" className="absolute -right-1 mr-4" />
|
||||
</View>
|
||||
<Picker
|
||||
title="请选择辅料项目"
|
||||
visible={pickerVisible.costItem}
|
||||
options={[
|
||||
costItems
|
||||
.filter((item) => {
|
||||
// 检查该项目是否已经被选择
|
||||
return !packagingMaterials.some(
|
||||
(hc) => hc.itemId === item.itemId,
|
||||
);
|
||||
})
|
||||
.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.itemId,
|
||||
})),
|
||||
]}
|
||||
onConfirm={(_, values) => {
|
||||
const selectedValue = values[0] as string;
|
||||
const selectedItem = costItems.find(
|
||||
(item) => item.itemId === selectedValue,
|
||||
);
|
||||
if (selectedItem) {
|
||||
setNewCostData((prev) => ({
|
||||
...prev,
|
||||
itemId: selectedValue,
|
||||
name: selectedItem.name,
|
||||
quantity: selectedItem.requireQuantityAndPrice ? 0 : 1, // 数量
|
||||
unit: selectedItem.requireQuantityAndPrice
|
||||
? selectedItem.unit
|
||||
: "元", // 单位
|
||||
unitPrice: "", // 单价
|
||||
amount: "", // 金额
|
||||
requireQuantityAndPrice: selectedItem.requireQuantityAndPrice,
|
||||
}));
|
||||
}
|
||||
setPickerVisible((prev) => ({ ...prev, costItem: false }));
|
||||
}}
|
||||
onCancel={() =>
|
||||
setPickerVisible((prev) => ({ ...prev, costItem: false }))
|
||||
}
|
||||
onClose={() =>
|
||||
setPickerVisible((prev) => ({ ...prev, costItem: false }))
|
||||
}
|
||||
/>
|
||||
|
||||
{/* 数量输入 */}
|
||||
{newCostData.itemId && newCostData.requireQuantityAndPrice && (
|
||||
<>
|
||||
<View className="text-neutral-darkest text-sm font-medium">
|
||||
数量
|
||||
</View>
|
||||
<View className="border-neutral-base flex flex-row items-center rounded-md border border-solid">
|
||||
<Input
|
||||
className="placeholder:text-neutral-dark flex-1"
|
||||
placeholder="请输入数量"
|
||||
type="digit"
|
||||
value={newCostData.quantity?.toString() || ""}
|
||||
onChange={(value) => {
|
||||
const numValue = validatePrice(value);
|
||||
if (numValue !== undefined) {
|
||||
setNewCostData((prev) => ({
|
||||
...prev,
|
||||
quantity: numValue as any,
|
||||
}));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<View className="mr-2">{newCostData.unit}</View>
|
||||
</View>
|
||||
|
||||
{/* 单价输入 */}
|
||||
<View className="text-neutral-darkest text-sm font-medium">
|
||||
单价
|
||||
</View>
|
||||
<View className="border-neutral-base flex flex-row items-center rounded-md border border-solid">
|
||||
<Input
|
||||
className="placeholder:text-neutral-dark flex-1"
|
||||
placeholder="请输入单价"
|
||||
type="digit"
|
||||
value={newCostData.unitPrice?.toString() || ""}
|
||||
onChange={(value) => {
|
||||
const numValue = validatePrice(value);
|
||||
if (numValue !== undefined) {
|
||||
setNewCostData((prev) => ({
|
||||
...prev,
|
||||
unitPrice: numValue as any,
|
||||
}));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<View className="mr-2">元</View>
|
||||
</View>
|
||||
|
||||
{/* 金额展示 */}
|
||||
<View className="flex items-center justify-between rounded-md bg-gray-100 p-3">
|
||||
<View className="text-neutral-darkest text-sm font-medium">
|
||||
金额
|
||||
</View>
|
||||
<View className="text-neutral-darkest text-sm font-medium">
|
||||
{(
|
||||
Number(newCostData.quantity || 0) *
|
||||
Number(newCostData.unitPrice || 0)
|
||||
).toFixed(2)}{" "}
|
||||
元
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
|
||||
{newCostData.itemId && !newCostData.requireQuantityAndPrice && (
|
||||
<>
|
||||
<View className="text-neutral-darkest text-sm font-medium">
|
||||
金额
|
||||
</View>
|
||||
<View className="border-neutral-base flex flex-row items-center rounded-md border border-solid">
|
||||
<Input
|
||||
className="placeholder:text-neutral-dark flex-1"
|
||||
placeholder="请输入金额"
|
||||
type="digit"
|
||||
value={newCostData.amount?.toString() || ""}
|
||||
onChange={(value) => {
|
||||
const numValue = validatePrice(value);
|
||||
if (numValue !== undefined) {
|
||||
setNewCostData((prev) => ({
|
||||
...prev,
|
||||
unitPrice: numValue as any,
|
||||
amount: numValue as any,
|
||||
}));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<View className="mr-2">元</View>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
<View className="flex w-full flex-col bg-white">
|
||||
<View className="flex flex-row gap-2 p-3">
|
||||
<View className="flex-1">
|
||||
<Button
|
||||
size="large"
|
||||
block
|
||||
type="default"
|
||||
onClick={() => {
|
||||
setShowAddCostPopup(false);
|
||||
|
||||
// 重置表单
|
||||
setNewCostData({
|
||||
itemId: "",
|
||||
name: "", // 费用名称
|
||||
quantity: 0, // 数量
|
||||
unit: "", // 单位
|
||||
unitPrice: "", // 单价
|
||||
amount: "", // 金额
|
||||
requireQuantityAndPrice: false,
|
||||
});
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
</View>
|
||||
<View className="flex-1">
|
||||
<Button
|
||||
size="large"
|
||||
block
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
// 检查必填项
|
||||
if (!newCostData.itemId) {
|
||||
console.log("请选择辅料项目");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查数量和单价或金额
|
||||
if (
|
||||
newCostData.requireQuantityAndPrice &&
|
||||
(!newCostData.quantity || !newCostData.unitPrice)
|
||||
) {
|
||||
console.log("请填写数量和单价");
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!newCostData.requireQuantityAndPrice &&
|
||||
!newCostData.amount
|
||||
) {
|
||||
console.log("请填写金额");
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建新的费用项
|
||||
const newOrderCost: BusinessAPI.OrderCost = {
|
||||
orderCostId: generateShortId(),
|
||||
itemId: newCostData.itemId || "",
|
||||
name: newCostData.name,
|
||||
price: Number(
|
||||
newCostData.requireQuantityAndPrice
|
||||
? newCostData.unitPrice || 0
|
||||
: newCostData.amount || 0,
|
||||
),
|
||||
unit: newCostData.unit,
|
||||
count: Number(
|
||||
newCostData.requireQuantityAndPrice
|
||||
? newCostData.quantity || 1
|
||||
: 1,
|
||||
),
|
||||
payerType: "US",
|
||||
costType: "PACKAGING_MATERIALS",
|
||||
principal: "",
|
||||
};
|
||||
|
||||
// 更新purchaseOrderVO,将新费用添加到orderCostList中
|
||||
if (onChange) {
|
||||
const updatedOrderCostList = [
|
||||
...(purchaseOrderVO.orderCostList || []),
|
||||
newOrderCost,
|
||||
];
|
||||
const newPurchaseOrderVO = {
|
||||
...purchaseOrderVO,
|
||||
orderCostList: updatedOrderCostList,
|
||||
};
|
||||
onChange(newPurchaseOrderVO);
|
||||
}
|
||||
|
||||
setShowAddCostPopup(false);
|
||||
// 重置表单
|
||||
setNewCostData({
|
||||
itemId: "",
|
||||
name: "", // 费用名称
|
||||
quantity: 0, // 数量
|
||||
unit: "", // 单位
|
||||
unitPrice: "", // 单价
|
||||
amount: "", // 金额
|
||||
requireQuantityAndPrice: false,
|
||||
});
|
||||
}}
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<SafeArea position="bottom" />
|
||||
</Popup>
|
||||
|
||||
{/* 辅料费编辑弹窗 */}
|
||||
{packagingMaterials.map((item) => (
|
||||
<Popup
|
||||
|
||||
@ -151,7 +151,7 @@ export default function PackagingCostSection(props: {
|
||||
onChange(newPurchaseOrderVO as any);
|
||||
}
|
||||
}
|
||||
}, [purchaseOrderVO.orderCostList]);
|
||||
}, [purchaseOrderVO.orderCostList, onChange, fixedCosts]);
|
||||
|
||||
// 当editValues发生变化时,更新purchaseOrderVO
|
||||
useEffect(() => {
|
||||
@ -204,7 +204,7 @@ export default function PackagingCostSection(props: {
|
||||
|
||||
return (
|
||||
<>
|
||||
<View className="grid grid-cols-1 gap-2.5">
|
||||
<View className="flex flex-col gap-2.5">
|
||||
{/* 固定费用 */}
|
||||
{fixedCosts.map((item, index) => {
|
||||
// 初始化编辑值
|
||||
@ -212,7 +212,7 @@ export default function PackagingCostSection(props: {
|
||||
|
||||
return (
|
||||
<View
|
||||
className="flex items-center justify-between gap-2.5 p-2.5"
|
||||
className="flex items-center justify-between gap-2.5"
|
||||
key={item.orderCostId}
|
||||
onClick={() =>
|
||||
setVisiblePopup((prev) => ({
|
||||
@ -254,7 +254,7 @@ export default function PackagingCostSection(props: {
|
||||
|
||||
return (
|
||||
<View
|
||||
className="flex items-center justify-between gap-2.5 p-2.5"
|
||||
className="flex items-center justify-between gap-2.5"
|
||||
key={item.orderCostId}
|
||||
onClick={() =>
|
||||
setVisiblePopup((prev) => ({
|
||||
@ -283,7 +283,6 @@ export default function PackagingCostSection(props: {
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
|
||||
{!readOnly && (
|
||||
<Button
|
||||
@ -295,6 +294,7 @@ export default function PackagingCostSection(props: {
|
||||
新增其他费用
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 新增其他费用*/}
|
||||
<Popup
|
||||
@ -311,33 +311,19 @@ export default function PackagingCostSection(props: {
|
||||
<View className="text-neutral-darkest text-sm font-medium">
|
||||
费用类型
|
||||
</View>
|
||||
<View className="flex flex-row gap-4">
|
||||
{costTypeOptions.map((option) => (
|
||||
<View
|
||||
className="border-neutral-base relative flex h-10 w-full items-center rounded-md border border-solid"
|
||||
onClick={() =>
|
||||
setPickerVisible((prev) => ({ ...prev, costType: true }))
|
||||
}
|
||||
>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="请选择费用类型"
|
||||
value={
|
||||
costTypeOptions.find(
|
||||
(option) => option.value === newCostData.costType,
|
||||
)?.label || ""
|
||||
}
|
||||
disabled
|
||||
/>
|
||||
<Icon name="chevron-down" className="absolute -right-1 mr-4" />
|
||||
</View>
|
||||
<Picker
|
||||
title="请选择费用类型"
|
||||
visible={pickerVisible.costType}
|
||||
options={[costTypeOptions]}
|
||||
onConfirm={(_, values) => {
|
||||
const selectedValue = values[0] as string;
|
||||
key={option.value}
|
||||
className={`flex flex-1 flex-row items-center justify-center rounded-md py-2 ${
|
||||
newCostData.costType === option.value
|
||||
? "bg-blue-100 text-blue-600"
|
||||
: "border border-gray-300"
|
||||
}`}
|
||||
onClick={() => {
|
||||
setNewCostData((prev) => ({
|
||||
...prev,
|
||||
costType: selectedValue,
|
||||
costType: option.value,
|
||||
itemId: "",
|
||||
name: "",
|
||||
payee: "",
|
||||
@ -345,15 +331,12 @@ export default function PackagingCostSection(props: {
|
||||
unitPrice: "",
|
||||
amount: "",
|
||||
}));
|
||||
setPickerVisible((prev) => ({ ...prev, costType: false }));
|
||||
}}
|
||||
onCancel={() =>
|
||||
setPickerVisible((prev) => ({ ...prev, costType: false }))
|
||||
}
|
||||
onClose={() =>
|
||||
setPickerVisible((prev) => ({ ...prev, costType: false }))
|
||||
}
|
||||
/>
|
||||
>
|
||||
{option.label}
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* 固定费用子类型 */}
|
||||
{newCostData.costType === "FIXED_COST" && (
|
||||
@ -381,7 +364,14 @@ export default function PackagingCostSection(props: {
|
||||
<Picker
|
||||
title="请选择固定费用类型"
|
||||
visible={pickerVisible.fixedCost}
|
||||
options={[fixedCostOptions]}
|
||||
options={[
|
||||
fixedCostOptions.filter((option) => {
|
||||
// 检查该固定费用类型是否已存在于fixedCosts中
|
||||
return !fixedCosts.some(
|
||||
(cost) => cost.name === option.label,
|
||||
);
|
||||
}),
|
||||
]}
|
||||
onConfirm={(_, values) => {
|
||||
const selectedValue = values[0] as string;
|
||||
const selectedItem = fixedCostOptions.find(
|
||||
@ -479,7 +469,21 @@ export default function PackagingCostSection(props: {
|
||||
size="large"
|
||||
block
|
||||
type="default"
|
||||
onClick={() => setShowAddCostPopup(false)}
|
||||
onClick={() => {
|
||||
setShowAddCostPopup(false);
|
||||
// 重置表单
|
||||
setNewCostData({
|
||||
payerType: "",
|
||||
principal: "",
|
||||
costType: "",
|
||||
itemId: generateShortId(),
|
||||
name: "",
|
||||
payee: "",
|
||||
quantity: "",
|
||||
unitPrice: "",
|
||||
amount: "",
|
||||
});
|
||||
}}
|
||||
>
|
||||
取消
|
||||
</Button>
|
||||
|
||||
@ -2265,7 +2265,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
type="default"
|
||||
size="large"
|
||||
block
|
||||
className="max-w-[150px] flex-1"
|
||||
onClick={handleDownload}
|
||||
>
|
||||
下载文档
|
||||
@ -2279,7 +2278,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
type="default"
|
||||
size="large"
|
||||
block
|
||||
className="max-w-[150px] flex-1"
|
||||
onClick={handleView}
|
||||
>
|
||||
查看文档
|
||||
@ -2290,7 +2288,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
className="max-w-[150px] flex-1"
|
||||
onClick={handleShare}
|
||||
>
|
||||
转发好友
|
||||
@ -0,0 +1,4 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: "采购底单单据生成",
|
||||
navigationBarBackgroundColor: "#fff",
|
||||
});
|
||||
2390
packages/app-client/src/pages/delivery/document/purchase.tsx
Normal file
2390
packages/app-client/src/pages/delivery/document/purchase.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@ -23,7 +23,12 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
const [state, setState] = useState<BusinessAPI.ShipOrderPageQry["state"]>();
|
||||
const [dealerVO, setDealerVO] = useState<BusinessAPI.DealerVO>();
|
||||
|
||||
const [deliveryTemplate, setDeliveryTemplate] = useState<BusinessAPI.DealerVO['deliveryTemplate']>();
|
||||
const [canGenerateDocuments, setCanGenerateDocuments] = useState({
|
||||
shipDocument: false,
|
||||
purchaseDocument: false,
|
||||
});
|
||||
const [deliveryTemplate, setDeliveryTemplate] =
|
||||
useState<BusinessAPI.DealerVO["deliveryTemplate"]>();
|
||||
|
||||
// 控制弹窗显示状态
|
||||
const [popupVisible, setPopupVisible] = useState(false);
|
||||
@ -31,6 +36,66 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
const [currentShipOrder, setCurrentShipOrder] =
|
||||
useState<BusinessAPI.ShipOrderVO | null>(null);
|
||||
|
||||
// 生成发货单据
|
||||
const generateShipDocument = async () => {
|
||||
if (!currentShipOrder?.shipOrderId) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "未找到关联的发货单",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 跳转到发货单据生成页面
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/delivery/document/delivery", {
|
||||
shipOrderId: currentShipOrder.shipOrderId,
|
||||
}),
|
||||
success: () => {
|
||||
setPopupVisible(false);
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "跳转发货单据页面失败",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 生成采购底单单据
|
||||
const 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: {
|
||||
@ -60,7 +125,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
},
|
||||
render: () => (
|
||||
<>
|
||||
{/* 生成发货单据弹窗 */}
|
||||
{/* 生成单据弹窗 */}
|
||||
<Popup
|
||||
duration={150}
|
||||
style={{
|
||||
@ -69,7 +134,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
visible={popupVisible}
|
||||
className={"flex flex-col"}
|
||||
position="bottom"
|
||||
title={"生成发货单据"}
|
||||
title={"生成单据"}
|
||||
onClose={() => setPopupVisible(false)}
|
||||
onOverlayClick={() => setPopupVisible(false)}
|
||||
lockScroll
|
||||
@ -104,47 +169,89 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
</View>
|
||||
)}
|
||||
|
||||
{deliveryTemplate ? (
|
||||
{currentShipOrder && (
|
||||
<View className="border-t border-gray-200 pt-2.5">
|
||||
<View className="mb-2">
|
||||
<Text className="text-lg font-semibold">操作确认</Text>
|
||||
<Text className="text-lg font-semibold">快捷生成单据</Text>
|
||||
</View>
|
||||
<View className="text-sm text-gray-600">
|
||||
确认生成发货单据吗?生成后可以下载或转发给好友。
|
||||
</View>
|
||||
</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>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<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
|
||||
size={"large"}
|
||||
block
|
||||
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
|
||||
size={"large"}
|
||||
block
|
||||
disabled={!deliveryTemplate}
|
||||
type="primary"
|
||||
onClick={confirmGenerateDocument}
|
||||
>
|
||||
前往生成
|
||||
关闭
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<SafeArea position={"bottom"} />
|
||||
</View>
|
||||
@ -194,7 +301,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
});
|
||||
|
||||
// 生成发货单据
|
||||
const generateShipDocument = async (shipOrderVO: BusinessAPI.ShipOrderVO) => {
|
||||
const generateDocument = async (shipOrderVO: BusinessAPI.ShipOrderVO) => {
|
||||
setCurrentShipOrder(shipOrderVO);
|
||||
|
||||
const { data: dealerData } = await business.dealer.showDealer({
|
||||
@ -205,40 +312,24 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
|
||||
if (dealerData.success) {
|
||||
const deliveryTemplate = dealerData.data?.deliveryTemplate;
|
||||
setDeliveryTemplate(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);
|
||||
};
|
||||
|
||||
// 确认生成发货单据
|
||||
const confirmGenerateDocument = () => {
|
||||
if (!currentShipOrder?.shipOrderId) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "未找到关联的发货单",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 跳转到发货单据生成页面
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/delivery/document", {
|
||||
shipOrderId: currentShipOrder.shipOrderId,
|
||||
}),
|
||||
});
|
||||
setPopupVisible(false);
|
||||
} catch (error) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "跳转发货单据页面失败",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<PageList<BusinessAPI.ShipOrderVO, BusinessAPI.ShipOrderPageQry>
|
||||
rowId={"shipOrderId"}
|
||||
@ -323,11 +414,11 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
type={"primary"}
|
||||
size={"small"}
|
||||
onClick={async (e) => {
|
||||
await generateShipDocument(shipOrderVO);
|
||||
await generateDocument(shipOrderVO);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
生成发货单据
|
||||
生成单据
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@ -1,16 +1,9 @@
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
import { View, Text } from "@tarojs/components";
|
||||
import { Text, View } from "@tarojs/components";
|
||||
import { useEffect, useState } from "react";
|
||||
import { auth } from "@/services";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
Image,
|
||||
Popup,
|
||||
SafeArea,
|
||||
Toast,
|
||||
} from "@nutui/nutui-react-taro";
|
||||
import { Button, Dialog, Image, Popup, Toast } from "@nutui/nutui-react-taro";
|
||||
import dayjs from "dayjs";
|
||||
import Taro from "@tarojs/taro";
|
||||
import buildUrl from "@/utils/buildUrl";
|
||||
@ -382,8 +375,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
确认切换
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
<SafeArea position={"bottom"} />
|
||||
</Popup>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -15,10 +15,11 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
useState<BusinessAPI.PurchaseOrderVO>();
|
||||
const [canGenerateDocuments, setCanGenerateDocuments] = useState({
|
||||
shipDocument: false,
|
||||
costDocument: false,
|
||||
purchaseDocument: false,
|
||||
});
|
||||
const [shipOrder, setShipOrder] = useState<BusinessAPI.ShipOrderVO>();
|
||||
const [deliveryTemplate, setDeliveryTemplate] = useState<BusinessAPI.DealerVO['deliveryTemplate']>();
|
||||
const [deliveryTemplate, setDeliveryTemplate] =
|
||||
useState<BusinessAPI.DealerVO["deliveryTemplate"]>();
|
||||
|
||||
const init = async (orderId: string) => {
|
||||
setLoading(true);
|
||||
@ -59,7 +60,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
setDeliveryTemplate(dealerData.data.deliveryTemplate);
|
||||
setCanGenerateDocuments({
|
||||
shipDocument: documentTypes.includes("delivery"),
|
||||
costDocument: documentTypes.includes("cost"),
|
||||
purchaseDocument: documentTypes.includes("purchase"),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -104,7 +105,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
try {
|
||||
// 跳转到发货单据生成页面
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/delivery/document", {
|
||||
url: buildUrl("/pages/delivery/document/delivery", {
|
||||
shipOrderId: shipOrder.shipOrderId,
|
||||
}),
|
||||
});
|
||||
@ -117,22 +118,40 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
}
|
||||
};
|
||||
|
||||
// 生成成本单
|
||||
const generateCostDocument = () => {
|
||||
if (!canGenerateDocuments.costDocument) {
|
||||
// 生成采购底单单据
|
||||
const generatePurchaseDocument = () => {
|
||||
if (!canGenerateDocuments.purchaseDocument) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "当前经销商不支持生成成本单",
|
||||
content: "当前经销商不支持生成采购底单单据",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shipOrder?.shipOrderId) {
|
||||
Toast.show("toast", {
|
||||
icon: "success",
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "成本单生成成功",
|
||||
content: "未找到关联的发货单",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 跳转到发货单据生成页面
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/delivery/document/purchase", {
|
||||
shipOrderId: shipOrder.shipOrderId,
|
||||
}),
|
||||
});
|
||||
} catch (error) {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "提示",
|
||||
content: "跳转发货单据页面失败",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@ -189,14 +208,15 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{deliveryTemplate ? (
|
||||
{shipOrder && (
|
||||
<View className="border-t border-gray-200 pt-2.5">
|
||||
<View className="mb-2">
|
||||
<Text className="text-lg font-semibold">快捷生成单据</Text>
|
||||
</View>
|
||||
|
||||
<View className="flex flex-col gap-3">
|
||||
{canGenerateDocuments.shipDocument && shipOrder && (
|
||||
{canGenerateDocuments.shipDocument &&
|
||||
(deliveryTemplate ? (
|
||||
<Button
|
||||
type="primary"
|
||||
size={"xlarge"}
|
||||
@ -205,37 +225,23 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
>
|
||||
生成发货单据
|
||||
</Button>
|
||||
)}
|
||||
) : (
|
||||
<View className="mt-2.5 text-center text-sm text-red-500">
|
||||
未找到关联的发货单模板,请联系管理员
|
||||
</View>
|
||||
))}
|
||||
|
||||
{canGenerateDocuments.costDocument && (
|
||||
{canGenerateDocuments.purchaseDocument && shipOrder && (
|
||||
<Button
|
||||
type="default"
|
||||
size={"xlarge"}
|
||||
block
|
||||
onClick={generateCostDocument}
|
||||
onClick={generatePurchaseDocument}
|
||||
>
|
||||
生成成本单
|
||||
生成采购底单单据
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{!shipOrder && (
|
||||
<View className="mt-2.5 text-center text-sm text-red-500">
|
||||
未找到关联的发货单,请联系管理员
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
) : (
|
||||
<View className="border-t border-gray-200 pt-2.5">
|
||||
<View className="mb-2">
|
||||
<Text className="text-lg font-semibold">快捷生成单据</Text>
|
||||
</View>
|
||||
|
||||
<View className="flex flex-col gap-3">
|
||||
<View className="mt-2.5 text-center text-sm text-red-500">
|
||||
未找到关联的发货单模板,请联系管理员
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@ -139,7 +139,8 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
const orderCostList1 = purchaseOrder.orderCostList.map(
|
||||
(item: CostItem) => ({
|
||||
...item,
|
||||
selected: true,
|
||||
// 设置默认选中,
|
||||
selected: item.count > 0,
|
||||
}),
|
||||
) as any;
|
||||
setOrderCostList(orderCostList1);
|
||||
@ -308,6 +309,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
orderId: orderId,
|
||||
active: active,
|
||||
orderSupplierList: purchaseOrder.orderSupplierList,
|
||||
orderCostList: purchaseOrder.orderCostList,
|
||||
});
|
||||
|
||||
if (data.success) {
|
||||
@ -611,6 +613,42 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
}),
|
||||
]);
|
||||
}}
|
||||
changeProduct={(productVO: BusinessAPI.ProductVO) => {
|
||||
setOrderSupplierList([
|
||||
...orderSupplierList.map((item: SupplierVO) => {
|
||||
item.productId = productVO.productId;
|
||||
item.productName = productVO.name;
|
||||
return item;
|
||||
}),
|
||||
]);
|
||||
setPurchaseOrder((prev) => {
|
||||
return {
|
||||
...prev!,
|
||||
orderCostList: [
|
||||
...(prev?.orderCostList?.filter((item) => {
|
||||
return (
|
||||
item.costType !== "WORKER_ADVANCE" &&
|
||||
item.costType !== "PRODUCTION_ADVANCE"
|
||||
);
|
||||
}) || []),
|
||||
...(productVO.costItemVOList?.map((item) => {
|
||||
return {
|
||||
orderCostId: generateShortId(),
|
||||
orderId: purchaseOrder?.orderId,
|
||||
itemId: item.itemId,
|
||||
name: item.name,
|
||||
price: item.price,
|
||||
unit: item.unit,
|
||||
count: 0,
|
||||
payerType: "US" as any,
|
||||
principal: "",
|
||||
costType: item.costType,
|
||||
};
|
||||
}) || []),
|
||||
],
|
||||
};
|
||||
});
|
||||
}}
|
||||
isFirst={index === 0}
|
||||
key={item.orderSupplierId}
|
||||
ref={(ref) => {
|
||||
@ -778,7 +816,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
const selectedIndex = orderSupplierList.findIndex(
|
||||
(supplier) => supplier.selected,
|
||||
);
|
||||
console.log("selectedIndex", selectedIndex);
|
||||
if (
|
||||
selectedIndex !== -1 &&
|
||||
orderPackageRefs.current[selectedIndex]?.validate()
|
||||
|
||||
@ -24,7 +24,6 @@ import {
|
||||
MaterialCostSection,
|
||||
PackageInfoSection,
|
||||
PackagingCostSection,
|
||||
PurchaseCostInfoSection,
|
||||
PurchaseOrderRejectApprove,
|
||||
RebateCalcSection,
|
||||
State,
|
||||
@ -70,13 +69,13 @@ const sections = {
|
||||
// containerClass: "border-l-8 border-l-purple-500",
|
||||
// contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto",
|
||||
// },
|
||||
// 采购成本
|
||||
purchaseCostInfo: {
|
||||
component: PurchaseCostInfoSection,
|
||||
title: "采购成本",
|
||||
containerClass: "border-l-8 border-l-red-500",
|
||||
contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto",
|
||||
},
|
||||
// // 采购成本
|
||||
// purchaseCostInfo: {
|
||||
// component: PurchaseCostInfoSection,
|
||||
// title: "采购成本",
|
||||
// containerClass: "border-l-8 border-l-red-500",
|
||||
// contentClass: "p-4 bg-white rounded-b-lg shadow-sm overflow-x-auto",
|
||||
// },
|
||||
// 包装纸箱费
|
||||
packageInfo: {
|
||||
component: PackageInfoSection,
|
||||
|
||||
@ -7,6 +7,7 @@ import * as supplier from "./supplier";
|
||||
import * as shipOrder from "./shipOrder";
|
||||
import * as setting from "./setting";
|
||||
import * as purchaseOrder from "./purchaseOrder";
|
||||
import * as product from "./product";
|
||||
import * as platform from "./platform";
|
||||
import * as menu from "./menu";
|
||||
import * as material from "./material";
|
||||
@ -34,6 +35,7 @@ export default {
|
||||
shipOrder,
|
||||
setting,
|
||||
purchaseOrder,
|
||||
product,
|
||||
platform,
|
||||
menu,
|
||||
material,
|
||||
|
||||
156
packages/app-client/src/services/business/product.ts
Normal file
156
packages/app-client/src/services/business/product.ts
Normal file
@ -0,0 +1,156 @@
|
||||
// @ts-ignore
|
||||
/* eslint-disable */
|
||||
import request from "../request";
|
||||
|
||||
/** 创建产品 POST /operation/createProduct */
|
||||
export async function createProduct(
|
||||
body: BusinessAPI.ProductCreateCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.SingleResponseProductVO>(
|
||||
"/operation/createProduct",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** 产品删除 DELETE /operation/destroyProduct */
|
||||
export async function destroyProduct(
|
||||
body: BusinessAPI.ProductDestroyCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.Response>("/operation/destroyProduct", {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 产品拖拽排序 PUT /operation/dragProduct */
|
||||
export async function dragProduct(
|
||||
body: BusinessAPI.ProductDragCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.Response>("/operation/dragProduct", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 产品拖拽排序 PATCH /operation/dragProduct */
|
||||
export async function dragProduct1(
|
||||
body: BusinessAPI.ProductDragCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.Response>("/operation/dragProduct", {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 产品列表 GET /operation/listProduct */
|
||||
export async function listProduct(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: BusinessAPI.listProductParams,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.MultiResponseProductVO>("/operation/listProduct", {
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
productListQry: undefined,
|
||||
...params["productListQry"],
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 产品列表 GET /operation/pageProduct */
|
||||
export async function pageProduct(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: BusinessAPI.pageProductParams,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.PageResponseProductVO>("/operation/pageProduct", {
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
productPageQry: undefined,
|
||||
...params["productPageQry"],
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 产品详情 GET /operation/showProduct */
|
||||
export async function showProduct(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: BusinessAPI.showProductParams,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.SingleResponseProductVO>(
|
||||
"/operation/showProduct",
|
||||
{
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
productShowQry: undefined,
|
||||
...params["productShowQry"],
|
||||
},
|
||||
...(options || {}),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** 产品更新 PUT /operation/updateProduct */
|
||||
export async function updateProduct(
|
||||
body: BusinessAPI.ProductUpdateCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.SingleResponseProductVO>(
|
||||
"/operation/updateProduct",
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** 产品更新 PATCH /operation/updateProduct */
|
||||
export async function updateProduct1(
|
||||
body: BusinessAPI.ProductUpdateCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.SingleResponseProductVO>(
|
||||
"/operation/updateProduct",
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -798,12 +798,14 @@ declare namespace BusinessAPI {
|
||||
type CostItemCreateCmd = {
|
||||
/** 项目ID */
|
||||
itemId: string;
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用 */
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用;5_工头垫付;6_产地垫付 */
|
||||
costType:
|
||||
| "PACKAGING_MATERIALS"
|
||||
| "HUMAN_COST"
|
||||
| "OTHER_COST"
|
||||
| "FIXED_COST";
|
||||
| "FIXED_COST"
|
||||
| "WORKER_ADVANCE"
|
||||
| "PRODUCTION_ADVANCE";
|
||||
/** 项目名称 */
|
||||
name: string;
|
||||
/** 单位 */
|
||||
@ -812,6 +814,8 @@ declare namespace BusinessAPI {
|
||||
price: number;
|
||||
/** 是否在录入时显示 */
|
||||
showInEntry: boolean;
|
||||
/** 是否需要填写数量和单价 */
|
||||
requireQuantityAndPrice: boolean;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 状态:1_启用;0_禁用 */
|
||||
@ -837,12 +841,14 @@ declare namespace BusinessAPI {
|
||||
status?: boolean;
|
||||
/** 费用项目ID */
|
||||
itemId?: string;
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用 */
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用;5_工头垫付;6_产地垫付 */
|
||||
costType?:
|
||||
| "PACKAGING_MATERIALS"
|
||||
| "HUMAN_COST"
|
||||
| "OTHER_COST"
|
||||
| "FIXED_COST";
|
||||
| "FIXED_COST"
|
||||
| "WORKER_ADVANCE"
|
||||
| "PRODUCTION_ADVANCE";
|
||||
/** 是否在录入时显示 */
|
||||
showInEntry?: boolean;
|
||||
};
|
||||
@ -864,12 +870,14 @@ declare namespace BusinessAPI {
|
||||
status?: boolean;
|
||||
/** 费用项目ID */
|
||||
itemId?: string;
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用 */
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用;5_工头垫付;6_产地垫付 */
|
||||
costType?:
|
||||
| "PACKAGING_MATERIALS"
|
||||
| "HUMAN_COST"
|
||||
| "OTHER_COST"
|
||||
| "FIXED_COST";
|
||||
| "FIXED_COST"
|
||||
| "WORKER_ADVANCE"
|
||||
| "PRODUCTION_ADVANCE";
|
||||
/** 项目名称 */
|
||||
name?: string;
|
||||
offset?: number;
|
||||
@ -885,12 +893,14 @@ declare namespace BusinessAPI {
|
||||
type CostItemUpdateCmd = {
|
||||
/** 费用项目ID */
|
||||
itemId: string;
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用 */
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用;5_工头垫付;6_产地垫付 */
|
||||
costType:
|
||||
| "PACKAGING_MATERIALS"
|
||||
| "HUMAN_COST"
|
||||
| "OTHER_COST"
|
||||
| "FIXED_COST";
|
||||
| "FIXED_COST"
|
||||
| "WORKER_ADVANCE"
|
||||
| "PRODUCTION_ADVANCE";
|
||||
/** 项目名称 */
|
||||
name: string;
|
||||
/** 单位 */
|
||||
@ -899,6 +909,8 @@ declare namespace BusinessAPI {
|
||||
price: number;
|
||||
/** 是否在录入时显示 */
|
||||
showInEntry: boolean;
|
||||
/** 是否需要填写数量和单价 */
|
||||
requireQuantityAndPrice: boolean;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 状态:1_启用;0_禁用 */
|
||||
@ -908,12 +920,14 @@ declare namespace BusinessAPI {
|
||||
type CostItemVO = {
|
||||
/** 项目ID */
|
||||
itemId: string;
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用 */
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用;5_工头垫付;6_产地垫付 */
|
||||
costType:
|
||||
| "PACKAGING_MATERIALS"
|
||||
| "HUMAN_COST"
|
||||
| "OTHER_COST"
|
||||
| "FIXED_COST";
|
||||
| "FIXED_COST"
|
||||
| "WORKER_ADVANCE"
|
||||
| "PRODUCTION_ADVANCE";
|
||||
/** 项目名称 */
|
||||
name: string;
|
||||
/** 单位 */
|
||||
@ -922,6 +936,8 @@ declare namespace BusinessAPI {
|
||||
price: number;
|
||||
/** 是否在录入时显示 */
|
||||
showInEntry: boolean;
|
||||
/** 是否需要填写数量和单价 */
|
||||
requireQuantityAndPrice: boolean;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 状态:1_启用;0_禁用 */
|
||||
@ -1859,6 +1875,10 @@ declare namespace BusinessAPI {
|
||||
platformListQry: PlatformListQry;
|
||||
};
|
||||
|
||||
type listProductParams = {
|
||||
productListQry: ProductListQry;
|
||||
};
|
||||
|
||||
type listPurchaseOrderParams = {
|
||||
purchaseOrderListQry: PurchaseOrderListQry;
|
||||
};
|
||||
@ -2251,6 +2271,15 @@ declare namespace BusinessAPI {
|
||||
notEmpty?: boolean;
|
||||
};
|
||||
|
||||
type MultiResponseProductVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
errMessage?: string;
|
||||
data?: ProductVO[];
|
||||
empty?: boolean;
|
||||
notEmpty?: boolean;
|
||||
};
|
||||
|
||||
type MultiResponsePurchaseOrderVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
@ -2352,15 +2381,17 @@ declare namespace BusinessAPI {
|
||||
/** 数量 */
|
||||
count: number;
|
||||
/** 付款方类型:1-我方,2-对方 */
|
||||
payerType: "US" | "OTHER";
|
||||
payerType?: "US" | "OTHER";
|
||||
/** 负责人 */
|
||||
principal?: string;
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用 */
|
||||
/** 费用类型:1_包装材料;2_人工费用;3_其他费用;4_固定费用;5_工头垫付;6_产地垫付 */
|
||||
costType:
|
||||
| "PACKAGING_MATERIALS"
|
||||
| "HUMAN_COST"
|
||||
| "OTHER_COST"
|
||||
| "FIXED_COST";
|
||||
| "FIXED_COST"
|
||||
| "WORKER_ADVANCE"
|
||||
| "PRODUCTION_ADVANCE";
|
||||
};
|
||||
|
||||
type OrderDealer = {
|
||||
@ -2501,6 +2532,10 @@ declare namespace BusinessAPI {
|
||||
contractUpload: boolean;
|
||||
/** 合同 */
|
||||
contractImg?: string[];
|
||||
/** 产品ID */
|
||||
productId?: string;
|
||||
/** 产品名称 */
|
||||
productName?: string;
|
||||
/** 采购订单包装箱信息 */
|
||||
orderPackageList?: OrderPackage[];
|
||||
};
|
||||
@ -2615,6 +2650,10 @@ declare namespace BusinessAPI {
|
||||
platformPageQry: PlatformPageQry;
|
||||
};
|
||||
|
||||
type pageProductParams = {
|
||||
productPageQry: ProductPageQry;
|
||||
};
|
||||
|
||||
type pagePurchaseOrderParams = {
|
||||
purchaseOrderPageQry: PurchaseOrderPageQry;
|
||||
};
|
||||
@ -2840,6 +2879,19 @@ declare namespace BusinessAPI {
|
||||
totalPages?: number;
|
||||
};
|
||||
|
||||
type PageResponseProductVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
errMessage?: string;
|
||||
totalCount?: number;
|
||||
pageSize?: number;
|
||||
pageIndex?: number;
|
||||
data?: ProductVO[];
|
||||
empty?: boolean;
|
||||
notEmpty?: boolean;
|
||||
totalPages?: number;
|
||||
};
|
||||
|
||||
type PageResponsePurchaseOrderVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
@ -3021,6 +3073,107 @@ declare namespace BusinessAPI {
|
||||
homePage: string;
|
||||
};
|
||||
|
||||
type ProductCreateCmd = {
|
||||
/** 产品ID */
|
||||
productId: string;
|
||||
/** 产品名称 */
|
||||
name: string;
|
||||
/** 关联成本费用id */
|
||||
costItemIds?: number[];
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 排序号 */
|
||||
sort: number;
|
||||
/** 状态:1_启用;0_禁用 */
|
||||
status: boolean;
|
||||
/** 创建时间 */
|
||||
createdAt?: string;
|
||||
};
|
||||
|
||||
type ProductDestroyCmd = {
|
||||
/** 产品表ID */
|
||||
productId: string;
|
||||
};
|
||||
|
||||
type ProductDragCmd = {
|
||||
/** 相邻元素前 */
|
||||
prevId?: number;
|
||||
/** 相邻元素后 */
|
||||
nextId?: number;
|
||||
/** 当前元素 */
|
||||
currentId?: number;
|
||||
};
|
||||
|
||||
type ProductListQry = {
|
||||
/** 状态:1_启用;0_禁用; */
|
||||
status?: boolean;
|
||||
/** 产品表ID */
|
||||
productId?: string;
|
||||
};
|
||||
|
||||
type ProductPageQry = {
|
||||
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 */
|
||||
productId?: string;
|
||||
offset?: number;
|
||||
};
|
||||
|
||||
type ProductShowQry = {
|
||||
/** 状态:1_启用;0_禁用; */
|
||||
status?: boolean;
|
||||
/** 产品表ID */
|
||||
productId?: string;
|
||||
};
|
||||
|
||||
type ProductUpdateCmd = {
|
||||
/** 产品表ID */
|
||||
productId: string;
|
||||
/** 产品名称 */
|
||||
name: string;
|
||||
/** 关联成本费用id */
|
||||
costItemIds?: number[];
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 排序号 */
|
||||
sort: number;
|
||||
/** 状态:1_启用;0_禁用 */
|
||||
status: boolean;
|
||||
/** 创建时间 */
|
||||
createdAt?: string;
|
||||
};
|
||||
|
||||
type ProductVO = {
|
||||
/** 产品ID */
|
||||
productId: string;
|
||||
/** 产品名称 */
|
||||
name: string;
|
||||
/** 关联成本费用id */
|
||||
costItemIds?: number[];
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 排序号 */
|
||||
sort: number;
|
||||
/** 状态:1_启用;0_禁用 */
|
||||
status: boolean;
|
||||
/** 成本费用 */
|
||||
costItemVOList?: CostItemVO[];
|
||||
/** 创建时间 */
|
||||
createdAt?: string;
|
||||
};
|
||||
|
||||
type PurchaseOrderApproveCmd = {
|
||||
/** 采购订单ID */
|
||||
orderId: string;
|
||||
@ -3169,6 +3322,8 @@ declare namespace BusinessAPI {
|
||||
active?: number;
|
||||
/** 供应商信息 */
|
||||
orderSupplierList: OrderSupplier[];
|
||||
/** 采购订单费用信息 */
|
||||
orderCostList: OrderCost[];
|
||||
};
|
||||
|
||||
type PurchaseOrderStep3Cmd = {
|
||||
@ -3838,6 +3993,10 @@ declare namespace BusinessAPI {
|
||||
platformShowQry: PlatformShowQry;
|
||||
};
|
||||
|
||||
type showProductParams = {
|
||||
productShowQry: ProductShowQry;
|
||||
};
|
||||
|
||||
type showPurchaseOrderParams = {
|
||||
purchaseOrderShowQry: PurchaseOrderShowQry;
|
||||
};
|
||||
@ -4009,6 +4168,13 @@ declare namespace BusinessAPI {
|
||||
data?: PlatformVO;
|
||||
};
|
||||
|
||||
type SingleResponseProductVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
errMessage?: string;
|
||||
data?: ProductVO;
|
||||
};
|
||||
|
||||
type SingleResponsePurchaseOrderVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
|
||||
107
packages/app-client/src/services/poster-request.ts
Normal file
107
packages/app-client/src/services/poster-request.ts
Normal file
@ -0,0 +1,107 @@
|
||||
import axios from "axios";
|
||||
import Taro from "@tarojs/taro";
|
||||
import { Toast } from "@nutui/nutui-react-taro";
|
||||
|
||||
const request = axios.create({
|
||||
baseURL: process.env.TARO_API_DOMAIN,
|
||||
});
|
||||
|
||||
// 创建全局的axios实例,并安装请求拦截器
|
||||
request.interceptors.request.use(
|
||||
(config) => {
|
||||
// 在发送请求之前做些什么
|
||||
const saToken = Taro.getStorageSync("saToken");
|
||||
if (saToken) {
|
||||
config.headers.saToken = saToken;
|
||||
}
|
||||
|
||||
const slug = Taro.getStorageSync("userRoleVO")?.slug;
|
||||
if (slug) {
|
||||
config.headers["Xh-Role-Slug"] = slug;
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
// 处理请求错误
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
// 在获取到响应后,安装响应拦截器
|
||||
request.interceptors.response.use(
|
||||
async (response) => {
|
||||
console.log("response", response);
|
||||
const {
|
||||
data: { success, data },
|
||||
} = response;
|
||||
// 处理响应成功的情况
|
||||
if (success) {
|
||||
const saToken = data?.meta?.accessToken;
|
||||
if (saToken) {
|
||||
Taro.setStorageSync("saToken", saToken);
|
||||
Taro.setStorageSync("user", data.userVO);
|
||||
Taro.setStorageSync("userRoleVO", data.userRoleVOList?.[0]);
|
||||
}
|
||||
} else {
|
||||
// 异常处理
|
||||
if (response.data.errCode === "403") {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "暂无权限",
|
||||
content: response.data.errMessage,
|
||||
});
|
||||
}
|
||||
|
||||
// 如果是401则重新登录,然后重新发起请求
|
||||
if (response.data.errCode === "401") {
|
||||
// 移除缓存
|
||||
Taro.removeStorageSync("saToken");
|
||||
Taro.removeStorageSync("user");
|
||||
Taro.removeStorageSync("userRoleVO");
|
||||
// const { code } = await Taro.login();
|
||||
// const data = await wxMaLogin(code);
|
||||
// if (data) {
|
||||
// response.config.headers.saToken = `${Taro.getStorageSync("saToken")}`;
|
||||
// return request(response.config);
|
||||
// }
|
||||
// 跳转到登录页面
|
||||
Taro.navigateTo({
|
||||
url: "/pages/public/login/index",
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
console.log("response.data.errCode", response.data.errCode);
|
||||
if (response.data.errCode === "400") {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "请求失败",
|
||||
content: response.data.errMessage,
|
||||
});
|
||||
}
|
||||
|
||||
if (response.data.errCode === "500") {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "服务器错误",
|
||||
content: response.data.errMessage,
|
||||
});
|
||||
} else {
|
||||
Toast.show("toast", {
|
||||
icon: "fail",
|
||||
title: "请求失败",
|
||||
content: response.data.errMessage,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
// 处理响应错误的情况
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
export default request;
|
||||
16
packages/app-client/src/services/poster/health.ts
Normal file
16
packages/app-client/src/services/poster/health.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// @ts-ignore
|
||||
/* eslint-disable */
|
||||
import request from "../poster-request";
|
||||
|
||||
/** 健康检查 检查服务是否正常运行 GET /status */
|
||||
export async function getStatus(options?: { [key: string]: any }) {
|
||||
return request<{
|
||||
success?: boolean;
|
||||
data?: Record<string, any>;
|
||||
message?: string;
|
||||
code?: number;
|
||||
}>("/status", {
|
||||
method: "GET",
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
12
packages/app-client/src/services/poster/index.ts
Normal file
12
packages/app-client/src/services/poster/index.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// @ts-ignore
|
||||
/* eslint-disable */
|
||||
// API 更新时间:
|
||||
// API 唯一标识:
|
||||
import * as health from "./health";
|
||||
import * as poster from "./poster";
|
||||
import * as pdf from "./pdf";
|
||||
export default {
|
||||
health,
|
||||
poster,
|
||||
pdf,
|
||||
};
|
||||
34
packages/app-client/src/services/poster/pdf.ts
Normal file
34
packages/app-client/src/services/poster/pdf.ts
Normal file
@ -0,0 +1,34 @@
|
||||
// @ts-ignore
|
||||
/* eslint-disable */
|
||||
import request from "../poster-request";
|
||||
|
||||
/** 生成PDF 从网页URL或HTML内容生成PDF文档 POST /api/v1/pdf */
|
||||
export async function postApiV1Pdf(
|
||||
body: {
|
||||
/** 要生成PDF的网页URL */
|
||||
webpage?: string;
|
||||
/** 要生成PDF的HTML内容(可选,优先级高于webpage) */
|
||||
html?: string;
|
||||
/** 设备缩放因子 */
|
||||
device?: number;
|
||||
/** PDF宽度 */
|
||||
width?: number;
|
||||
/** PDF高度 */
|
||||
height?: number;
|
||||
},
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<{
|
||||
success?: boolean;
|
||||
data?: { name?: string; path?: string };
|
||||
message?: string;
|
||||
code?: number;
|
||||
}>("/api/v1/pdf", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
38
packages/app-client/src/services/poster/poster.ts
Normal file
38
packages/app-client/src/services/poster/poster.ts
Normal file
@ -0,0 +1,38 @@
|
||||
// @ts-ignore
|
||||
/* eslint-disable */
|
||||
import request from "../poster-request";
|
||||
|
||||
/** 生成海报 从网页URL或HTML内容生成海报图像 POST /api/v1/poster */
|
||||
export async function postApiV1Poster(
|
||||
body: {
|
||||
/** 要生成海报的网页URL */
|
||||
webpage?: string;
|
||||
/** 要生成海报的HTML内容(可选,优先级高于webpage) */
|
||||
html?: string;
|
||||
/** 设备缩放因子 */
|
||||
device?: number;
|
||||
/** 海报宽度 */
|
||||
width?: number;
|
||||
/** 海报高度 */
|
||||
height?: number;
|
||||
/** 输出图像类型 */
|
||||
type?: string;
|
||||
/** 编码类型 */
|
||||
encoding?: string;
|
||||
},
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<{
|
||||
success?: boolean;
|
||||
data?: { name?: string; path?: string };
|
||||
message?: string;
|
||||
code?: number;
|
||||
}>("/api/v1/poster", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
1
packages/app-client/src/services/poster/typings.d.ts
vendored
Normal file
1
packages/app-client/src/services/poster/typings.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
declare namespace PosterAPI {}
|
||||
@ -26,7 +26,7 @@ async function ocr(tempFilePath: string, path: string) {
|
||||
name: "file",
|
||||
header: {
|
||||
saToken: Taro.getStorageSync("saToken"),
|
||||
"Content-Type": "multipart/form-data",
|
||||
// "Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ export const uploadFile = async (file: File | string) => {
|
||||
name: "file",
|
||||
header: {
|
||||
saToken: Taro.getStorageSync("saToken"),
|
||||
"Content-Type": "multipart/form-data",
|
||||
// "Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
1
swagger/poster.json
Normal file
1
swagger/poster.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user