feat(components): 添加发票批量上传功能并优化列表组件

- 添加 InvoiceBatchUpload 组件支持发票批量上传
- 修改 PageList 组件类型定义支持泛型
- 在 PageList 组件中添加 toolbar footer 支持
- 优化发票页面 UI 布局和交互体验
- 更新应用版本号到 v0.0.53
- 重构发票上传页面实现批量选择功能
This commit is contained in:
shenyifei 2025-12-23 17:24:37 +08:00
parent ebd955de97
commit ff39dc01d2
10 changed files with 960 additions and 853 deletions

View File

@ -48,7 +48,7 @@ export default <T extends {}, Q extends Query = Query>(
);
const [lightTheme, setLightTheme] = useState(false);
const [data, setData] = useState<Record<any>[]>();
const [data, setData] = useState<T[]>([]);
const [query, setQuery] = useState<Query>();
const [selectRows, setSelectRows] = useState<any[]>([]);
@ -345,7 +345,7 @@ export default <T extends {}, Q extends Query = Query>(
>
{toolbar?.actions && toolbar?.actions.map((item) => item)}
{toolbar?.selectRow?.onClick && (
{toolbar?.selectRow?.onClick && !toolbar?.footer && (
<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"}>
@ -393,6 +393,7 @@ export default <T extends {}, Q extends Query = Query>(
</View>
)}
{toolbar?.footer && toolbar?.footer?.(data || [])}
{tabbar ? tabbar : <SafeArea position="bottom" />}
<Picker

View File

@ -21,7 +21,7 @@ export type TabPane = {
title: string | number;
};
export type ToolBar = {
export type ToolBar<T> = {
selectRow?: {
onClick: (selectRow: any[]) => void;
};
@ -38,6 +38,7 @@ export type ToolBar = {
items: any[];
};
render?: () => React.ReactNode | undefined;
footer?: (record: T[]) => React.ReactNode | undefined;
};
export type IRecordListProps<T = {}, Q extends Query = Query> = {
@ -47,7 +48,7 @@ export type IRecordListProps<T = {}, Q extends Query = Query> = {
type: "virtual" | "infinite";
skeleton?: React.ReactNode;
actionRef: React.MutableRefObject<any>;
toolbar?: ToolBar;
toolbar?: ToolBar<T>;
render: (record: T, index: number) => React.ReactNode;
request: (params: Q) => Promise<Record<T>>;
pagination: {

View File

@ -9,3 +9,4 @@ export * from "./delivery";
export * from "./cost";
export * from "./expenses";
export * from "./audit";
export * from "./invoce";

View File

@ -0,0 +1,298 @@
import { Image, Text, View } from "@tarojs/components";
import { Button, Popup, SafeArea, Toast } from "@nutui/nutui-react-taro";
import Taro from "@tarojs/taro";
import { uploadFile } from "@/utils";
import { Icon } from "@/components";
import { useState } from "react";
import { business } from "@/services";
import { globalStore } from "@/store/global-store";
import { DecimalUtils } from "@/utils/classes/calculators/core/DecimalUtils";
interface IInvoiceBatchUploadProps {
visible: boolean;
setVisible: (visible: boolean) => void;
onFinish: () => void;
selectedOrders: BusinessAPI.OrderSupplierVO[];
}
export default function InvoiceBatchUpload(props: IInvoiceBatchUploadProps) {
const { visible, setVisible, onFinish, selectedOrders } = props;
const { setLoading } = globalStore((state: any) => state);
const [invoiceImg, setInvoiceImg] = useState<
BusinessAPI.OrderSupplier["invoiceImg"]
>([]);
// 提交申请
const handleSubmit = async () => {
// 这里添加提交申请的逻辑
const {
data: { success },
} = await business.orderSupplier.batchUploadInvoice({
orderSupplierIdList: selectedOrders.map((order) => order.orderSupplierId),
invoiceImg: invoiceImg,
invoiceUpload: true,
});
if (success) {
Toast.show("toast", {
icon: "success",
title: "提交成功",
content: "发票已批量上传",
});
onFinish?.();
setVisible(false);
setInvoiceImg([]);
}
};
// 计算选中车次的总重量和总金额
const calculateTotals = () => {
return selectedOrders.reduce(
(totals, order) => {
totals.totalWeight = DecimalUtils.add(
totals.totalWeight,
order.netWeight || 0,
);
totals.totalAmount = DecimalUtils.add(
totals.totalAmount,
order.invoiceAmount || 0,
);
return totals;
},
{ totalWeight: 0, totalAmount: 0 },
);
};
const { totalWeight, totalAmount } = calculateTotals();
return (
<Popup
duration={150}
style={{
minHeight: "auto",
}}
closeable
destroyOnClose
visible={visible}
title={"批量上传发票"}
position="bottom"
onClose={() => setVisible(false)}
onOverlayClick={() => setVisible(false)}
lockScroll
round
>
<View className="flex flex-col">
{/* 统计信息 */}
<View className="mb-2 flex items-center justify-between p-2.5">
<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="rounded-lg bg-white p-2.5">
<View className="flex flex-col gap-2.5">
{invoiceImg && invoiceImg?.length > 0 ? (
invoiceImg?.map((uploadFileItem, index) => (
<View
key={uploadFileItem.fileName || index}
className="bg-primary/10 flex flex-col gap-2.5 rounded-lg p-2.5"
>
<View className="flex items-center">
<View className="relative mr-3 h-16 w-16 overflow-hidden rounded-lg">
<Image
className="h-full w-full object-cover"
src={uploadFileItem.filePath!}
/>
</View>
<View className="flex-1">
<View className="font-medium" id="invoice-filename">
{uploadFileItem.fileName}
</View>
<View className="text-sm text-gray-500">
{Number(uploadFileItem.fileSize! / 1024 / 1024).toFixed(
2,
)}{" "}
MB
</View>
</View>
</View>
<View className="flex flex-row gap-2.5">
<View className={"flex-1"}>
<Button
type={"primary"}
size={"large"}
fill={"outline"}
block
onClick={() => {
setInvoiceImg([]);
}}
>
<View></View>
</Button>
</View>
<View className={"flex-1"}>
<Button
type={"warning"}
size={"large"}
fill={"outline"}
block
onClick={() => {
setInvoiceImg([]);
Toast.show("toast", {
title: "删除成功",
icon: "success",
content: "发票已删除",
});
}}
>
<View></View>
</Button>
</View>
</View>
</View>
))
) : (
<View className={`flex w-full flex-row items-center gap-2.5`}>
<View
className={
"border-primary bg-primary/5 flex h-24 flex-1 flex-col items-center justify-center rounded-md border-2 border-dashed p-2.5"
}
onClick={async () => {
await Taro.chooseMessageFile({
type: "file",
count: 1,
success: (res) => {
setLoading(true);
const file = res.tempFiles[0];
uploadFile(file.path).then(({ url }) => {
setInvoiceImg([
{
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
},
]);
setLoading(false);
Toast.show("toast", {
title: "上传成功",
icon: "success",
content: "发票已添加",
});
});
},
fail: (err) => {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: err.errMsg,
});
},
});
}}
>
<Icon name={"file-pdf"} size={28} className="text-primary" />
<Text className="text-primary text-sm font-medium">
PDF文档
</Text>
<Text className="mt-1 text-xs text-gray-400">
PDF
</Text>
</View>
<View className={"text-primary text-sm font-medium"}></View>
<View
className={
"border-primary bg-primary/5 flex h-24 flex-1 flex-col items-center justify-center rounded-md border-2 border-dashed p-2.5"
}
onClick={async () => {
await Taro.chooseImage({
count: 1,
success: (res) => {
setLoading(true);
const file = res.tempFiles[0];
uploadFile(file.path).then(({ url }) => {
setInvoiceImg([
{
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
},
]);
setLoading(false);
Toast.show("toast", {
title: "上传成功",
icon: "success",
content: "发票已添加",
});
});
},
fail: (err) => {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: err.errMsg,
});
},
});
}}
>
<Icon name={"camera"} size={28} className="text-primary" />
<Text className="text-primary text-sm font-medium">
/
</Text>
<Text className="mt-1 text-xs text-gray-400">
</Text>
</View>
</View>
)}
</View>
</View>
{/* 操作按钮 */}
<View className={"flex flex-row gap-2 p-2.5"}>
<View className={"flex-1"}>
<Button
size={"large"}
block
type="default"
onClick={() => {
setVisible(false);
setInvoiceImg([]);
}}
>
</Button>
</View>
{/* 提交按钮 */}
<View className={"flex-1"}>
<Button
size={"large"}
block
type="primary"
disabled={invoiceImg?.length === 0}
onClick={handleSubmit}
>
</Button>
</View>
</View>
</View>
<SafeArea position={"bottom"} />
</Popup>
);
}

View File

@ -0,0 +1 @@
export { default as InvoiceBatchUpload } from "./InvoiceBatchUpload";

View File

@ -1,2 +1,2 @@
// App 相关常量
export const APP_VERSION = "v0.0.52";
export const APP_VERSION = "v0.0.53";

View File

@ -11,10 +11,11 @@ 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 { Label, Text, View } from "@tarojs/components";
import dayjs from "dayjs";
import order from "@/constant/order";
import { Button, Toast } from "@nutui/nutui-react-taro";
import classNames from "classnames";
export default hocAuth(function Page(props: CommonComponent) {
const { shareOptions } = props;
@ -94,21 +95,45 @@ export default hocAuth(function Page(props: CommonComponent) {
type={"infinite"}
actionRef={actionRef}
render={(orderSupplierVO: BusinessAPI.OrderSupplierVO, index) => (
<View className={"mb-2.5"} key={index}>
<View className={"mb-2"} key={index}>
<View
className={
"relative flex flex-col divide-y-2 divide-neutral-100 rounded-lg bg-white px-2.5"
"relative flex flex-col divide-y divide-neutral-100 overflow-hidden rounded-xl bg-white shadow-sm"
}
>
<View className={"flex flex-col divide-y-2 divide-neutral-100"}>
<View className={"py-2.5"}>
<View className="flex items-start justify-between">
<View className="text-base font-medium text-gray-800">
{orderSupplierVO.name} (
{orderSupplierVO.orderVO?.orderVehicle?.origin}-
{orderSupplierVO.orderVO?.orderVehicle?.destination})
{/* 头部区域:名称 + 状态 */}
<View
className={
"flex cursor-pointer items-center justify-between gap-2 px-4 py-3"
}
onClick={() => {
const imageUrls =
orderSupplierVO.invoiceImg?.map((file) => file.filePath!) ||
[];
// 使用 Taro.previewImage 预览图片
if (imageUrls?.length > 0) {
Taro.previewImage({
urls: imageUrls,
});
} else {
Toast.show("toast", {
title: "暂无发票图片",
icon: "none",
content: "",
});
}
}}
>
<View className={"flex min-w-0 flex-1 flex-col gap-1.5"}>
<Text className={"text-neutral-darkest text-lg font-bold"}>
{orderSupplierVO.name}
</Text>
<Text className={"text-neutral-dark text-xs"}>
{orderSupplierVO.orderVO?.orderVehicle?.origin} {" "}
{orderSupplierVO.orderVO?.orderVehicle?.destination}
</Text>
</View>
<View className={"flex-shrink-0"}>
<View className={"flex flex-col items-end gap-1"}>
{orderSupplierVO.poState && (
<State
position="relative"
@ -118,36 +143,86 @@ export default hocAuth(function Page(props: CommonComponent) {
)}
</View>
</View>
<View className="my-1 flex flex-row flex-wrap gap-1 text-sm text-gray-600">
<View className="text-primary">
{/* 详细信息区域 */}
<View
className={"flex cursor-pointer flex-col gap-2 px-4 py-3"}
onClick={() => {
const imageUrls =
orderSupplierVO.invoiceImg?.map((file) => file.filePath!) ||
[];
// 使用 Taro.previewImage 预览图片
if (imageUrls?.length > 0) {
Taro.previewImage({
urls: imageUrls,
});
} else {
Toast.show("toast", {
title: "暂无发票图片",
icon: "none",
content: "",
});
}
}}
>
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}>
</Label>
<Text
className={classNames(
"text-xs font-medium",
"text-primary",
)}
>
{orderSupplierVO.orderVO?.orderVehicle?.vehicleNo
? "第" +
orderSupplierVO.orderVO?.orderVehicle?.vehicleNo +
"车"
? `${orderSupplierVO.orderVO?.orderVehicle?.vehicleNo}`
: "暂未生成车次"}
</Text>
</View>
<View>
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}>
</Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
{dayjs(
orderSupplierVO.orderVO?.orderVehicle?.deliveryTime,
).format("MM-DD")}
).format("YYYY-MM-DD")}
</Text>
</View>
<View>|</View>
<View>{orderSupplierVO.netWeight}</View>
<View>|</View>
<View>¥{orderSupplierVO.invoiceAmount}</View>
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}></Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
{orderSupplierVO.netWeight}
</Text>
</View>
<View className="text-neutral-darker text-xs">
{`品种:${orderSupplierVO.productName}`}
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}>
</Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
¥{orderSupplierVO.invoiceAmount}
</Text>
</View>
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}></Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
{orderSupplierVO.productName}
</Text>
</View>
</View>
<View className={"py-2.5"}>
<View className={"flex flex-row justify-end gap-2"}>
{/* 操作按钮区域 */}
<View
className={
"flex justify-end gap-2 border-t border-neutral-100 bg-gray-50 px-4 py-3"
}
>
<Button
size={"small"}
type={"primary"}
onClick={() => {
onClick={(e) => {
e.stopPropagation();
const imageUrls =
orderSupplierVO.invoiceImg?.map(
(file) => file.filePath!,
@ -159,7 +234,7 @@ export default hocAuth(function Page(props: CommonComponent) {
});
} else {
Toast.show("toast", {
title: "暂无数据",
title: "暂无发票图片",
icon: "none",
content: "",
});
@ -171,7 +246,6 @@ export default hocAuth(function Page(props: CommonComponent) {
</View>
</View>
</View>
</View>
)}
toolbar={toolbar}
request={async (params) => {

View File

@ -1,37 +1,31 @@
import {
ActionType,
Icon,
InvoiceBatchUpload,
PageList,
State,
SupplierPicker,
ToolBar,
} from "@/components";
import Taro, { useShareAppMessage } from "@tarojs/taro";
import { useRef, useState } from "react";
import { useShareAppMessage } from "@tarojs/taro";
import { business } from "@/services";
import hocAuth from "@/hocs/auth";
import { CommonComponent } from "@/types/typings";
import { Image, View } from "@tarojs/components";
import { Label, Text, View } from "@tarojs/components";
import dayjs from "dayjs";
import { Button, Popup, SafeArea, Toast } from "@nutui/nutui-react-taro";
import { uploadFile } from "@/utils";
import { globalStore } from "@/store/global-store";
import { DecimalUtils } from "@/utils/classes/calculators/core/DecimalUtils";
import { Button } from "@nutui/nutui-react-taro";
import order from "@/constant/order";
import classNames from "classnames";
import { useRef, useState } from "react";
export default hocAuth(function Page(props: CommonComponent) {
const { shareOptions } = props;
const [supplierVO, setSupplierVO] = useState<BusinessAPI.SupplierVO>();
const [popupVisible, setPopupVisible] = useState(false);
const [visible, setVisible] = useState(false);
const [selectedOrders, setSelectedOrders] = useState<
BusinessAPI.OrderSupplierVO[]
>([]);
const { setLoading } = globalStore((state: any) => state);
const [invoiceImg, setInvoiceImg] = useState<
BusinessAPI.OrderSupplier["invoiceImg"]
>([]);
const actionRef = useRef<ActionType>();
const toolbar: ToolBar = {
@ -53,220 +47,14 @@ export default hocAuth(function Page(props: CommonComponent) {
},
render: () => (
<>
{/* Popup 弹窗 */}
<Popup
duration={150}
style={{
minHeight: "auto",
<InvoiceBatchUpload
visible={visible}
setVisible={setVisible}
selectedOrders={selectedOrders}
onFinish={() => {
actionRef.current?.reload();
}}
closeable
destroyOnClose
visible={popupVisible}
title={"上传发票"}
position="bottom"
onClose={() => setPopupVisible(false)}
onOverlayClick={() => setPopupVisible(false)}
lockScroll
round
>
<View className="flex flex-col gap-2.5">
{/* 统计信息 */}
<View className="mb-2 flex items-center justify-between p-2.5">
<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="rounded-lg bg-white p-2.5">
<View className="flex flex-col gap-2.5">
{invoiceImg && invoiceImg?.length > 0 ? (
invoiceImg?.map((uploadFileItem, index) => (
<View
key={uploadFileItem.fileName || index}
className="bg-primary/10 flex flex-col gap-2.5 rounded-lg p-2.5"
>
<View className="flex items-center">
<View className="relative mr-3 h-16 w-16 overflow-hidden rounded-lg">
<Image
className="h-full w-full object-cover"
src={uploadFileItem.filePath!}
/>
</View>
<View className="flex-1">
<View className="font-medium" id="invoice-filename">
{uploadFileItem.fileName}
</View>
<View className="text-sm text-gray-500">
{Number(
uploadFileItem.fileSize! / 1024 / 1024,
).toFixed(2)}{" "}
MB
</View>
</View>
</View>
<View className="flex flex-row gap-2.5">
<View className={"flex-1"}>
<Button
type={"primary"}
size={"large"}
fill={"outline"}
block
onClick={() => {
setInvoiceImg([]);
}}
>
<View></View>
</Button>
</View>
<View className={"flex-1"}>
<Button
type={"warning"}
size={"large"}
fill={"outline"}
block
onClick={() => {
setInvoiceImg([]);
Toast.show("toast", {
title: "删除成功",
icon: "success",
content: "发票已删除",
});
}}
>
<View></View>
</Button>
</View>
</View>
</View>
))
) : (
<View className={`flex w-full flex-row items-center gap-2.5`}>
<View
className={
"border-primary bg-primary/5 flex h-24 flex-1 flex-col items-center justify-center rounded-md border-2 border-dashed p-2.5"
}
onClick={async () => {
await Taro.chooseMessageFile({
type: "file",
count: 1,
success: (res) => {
setLoading(true);
const file = res.tempFiles[0];
uploadFile(file.path).then(({ url }) => {
setInvoiceImg([
{
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
},
]);
setLoading(false);
});
},
fail: (err) => {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: err.errMsg,
});
},
});
}}
>
<Icon name={"camera"} size={24} />
<View className="text-primary text-sm"></View>
<View className="mt-1 text-xs text-gray-400">
PDF文档
</View>
</View>
<View className={"text-primary text-base"}></View>
<View
className={
"border-primary bg-primary/5 flex h-24 flex-1 flex-col items-center justify-center rounded-md border-2 border-dashed p-2.5"
}
onClick={async () => {
await Taro.chooseImage({
count: 1,
success: (res) => {
setLoading(true);
const file = res.tempFiles[0];
uploadFile(file.path).then(({ url }) => {
setInvoiceImg([
{
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
},
]);
setLoading(false);
});
},
fail: (err) => {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: err.errMsg,
});
},
});
}}
>
<Icon name={"camera"} size={24} />
<View className="text-primary text-sm"></View>
<View className="mt-1 text-xs text-gray-400">
</View>
</View>
</View>
)}
</View>
</View>
<View className={"flex flex-1 flex-row gap-2.5 p-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={invoiceImg?.length === 0}
onClick={handleSubmit}
>
</Button>
</View>
</View>
<SafeArea position={"bottom"} />
</View>
</Popup>
<View className={"flex flex-row gap-2.5"}>
<SupplierPicker
@ -313,50 +101,6 @@ export default hocAuth(function Page(props: CommonComponent) {
return {};
});
// 计算选中车次的总重量和总金额
const calculateTotals = () => {
return selectedOrders.reduce(
(totals, order) => {
totals.totalWeight = DecimalUtils.add(
totals.totalWeight,
order.netWeight || 0,
);
totals.totalAmount = DecimalUtils.add(
totals.totalAmount,
order.invoiceAmount || 0,
);
return totals;
},
{ totalWeight: 0, totalAmount: 0 },
);
};
const { totalWeight, totalAmount } = calculateTotals();
// 提交申请
const handleSubmit = async () => {
// 这里添加提交申请的逻辑
const {
data: { success },
} = await business.orderSupplier.batchUploadInvoice({
orderSupplierIdList: selectedOrders.map((order) => order.orderSupplierId),
invoiceImg: invoiceImg,
invoiceUpload: true,
});
if (success) {
Toast.show("toast", {
icon: "success",
title: "提交成功",
content: "",
});
}
actionRef.current?.reload();
setPopupVisible(false);
setInvoiceImg([]);
};
return (
<>
<PageList<BusinessAPI.OrderSupplierVO, BusinessAPI.OrderSupplierPageQry>
@ -365,21 +109,28 @@ export default hocAuth(function Page(props: CommonComponent) {
type={"infinite"}
actionRef={actionRef}
render={(orderSupplierVO: BusinessAPI.OrderSupplierVO, index) => (
<View className={"mb-2.5"} key={index}>
<View className={"mb-2"} key={index}>
<View
className={
"relative flex flex-col divide-y-2 divide-neutral-100 rounded-lg bg-white px-2.5"
"relative flex flex-col divide-y divide-neutral-100 overflow-hidden rounded-xl bg-white shadow-sm"
}
>
<View className={"flex flex-col divide-y-2 divide-neutral-100"}>
<View className={"py-2.5"}>
<View className="flex items-start justify-between">
<View className="text-base font-medium text-gray-800">
{orderSupplierVO.name} (
{orderSupplierVO.orderVO?.orderVehicle?.origin}-
{orderSupplierVO.orderVO?.orderVehicle?.destination})
{/* 头部区域:名称 + 状态 */}
<View
className={
"flex cursor-pointer items-center justify-between gap-2 px-4 py-3"
}
>
<View className={"flex min-w-0 flex-1 flex-col gap-1.5"}>
<Text className={"text-neutral-darkest text-lg font-bold"}>
{orderSupplierVO.name}
</Text>
<Text className={"text-neutral-dark text-xs"}>
{orderSupplierVO.orderVO?.orderVehicle?.origin} {" "}
{orderSupplierVO.orderVO?.orderVehicle?.destination}
</Text>
</View>
<View className={"flex-shrink-0"}>
<View className={"flex flex-col items-end gap-1"}>
{orderSupplierVO.poState && (
<State
position="relative"
@ -389,31 +140,78 @@ export default hocAuth(function Page(props: CommonComponent) {
)}
</View>
</View>
<View className="my-1 flex flex-row flex-wrap gap-1 text-sm text-gray-600">
<View className="text-primary">
{/* 详细信息区域 */}
<View className={"flex flex-col gap-2 px-4 py-3"}>
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}>
</Label>
<Text
className={classNames(
"text-xs font-medium",
"text-primary",
)}
>
{orderSupplierVO.orderVO?.orderVehicle?.vehicleNo
? "第" +
orderSupplierVO.orderVO?.orderVehicle?.vehicleNo +
"车"
? `${orderSupplierVO.orderVO?.orderVehicle?.vehicleNo}`
: "暂未生成车次"}
</Text>
</View>
<View>
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}>
</Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
{dayjs(
orderSupplierVO.orderVO?.orderVehicle?.deliveryTime,
).format("MM-DD")}
).format("YYYY-MM-DD")}
</Text>
</View>
<View>|</View>
<View>{orderSupplierVO.netWeight}</View>
<View>|</View>
<View>¥{orderSupplierVO.invoiceAmount}</View>
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}></Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
{orderSupplierVO.netWeight}
</Text>
</View>
<View className="text-neutral-darker text-xs">
{`品种:${orderSupplierVO.productName}`}
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}>
</Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
¥{orderSupplierVO.invoiceAmount}
</Text>
</View>
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}></Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
{orderSupplierVO.productName}
</Text>
</View>
{/* 发票状态提示 */}
{orderSupplierVO.invoiceUpload ? (
<View className="mt-1 flex items-center gap-1 rounded-full bg-green-50 px-2 py-1">
<Icon name="check-circle" size={12} color={"#2E7D32"} />
<Text className="text-xs font-medium text-green-700">
</Text>
</View>
<View className={"py-2.5"}>
<View className={"flex flex-row justify-end gap-2"}>
) : (
<View className="mt-1 flex items-center gap-1 rounded-full bg-orange-50 px-2 py-1">
<Icon name="clock" size={12} color={"#D97A05"} />
<Text className="text-xs font-medium text-orange-700">
</Text>
</View>
)}
</View>
{/* 操作按钮区域 */}
<View
className={
"flex justify-end gap-2 border-t border-neutral-100 bg-gray-50 px-4 py-3"
}
>
{!orderSupplierVO.invoiceUpload &&
(orderSupplierVO.poState === "WAITING_AUDIT" ||
orderSupplierVO.poState === "COMPLETED") && (
@ -422,7 +220,7 @@ export default hocAuth(function Page(props: CommonComponent) {
type={"primary"}
onClick={() => {
setSelectedOrders([orderSupplierVO]);
setPopupVisible(true);
setVisible(true);
}}
>
@ -431,7 +229,6 @@ export default hocAuth(function Page(props: CommonComponent) {
</View>
</View>
</View>
</View>
)}
toolbar={toolbar}
request={async (params) => {

View File

@ -1,48 +1,87 @@
import {
ActionType,
Icon,
InvoiceBatchUpload,
PageList,
State,
SupplierPicker,
ToolBar,
} from "@/components";
import Taro, { useShareAppMessage } from "@tarojs/taro";
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 { Image, View } from "@tarojs/components";
import { Text, View } from "@tarojs/components";
import dayjs from "dayjs";
import { Button, Popup, SafeArea, Toast } from "@nutui/nutui-react-taro";
import { uploadFile } from "@/utils";
import { globalStore } from "@/store/global-store";
import { DecimalUtils } from "@/utils/classes/calculators/core/DecimalUtils";
import order from "@/constant/order";
import classNames from "classnames";
import { Button, Checkbox, SafeArea } from "@nutui/nutui-react-taro";
import { DecimalUtils } from "@/utils/classes/calculators/core/DecimalUtils";
export default hocAuth(function Page(props: CommonComponent) {
const { shareOptions } = props;
const [supplierVO, setSupplierVO] = useState<BusinessAPI.SupplierVO>();
const [popupVisible, setPopupVisible] = useState(false);
const [visible, setVisible] = useState(false);
const [selectedOrders, setSelectedOrders] = useState<
BusinessAPI.OrderSupplierVO[]
>([]);
const { setLoading } = globalStore((state: any) => state);
const [invoiceImg, setInvoiceImg] = useState<
BusinessAPI.OrderSupplier["invoiceImg"]
>([]);
const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
const actionRef = useRef<ActionType>();
const toolbar: ToolBar = {
selectRow: {
onClick: async (orderSupplierVOList: BusinessAPI.OrderSupplierVO[]) => {
console.log("orderSupplierVOList", orderSupplierVOList);
// 点击弹出popup
setSelectedOrders(orderSupplierVOList);
setPopupVisible(true);
},
// 切换选中状态
const toggleSelect = (orderSupplierVO: BusinessAPI.OrderSupplierVO) => {
const newSelectedIds = new Set(selectedIds);
if (newSelectedIds.has(orderSupplierVO.orderSupplierId)) {
newSelectedIds.delete(orderSupplierVO.orderSupplierId);
setSelectedOrders(
selectedOrders.filter(
(orderSupplierVO) =>
orderSupplierVO.orderSupplierId !== orderSupplierVO.orderSupplierId,
),
);
} else {
newSelectedIds.add(orderSupplierVO.orderSupplierId);
setSelectedOrders([...selectedOrders, orderSupplierVO]);
}
setSelectedIds(newSelectedIds);
};
// 全选/取消全选
const toggleSelectAll = (allIds: string[]) => {
if (selectedIds.size === allIds.length) {
// 取消全选
setSelectedIds(new Set());
} else {
// 全选
setSelectedIds(new Set(allIds));
}
};
// 计算选中订单的总重量和总金额
const calculateSelectedTotals = (data: BusinessAPI.OrderSupplierVO[]) => {
const selected = data.filter((item) =>
selectedIds.has(item.orderSupplierId),
);
return selected.reduce(
(totals, order) => {
totals.totalWeight = DecimalUtils.add(
totals.totalWeight,
order.netWeight || 0,
);
totals.totalAmount = DecimalUtils.add(
totals.totalAmount,
order.invoiceAmount || 0,
);
return totals;
},
{ totalWeight: 0, totalAmount: 0 },
);
};
const toolbar: ToolBar<BusinessAPI.OrderSupplierVO> = {
search: {
activeKey: "vehicleNo",
defaultActiveKey: "vehicleNo",
@ -59,222 +98,19 @@ export default hocAuth(function Page(props: CommonComponent) {
},
],
},
render: () => (
render: () => {
return (
<>
{/* Popup 弹窗 */}
<Popup
duration={150}
style={{
minHeight: "auto",
<InvoiceBatchUpload
selectedOrders={selectedOrders}
visible={visible}
setVisible={setVisible}
onFinish={() => {
actionRef.current?.reload();
setSelectedIds(new Set());
}}
closeable
destroyOnClose
visible={popupVisible}
title={"上传发票"}
position="bottom"
onClose={() => setPopupVisible(false)}
onOverlayClick={() => setPopupVisible(false)}
lockScroll
round
>
<View className="flex flex-col gap-2.5">
{/* 统计信息 */}
<View className="mb-2 flex items-center justify-between p-2.5">
<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="rounded-lg bg-white p-2.5">
<View className="flex flex-col gap-2.5">
{invoiceImg && invoiceImg?.length > 0 ? (
invoiceImg?.map((uploadFileItem, index) => (
<View
key={uploadFileItem.fileName || index}
className="bg-primary/10 flex flex-col gap-2.5 rounded-lg p-2.5"
>
<View className="flex items-center">
<View className="relative mr-3 h-16 w-16 overflow-hidden rounded-lg">
<Image
className="h-full w-full object-cover"
src={uploadFileItem.filePath!}
/>
</View>
<View className="flex-1">
<View className="font-medium" id="invoice-filename">
{uploadFileItem.fileName}
</View>
<View className="text-sm text-gray-500">
{Number(
uploadFileItem.fileSize! / 1024 / 1024,
).toFixed(2)}{" "}
MB
</View>
</View>
</View>
<View className="flex flex-row gap-2.5">
<View className={"flex-1"}>
<Button
type={"primary"}
size={"large"}
fill={"outline"}
block
onClick={() => {
setInvoiceImg([]);
}}
>
<View></View>
</Button>
</View>
<View className={"flex-1"}>
<Button
type={"warning"}
size={"large"}
fill={"outline"}
block
onClick={() => {
setInvoiceImg([]);
Toast.show("toast", {
title: "删除成功",
icon: "success",
content: "发票已删除",
});
}}
>
<View></View>
</Button>
</View>
</View>
</View>
))
) : (
<View className={`flex w-full flex-row items-center gap-2.5`}>
<View
className={
"border-primary bg-primary/5 flex h-24 flex-1 flex-col items-center justify-center rounded-md border-2 border-dashed p-2.5"
}
onClick={async () => {
await Taro.chooseMessageFile({
type: "file",
count: 1,
success: (res) => {
setLoading(true);
const file = res.tempFiles[0];
uploadFile(file.path).then(({ url }) => {
setInvoiceImg([
{
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
},
]);
setLoading(false);
});
},
fail: (err) => {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: err.errMsg,
});
},
});
}}
>
<Icon name={"camera"} size={24} />
<View className="text-primary text-sm"></View>
<View className="mt-1 text-xs text-gray-400">
PDF文档
</View>
</View>
<View className={"text-primary text-base"}></View>
<View
className={
"border-primary bg-primary/5 flex h-24 flex-1 flex-col items-center justify-center rounded-md border-2 border-dashed p-2.5"
}
onClick={async () => {
await Taro.chooseImage({
count: 1,
success: (res) => {
setLoading(true);
const file = res.tempFiles[0];
uploadFile(file.path).then(({ url }) => {
setInvoiceImg([
{
fileName: url.split("/").pop(),
filePath: url,
fileSize: file.size,
fileType: url.split(".").pop(),
},
]);
setLoading(false);
});
},
fail: (err) => {
Toast.show("toast", {
title: "上传失败",
icon: "fail",
content: err.errMsg,
});
},
});
}}
>
<Icon name={"camera"} size={24} />
<View className="text-primary text-sm"></View>
<View className="mt-1 text-xs text-gray-400">
</View>
</View>
</View>
)}
</View>
</View>
<View className={"flex flex-1 flex-row gap-2.5 p-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={invoiceImg?.length === 0}
onClick={handleSubmit}
>
</Button>
</View>
</View>
<SafeArea position={"bottom"} />
</View>
</Popup>
<View className={"flex flex-row gap-2.5"}>
<SupplierPicker
@ -308,7 +144,79 @@ export default hocAuth(function Page(props: CommonComponent) {
/>
</View>
</>
),
);
},
footer: (data: BusinessAPI.OrderSupplierVO[]) => {
const allIds = data.map((item) => item.orderSupplierId);
const isSelectedAll =
selectedIds.size === allIds.length && allIds.length > 0;
const totals = calculateSelectedTotals(data);
return (
<View className="sticky bottom-0 z-10 bg-white">
{/* 批量操作栏 */}
{selectedIds.size > 0 && (
<View className="flex items-center justify-between p-2.5">
<View className="flex flex-1 flex-row items-center gap-2">
<Checkbox
checked={isSelectedAll}
onChange={() => toggleSelectAll(allIds)}
/>
<View className="flex flex-col">
<Text className="text-sm font-medium text-gray-700">
{selectedIds.size}
</Text>
<Text className="text-xs text-gray-500">
: {totals.totalWeight} | : ¥
{totals.totalAmount.toFixed(2)}
</Text>
</View>
</View>
<View className="flex flex-row items-center gap-2">
<Button
type={"default"}
size={"large"}
onClick={() => {
setSelectedIds(new Set());
}}
>
</Button>
<Button
type={"primary"}
size={"large"}
disabled={selectedIds.size === 0}
onClick={() => {
if (selectedIds.size > 0) {
const selected = data.filter((item) =>
selectedIds.has(item.orderSupplierId),
);
setSelectedOrders(selected);
setVisible(true);
}
}}
>
</Button>
</View>
</View>
)}
{/* 全选按钮 */}
{selectedIds.size === 0 && data.length > 0 && (
<View className="p-2.5">
<View
className="flex cursor-pointer items-center gap-2 rounded-lg bg-gray-50 px-3 py-2"
onClick={() => toggleSelectAll(allIds)}
>
<Checkbox checked={false} />
<Text className="text-sm text-gray-600"></Text>
</View>
</View>
)}
<SafeArea position={"bottom"} />
</View>
);
},
};
useShareAppMessage((res) => {
@ -321,70 +229,65 @@ export default hocAuth(function Page(props: CommonComponent) {
return {};
});
// 计算选中车次的总重量和总金额
const calculateTotals = () => {
return selectedOrders.reduce(
(totals, order) => {
totals.totalWeight = DecimalUtils.add(
totals.totalWeight,
order.netWeight || 0,
);
totals.totalAmount = DecimalUtils.add(
totals.totalAmount,
order.invoiceAmount || 0,
);
return totals;
},
{ totalWeight: 0, totalAmount: 0 },
);
};
const { totalWeight, totalAmount } = calculateTotals();
// 提交申请
const handleSubmit = async () => {
// 这里添加提交申请的逻辑
const {
data: { success },
} = await business.orderSupplier.batchUploadInvoice({
orderSupplierIdList: selectedOrders.map((order) => order.orderSupplierId),
invoiceImg: invoiceImg,
invoiceUpload: true,
});
if (success) {
Toast.show("toast", {
icon: "success",
title: "提交成功",
content: "",
});
}
actionRef.current?.reload();
setPopupVisible(false);
setInvoiceImg([]);
};
return (
<>
<PageList<BusinessAPI.OrderSupplierVO, BusinessAPI.OrderSupplierPageQry>
rowId={"orderSupplierId"}
itemHeight={182}
itemHeight={100}
type={"infinite"}
actionRef={actionRef}
render={(orderSupplierVO: BusinessAPI.OrderSupplierVO, index) => (
<View className={"flex-1"} key={index}>
render={(orderSupplierVO: BusinessAPI.OrderSupplierVO, index) => {
const isSelected = selectedIds.has(orderSupplierVO.orderSupplierId);
return (
<View
className={"relative flex flex-col divide-y-2 divide-neutral-100"}
className={classNames("mb-2", isSelected && "p-0.5")}
key={index}
>
<View className="flex-1">
<View className="flex items-start justify-between">
<View className="text-base font-medium text-gray-800">
{orderSupplierVO.name} (
{orderSupplierVO.orderVO?.orderVehicle.origin}-
{orderSupplierVO.orderVO?.orderVehicle.destination})
<View
className={classNames(
"relative flex flex-col divide-y divide-neutral-100 overflow-hidden rounded-lg bg-white shadow-sm transition-all",
isSelected && "ring-primary ring-2 ring-offset-1",
)}
>
{/* 选中遮罩层 */}
{isSelected && (
<View className="bg-primary/5 pointer-events-none absolute inset-0 z-10" />
)}
{/* 复选框 + 头部区域 */}
<View
className={
"flex cursor-pointer items-center justify-between gap-2 px-3 py-2"
}
onClick={(e) => {
// 点击卡片切换选中状态
e.stopPropagation();
toggleSelect(orderSupplierVO);
}}
>
<View className={"flex flex-1 flex-row items-center gap-2"}>
<Checkbox
checked={isSelected}
onClick={(e) => {
e.stopPropagation();
toggleSelect(orderSupplierVO);
}}
/>
<View className={"flex min-w-0 flex-1 flex-col gap-1"}>
<Text
className={"text-neutral-darkest text-sm font-bold"}
>
{orderSupplierVO.name}
</Text>
<View className={"flex flex-row items-center gap-2"}>
<Text className={"text-neutral-dark text-xs"}>
{orderSupplierVO.orderVO?.orderVehicle?.origin} {" "}
{orderSupplierVO.orderVO?.orderVehicle?.destination}
</Text>
</View>
<View className={"flex-shrink-0"}>
</View>
</View>
<View className={"flex flex-col items-end gap-1"}>
{orderSupplierVO.poState && (
<State
position="relative"
@ -392,33 +295,66 @@ export default hocAuth(function Page(props: CommonComponent) {
stateMap={order.stateMap}
/>
)}
{/* 发票状态提示 */}
{orderSupplierVO.invoiceUpload ? (
<View className="flex items-center gap-1">
<Icon name="check-circle" size={10} color={"#2E7D32"} />
<Text className="text-xs text-green-700"></Text>
</View>
) : (
<View className="flex items-center gap-1">
<Icon name="clock" size={10} color={"#D97A05"} />
<Text className="text-xs text-orange-700"></Text>
</View>
)}
</View>
</View>
<View className="my-1 flex flex-row flex-wrap gap-1 text-sm text-gray-600">
<View className="text-primary">
{/* 详细信息区域 - 紧凑一行显示 */}
<View
className={
"flex flex-row items-center justify-between gap-2 px-3 py-2 text-xs"
}
onClick={(e) => {
// 点击详细信息区域也切换选中状态
e.stopPropagation();
toggleSelect(orderSupplierVO);
}}
>
<View
className={
"flex flex-1 flex-row items-center gap-1 text-gray-600"
}
>
<Text
className={classNames(
"text-xs font-medium",
"text-primary",
)}
>
{orderSupplierVO.orderVO?.orderVehicle?.vehicleNo
? "第" +
orderSupplierVO.orderVO?.orderVehicle?.vehicleNo +
"车"
? `${orderSupplierVO.orderVO?.orderVehicle?.vehicleNo}`
: "暂未生成车次"}
</View>
<View>
</Text>
|
<Text>
{dayjs(
orderSupplierVO.orderVO?.orderVehicle?.deliveryTime,
).format("MM-DD")}
</Text>
<Text>|</Text>
<Text>{orderSupplierVO.netWeight}</Text>
<Text>|</Text>
<Text>¥{orderSupplierVO.invoiceAmount}</Text>
</View>
<View>|</View>
<View>{orderSupplierVO.netWeight}</View>
<View>|</View>
<View>¥{orderSupplierVO.invoiceAmount}</View>
</View>
<View className="text-neutral-darker text-xs">
{`品种:${orderSupplierVO.productName}`}
<Text className={"text-neutral-darkest font-medium"}>
{orderSupplierVO.productName}
</Text>
</View>
</View>
</View>
</View>
)}
);
}}
toolbar={toolbar}
request={async (params) => {
const {

View File

@ -60,31 +60,40 @@ export default hocAuth(function Page(props: CommonComponent) {
type={"infinite"}
actionRef={actionRef}
render={(supplierVO: BusinessAPI.SupplierVO, index) => (
<View className={"mb-2.5"} key={index}>
<View className={"mb-2"} key={index}>
<View
className={
"relative flex flex-col divide-y-2 divide-neutral-100 rounded-lg bg-white px-2.5"
"relative flex flex-col divide-y divide-neutral-100 overflow-hidden rounded-xl bg-white shadow-sm"
}
>
<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"}
{/* 头部区域:名称 + 编辑按钮 */}
<View
className={
"flex cursor-pointer items-center justify-between gap-2 px-4 py-3"
}
onClick={() => {
Taro.navigateTo({
url: buildUrl("/pages/supplier/create", {
supplierId: supplierVO.supplierId,
}),
});
}}
>
<View className={"flex min-w-0 flex-1 flex-col gap-1.5"}>
<Text className={"text-neutral-darkest text-lg font-bold"}>
{supplierVO?.name}
</Text>
</View>
<Text className={"text-neutral-dark text-xs"}>
ID: {supplierVO.supplierId}
</Text>
</View>
<Button
size={"small"}
type={"primary"}
fill={"none"}
icon={<Icon name={"pen-to-square"} size={18} />}
onClick={() => {
icon={<Icon name={"pen-to-square"} size={16} />}
onClick={(e) => {
e.stopPropagation();
Taro.navigateTo({
url: buildUrl("/pages/supplier/create", {
supplierId: supplierVO.supplierId,
@ -93,29 +102,26 @@ export default hocAuth(function Page(props: CommonComponent) {
}}
/>
</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"
}
className={"flex cursor-pointer flex-col gap-2 px-4 py-3"}
onClick={() => {
Taro.navigateTo({
url: buildUrl("/pages/supplier/create", {
supplierId: supplierVO.supplierId,
}),
});
}}
>
<Label className={"text-neutral-dark text-sm"}>
</Label>
<Text className={"text-neutral-darkest text-sm"}>
{dayjs(supplierVO.createdAt).format("MM-DD HH:mm")}
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}></Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
{dayjs(supplierVO.createdAt).format("YYYY-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-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}></Label>
<View
className={
"flex flex-1 flex-row items-center justify-end gap-1"
@ -124,33 +130,26 @@ export default hocAuth(function Page(props: CommonComponent) {
{supplierVO.phone && <Phone phone={supplierVO.phone} />}
</View>
</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"
}
>
<View className={"flex flex-row items-center justify-between"}>
<Label className={"text-neutral-dark text-xs"}></Label>
<Text className={"text-neutral-darkest text-xs font-medium"}>
12 | 2
</Text>
</View>
</View>
</View>
</View>
</View>
<View className={"py-2.5"}>
<View className={"flex flex-row justify-end gap-2"}>
{/* 联系 */}
{/* 操作按钮区域 */}
<View
className={
"flex justify-end gap-2 border-t border-neutral-100 bg-gray-50 px-4 py-3"
}
>
{supplierVO.phone && (
<Button
size={"small"}
type={"default"}
onClick={() => {
onClick={(e) => {
e.stopPropagation();
Taro.makePhoneCall({
phoneNumber: supplierVO.phone!,
});
@ -159,11 +158,11 @@ export default hocAuth(function Page(props: CommonComponent) {
</Button>
)}
{/* 新建采购 */}
<Button
size={"small"}
type={"default"}
onClick={() => {
onClick={(e) => {
e.stopPropagation();
Taro.navigateTo({
url: buildUrl("/pages/purchase/made/create", {
supplierId: supplierVO.supplierId,
@ -173,11 +172,11 @@ export default hocAuth(function Page(props: CommonComponent) {
>
</Button>
{/* 协助开票 */}
<Button
size={"small"}
type={"primary"}
onClick={() => {
onClick={(e) => {
e.stopPropagation();
Taro.navigateTo({
url: buildUrl("/pages/invoice/upload", {
supplierId: supplierVO.supplierId,
@ -190,7 +189,6 @@ export default hocAuth(function Page(props: CommonComponent) {
</View>
</View>
</View>
</View>
)}
toolbar={toolbar}
request={async (params) => {