feat(audit): 新增审核功能模块
- 新增审核列表、详情、更新接口 - 新增审核相关常量配置 - 新增审核页面组件及路由 - 调整采购订单驳回描述文案 - 优化费用统计导出功能 - 修复部分页面tabbar显示问题 - 更新应用版本号至v0.0.52
This commit is contained in:
parent
e546067226
commit
ac170e8628
@ -57,6 +57,7 @@
|
||||
"ua-parser-js": "^1.0.37",
|
||||
"vconsole": "^3.15.1",
|
||||
"weixin-js-sdk": "^1.6.5",
|
||||
"xlsx": "^0.18.5",
|
||||
"zustand": "^5.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
320
packages/app-client/src/components/audit/ApprovalList.tsx
Normal file
320
packages/app-client/src/components/audit/ApprovalList.tsx
Normal file
@ -0,0 +1,320 @@
|
||||
import {
|
||||
ActionType,
|
||||
CopyText,
|
||||
DealerPicker,
|
||||
Icon,
|
||||
PageList,
|
||||
PurchaseOrderRejectFinal,
|
||||
State,
|
||||
SupplierPicker,
|
||||
ToolBar,
|
||||
} from "@/components";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { business } from "@/services";
|
||||
import { Label, Text, View } from "@tarojs/components";
|
||||
import { buildUrl } from "@/utils";
|
||||
import { Button } from "@nutui/nutui-react-taro";
|
||||
import dayjs from "dayjs";
|
||||
import Taro from "@tarojs/taro";
|
||||
import audit from "@/constant/audit";
|
||||
|
||||
interface IApprovalListProps {
|
||||
params: BusinessAPI.AuditPageQry;
|
||||
toolbar?: ToolBar;
|
||||
actionRef?: React.MutableRefObject<ActionType | undefined>;
|
||||
}
|
||||
|
||||
export default function ApprovalList(props: IApprovalListProps) {
|
||||
const {
|
||||
params: bizParams,
|
||||
toolbar: defaultToolbar,
|
||||
actionRef: externalActionRef,
|
||||
} = props;
|
||||
const internalActionRef = useRef<ActionType>();
|
||||
const actionRef = externalActionRef || internalActionRef;
|
||||
const [dealerVO, setDealerVO] = useState<BusinessAPI.DealerVO>();
|
||||
const [supplierVO, setSupplierVO] = useState<BusinessAPI.SupplierVO>();
|
||||
const toolbar: ToolBar = {
|
||||
...defaultToolbar,
|
||||
search: {
|
||||
activeKey: "plate",
|
||||
defaultActiveKey: "plate",
|
||||
items: [
|
||||
{
|
||||
key: "plate",
|
||||
name: "车牌号",
|
||||
placeholder: "请输入车牌号",
|
||||
},
|
||||
],
|
||||
},
|
||||
render: () => (
|
||||
<View className={"item-start flex flex-row gap-2.5"}>
|
||||
<View>
|
||||
<DealerPicker
|
||||
onFinish={(dealerVO) => {
|
||||
setDealerVO(dealerVO);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
trigger={
|
||||
<View
|
||||
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
||||
>
|
||||
<View className={"text-primary text-xs"}>
|
||||
{dealerVO?.shortName || "经销商"}
|
||||
</View>
|
||||
{dealerVO?.shortName ? (
|
||||
<Icon
|
||||
name={"circle-xmark"}
|
||||
size={16}
|
||||
onClick={(event) => {
|
||||
setDealerVO(undefined);
|
||||
actionRef.current?.reload();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Icon name={"chevron-down"} size={16} />
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<SupplierPicker
|
||||
type={"FARMER"}
|
||||
onFinish={(supplierVO) => {
|
||||
setSupplierVO(supplierVO);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
trigger={
|
||||
<View
|
||||
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
||||
>
|
||||
<View className={"text-primary text-xs"}>
|
||||
{supplierVO?.name || "瓜农"}
|
||||
</View>
|
||||
{supplierVO?.name ? (
|
||||
<Icon
|
||||
name={"circle-xmark"}
|
||||
size={16}
|
||||
onClick={(event) => {
|
||||
setSupplierVO(undefined);
|
||||
actionRef.current?.reload();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Icon name={"chevron-down"} size={16} />
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<PageList<BusinessAPI.AuditVO, BusinessAPI.AuditPageQry>
|
||||
rowId={"purchaseOrderId"}
|
||||
itemHeight={182}
|
||||
toolbar={toolbar}
|
||||
type={"infinite"}
|
||||
actionRef={actionRef}
|
||||
render={(auditVO: BusinessAPI.AuditVO, index) => {
|
||||
const purchaseOrderVO = auditVO.purchaseOrderVO;
|
||||
return (
|
||||
purchaseOrderVO && (
|
||||
<View className={"mb-2.5"} key={index}>
|
||||
<View
|
||||
className={
|
||||
"relative flex flex-col divide-y-2 divide-neutral-100 rounded-lg bg-white px-2.5"
|
||||
}
|
||||
>
|
||||
<View className={"flex flex-col divide-y-2 divide-neutral-100"}>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-row items-center"}>
|
||||
<View className={"flex flex-1 flex-col gap-2"}>
|
||||
<View className={"flex flex-row gap-1"}>
|
||||
{/* 复制 */}
|
||||
<Text
|
||||
className={"text-neutral-darkest text-xl font-bold"}
|
||||
>
|
||||
{purchaseOrderVO.orderVehicle?.dealerName}{" "}
|
||||
{purchaseOrderVO.orderVehicle?.vehicleNo
|
||||
? "第" +
|
||||
purchaseOrderVO.orderVehicle?.vehicleNo +
|
||||
"车"
|
||||
: "暂未生成车次"}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className={"text-neutral-dark text-sm"}>
|
||||
{purchaseOrderVO.orderVehicle?.origin} {" 至 "}
|
||||
{purchaseOrderVO.orderVehicle?.destination}
|
||||
</Text>
|
||||
</View>
|
||||
<State
|
||||
state={auditVO.state}
|
||||
stateMap={audit.approvalStateMap}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-col gap-2"}>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
采购单号
|
||||
</Label>
|
||||
<CopyText copyData={purchaseOrderVO?.orderSn || "-"}>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{purchaseOrderVO.orderSn}
|
||||
</Text>
|
||||
</CopyText>
|
||||
</View>
|
||||
{/* 采购类型*/}
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
采购类型
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{purchaseOrderVO.type === "PRODUCTION_PURCHASE"
|
||||
? "产地采购"
|
||||
: "市场采购"}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
提交人
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{auditVO.createdByName}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
提交时间
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{dayjs(auditVO.createdAt).format("MM-DD HH:mm")}
|
||||
</Text>
|
||||
</View>
|
||||
{auditVO.state === "AUDIT_REJECTED" && (
|
||||
<>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
驳回理由
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{auditVO.auditReason}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
驳回人
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{auditVO.auditByName}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
驳回时间
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{dayjs(auditVO.auditAt).format("MM-DD HH:mm")}
|
||||
</Text>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
{auditVO.state === "WAITING_AUDIT" &&
|
||||
auditVO.type === "BOSS_AUDIT" && (
|
||||
<View className={"flex flex-row gap-2"}>
|
||||
<View className={"flex-1"}>
|
||||
<PurchaseOrderRejectFinal
|
||||
purchaseOrderVO={purchaseOrderVO}
|
||||
size={"large"}
|
||||
onFinish={() => {
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View className={"flex-1"}>
|
||||
<Button
|
||||
type={"primary"}
|
||||
size={"large"}
|
||||
block
|
||||
onClick={(e) => {
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/approval/audit", {
|
||||
orderId: purchaseOrderVO.orderId,
|
||||
auditId: auditVO.auditId,
|
||||
}),
|
||||
});
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
前往审批
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
);
|
||||
}}
|
||||
request={async (params) => {
|
||||
const {
|
||||
data: { data, success, notEmpty },
|
||||
} = await business.audit.pageAudit({
|
||||
auditPageQry: {
|
||||
...params,
|
||||
...bizParams,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
success,
|
||||
hasMore: notEmpty,
|
||||
};
|
||||
}}
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
370
packages/app-client/src/components/audit/AuditList.tsx
Normal file
370
packages/app-client/src/components/audit/AuditList.tsx
Normal file
@ -0,0 +1,370 @@
|
||||
import {
|
||||
ActionType,
|
||||
CopyText,
|
||||
DealerPicker,
|
||||
Icon,
|
||||
PageList,
|
||||
PurchaseOrderRejectApprove,
|
||||
PurchaseOrderWithdrawReview,
|
||||
State,
|
||||
SupplierPicker,
|
||||
ToolBar,
|
||||
} from "@/components";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { business } from "@/services";
|
||||
import { Label, Text, View } from "@tarojs/components";
|
||||
import { buildUrl } from "@/utils";
|
||||
import { Button } from "@nutui/nutui-react-taro";
|
||||
import dayjs from "dayjs";
|
||||
import Taro from "@tarojs/taro";
|
||||
import audit from "@/constant/audit";
|
||||
import { globalStore } from "@/store/global-store";
|
||||
import { purchase } from "@/constant";
|
||||
|
||||
interface IAuditListProps {
|
||||
params: BusinessAPI.AuditPageQry;
|
||||
toolbar?: ToolBar;
|
||||
actionRef?: React.MutableRefObject<ActionType | undefined>;
|
||||
}
|
||||
|
||||
export default function AuditList(props: IAuditListProps) {
|
||||
const {
|
||||
params: bizParams,
|
||||
toolbar: defaultToolbar,
|
||||
actionRef: externalActionRef,
|
||||
} = props;
|
||||
|
||||
const userRoleVO = globalStore((state: any) => state.userRoleVO);
|
||||
const slug = userRoleVO?.slug;
|
||||
const internalActionRef = useRef<ActionType>();
|
||||
const actionRef = externalActionRef || internalActionRef;
|
||||
const [dealerVO, setDealerVO] = useState<BusinessAPI.DealerVO>();
|
||||
const [supplierVO, setSupplierVO] = useState<BusinessAPI.SupplierVO>();
|
||||
const toolbar: ToolBar = {
|
||||
...defaultToolbar,
|
||||
search: {
|
||||
activeKey: "plate",
|
||||
defaultActiveKey: "plate",
|
||||
items: [
|
||||
{
|
||||
key: "plate",
|
||||
name: "车牌号",
|
||||
placeholder: "请输入车牌号",
|
||||
},
|
||||
],
|
||||
},
|
||||
render: () => (
|
||||
<View className={"item-start flex flex-row gap-2.5"}>
|
||||
<View>
|
||||
<DealerPicker
|
||||
onFinish={(dealerVO) => {
|
||||
setDealerVO(dealerVO);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
trigger={
|
||||
<View
|
||||
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
||||
>
|
||||
<View className={"text-primary text-xs"}>
|
||||
{dealerVO?.shortName || "经销商"}
|
||||
</View>
|
||||
{dealerVO?.shortName ? (
|
||||
<Icon
|
||||
name={"circle-xmark"}
|
||||
size={16}
|
||||
onClick={(event) => {
|
||||
setDealerVO(undefined);
|
||||
actionRef.current?.reload();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Icon name={"chevron-down"} size={16} />
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<SupplierPicker
|
||||
type={"FARMER"}
|
||||
onFinish={(supplierVO) => {
|
||||
setSupplierVO(supplierVO);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
trigger={
|
||||
<View
|
||||
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
||||
>
|
||||
<View className={"text-primary text-xs"}>
|
||||
{supplierVO?.name || "瓜农"}
|
||||
</View>
|
||||
{supplierVO?.name ? (
|
||||
<Icon
|
||||
name={"circle-xmark"}
|
||||
size={16}
|
||||
onClick={(event) => {
|
||||
setSupplierVO(undefined);
|
||||
actionRef.current?.reload();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Icon name={"chevron-down"} size={16} />
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<PageList<BusinessAPI.AuditVO, BusinessAPI.AuditPageQry>
|
||||
rowId={"purchaseOrderId"}
|
||||
itemHeight={182}
|
||||
toolbar={toolbar}
|
||||
type={"infinite"}
|
||||
actionRef={actionRef}
|
||||
render={(auditVO: BusinessAPI.AuditVO, index) => {
|
||||
const { purchaseOrderVO } = auditVO;
|
||||
return (
|
||||
purchaseOrderVO && (
|
||||
<View className={"mb-2.5"} key={index}>
|
||||
<View
|
||||
className={
|
||||
"relative flex flex-col divide-y-2 divide-neutral-100 rounded-lg bg-white px-2.5"
|
||||
}
|
||||
>
|
||||
<View className={"flex flex-col divide-y-2 divide-neutral-100"}>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-row items-center"}>
|
||||
<View className={"flex flex-1 flex-col gap-2"}>
|
||||
<View className={"flex flex-row gap-1"}>
|
||||
{/* 复制 */}
|
||||
<Text
|
||||
className={"text-neutral-darkest text-xl font-bold"}
|
||||
>
|
||||
{purchaseOrderVO.orderVehicle?.dealerName}{" "}
|
||||
{purchaseOrderVO.orderVehicle?.vehicleNo
|
||||
? "第" +
|
||||
purchaseOrderVO.orderVehicle?.vehicleNo +
|
||||
"车"
|
||||
: "暂未生成车次"}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className={"text-neutral-dark text-sm"}>
|
||||
{purchaseOrderVO.orderVehicle?.origin} {" 至 "}
|
||||
{purchaseOrderVO.orderVehicle?.destination}
|
||||
</Text>
|
||||
</View>
|
||||
{bizParams.type === "BOSS_AUDIT" ? (
|
||||
<State
|
||||
state={"AUDITING"}
|
||||
stateMap={audit.auditStateMap}
|
||||
/>
|
||||
) : (
|
||||
<State
|
||||
state={auditVO.state}
|
||||
stateMap={audit.auditStateMap}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-col gap-2"}>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
采购单号
|
||||
</Label>
|
||||
<CopyText copyData={purchaseOrderVO?.orderSn || "-"}>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{purchaseOrderVO.orderSn}
|
||||
</Text>
|
||||
</CopyText>
|
||||
</View>
|
||||
{/* 采购类型*/}
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
采购类型
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{purchaseOrderVO.type === "PRODUCTION_PURCHASE"
|
||||
? "产地采购"
|
||||
: "市场采购"}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
提交人
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{auditVO.createdByName}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
提交时间
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{dayjs(auditVO.createdAt).format("MM-DD HH:mm")}
|
||||
</Text>
|
||||
</View>
|
||||
{auditVO.state === "AUDIT_REJECTED" && (
|
||||
<>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
驳回理由
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{auditVO.auditReason}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
驳回人
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{auditVO.auditByName}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
驳回时间
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{dayjs(auditVO.auditAt).format("MM-DD HH:mm")}
|
||||
</Text>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
{slug === "reviewer" &&
|
||||
auditVO.state === "WAITING_AUDIT" &&
|
||||
auditVO.type === "REVIEWER_AUDIT" && (
|
||||
<View className={"flex flex-row gap-2"}>
|
||||
<View className={"flex-1"}>
|
||||
<PurchaseOrderRejectApprove
|
||||
purchaseOrderVO={purchaseOrderVO}
|
||||
size={"large"}
|
||||
onFinish={() => {
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View className={"flex-1"}>
|
||||
<Button
|
||||
type={"primary"}
|
||||
size={"large"}
|
||||
block
|
||||
onClick={(e) => {
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/audit/audit", {
|
||||
auditId: auditVO.auditId,
|
||||
orderId: purchaseOrderVO.orderId,
|
||||
}),
|
||||
});
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
前往审核
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{(slug === "origin-entry" || slug === "market-buyer") &&
|
||||
auditVO.state === "WAITING_AUDIT" && (
|
||||
<View className={"flex flex-row justify-end gap-2"}>
|
||||
<PurchaseOrderWithdrawReview
|
||||
purchaseOrderVO={purchaseOrderVO}
|
||||
size={"small"}
|
||||
onFinish={() => {
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{(slug === "origin-entry" || slug === "market-buyer") &&
|
||||
auditVO.state === "AUDIT_REJECTED" && (
|
||||
<View className={"flex flex-row justify-end gap-2"}>
|
||||
<Button
|
||||
type={"primary"}
|
||||
size={"small"}
|
||||
onClick={(e) => {
|
||||
Taro.navigateTo({
|
||||
url: buildUrl(
|
||||
purchase.path[purchaseOrderVO.type].create,
|
||||
{
|
||||
orderId: purchaseOrderVO.orderId,
|
||||
},
|
||||
),
|
||||
});
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
再次编辑
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
);
|
||||
}}
|
||||
request={async (params) => {
|
||||
const {
|
||||
data: { data, success, notEmpty },
|
||||
} = await business.audit.pageAudit({
|
||||
auditPageQry: {
|
||||
...params,
|
||||
...bizParams,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
success,
|
||||
hasMore: notEmpty,
|
||||
};
|
||||
}}
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
2
packages/app-client/src/components/audit/index.ts
Normal file
2
packages/app-client/src/components/audit/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { default as AuditList } from "./AuditList";
|
||||
export { default as ApprovalList } from "./ApprovalList";
|
||||
@ -8,3 +8,4 @@ export * from "./company";
|
||||
export * from "./delivery";
|
||||
export * from "./cost";
|
||||
export * from "./expenses";
|
||||
export * from "./audit";
|
||||
|
||||
@ -1,263 +0,0 @@
|
||||
import {
|
||||
ActionType,
|
||||
CopyText,
|
||||
DealerPicker,
|
||||
Icon,
|
||||
PageList,
|
||||
PurchaseOrderRejectFinal,
|
||||
State,
|
||||
SupplierPicker,
|
||||
ToolBar,
|
||||
} from "@/components";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { business } from "@/services";
|
||||
import { Label, Text, View } from "@tarojs/components";
|
||||
import { buildUrl } from "@/utils";
|
||||
import { Button } from "@nutui/nutui-react-taro";
|
||||
import dayjs from "dayjs";
|
||||
import purchaseOrder from "@/constant/purchaseOrder";
|
||||
import Taro from "@tarojs/taro";
|
||||
|
||||
interface IPurchaseOrderApprovalListProps {
|
||||
params: BusinessAPI.PurchaseOrderPageQry;
|
||||
toolbar?: ToolBar;
|
||||
actionRef?: React.MutableRefObject<ActionType | undefined>;
|
||||
}
|
||||
|
||||
export default function PurchaseOrderApprovalList(
|
||||
props: IPurchaseOrderApprovalListProps,
|
||||
) {
|
||||
const {
|
||||
params: bizParams,
|
||||
toolbar: defaultToolbar,
|
||||
actionRef: externalActionRef,
|
||||
} = props;
|
||||
const internalActionRef = useRef<ActionType>();
|
||||
const actionRef = externalActionRef || internalActionRef;
|
||||
const [dealerVO, setDealerVO] = useState<BusinessAPI.DealerVO>();
|
||||
const [supplierVO, setSupplierVO] = useState<BusinessAPI.SupplierVO>();
|
||||
const toolbar: ToolBar = {
|
||||
...defaultToolbar,
|
||||
search: {
|
||||
activeKey: "plate",
|
||||
defaultActiveKey: "plate",
|
||||
items: [
|
||||
{
|
||||
key: "plate",
|
||||
name: "车牌号",
|
||||
placeholder: "请输入车牌号",
|
||||
},
|
||||
],
|
||||
},
|
||||
render: () => (
|
||||
<View className={"item-start flex flex-row gap-2.5"}>
|
||||
<View>
|
||||
<DealerPicker
|
||||
onFinish={(dealerVO) => {
|
||||
setDealerVO(dealerVO);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
trigger={
|
||||
<View
|
||||
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
||||
>
|
||||
<View className={"text-primary text-xs"}>
|
||||
{dealerVO?.shortName || "经销商"}
|
||||
</View>
|
||||
{dealerVO?.shortName ? (
|
||||
<Icon
|
||||
name={"circle-xmark"}
|
||||
size={16}
|
||||
onClick={(event) => {
|
||||
setDealerVO(undefined);
|
||||
actionRef.current?.reload();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Icon name={"chevron-down"} size={16} />
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<SupplierPicker
|
||||
type={"FARMER"}
|
||||
onFinish={(supplierVO) => {
|
||||
setSupplierVO(supplierVO);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
trigger={
|
||||
<View
|
||||
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
||||
>
|
||||
<View className={"text-primary text-xs"}>
|
||||
{supplierVO?.name || "瓜农"}
|
||||
</View>
|
||||
{supplierVO?.name ? (
|
||||
<Icon
|
||||
name={"circle-xmark"}
|
||||
size={16}
|
||||
onClick={(event) => {
|
||||
setSupplierVO(undefined);
|
||||
actionRef.current?.reload();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Icon name={"chevron-down"} size={16} />
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<PageList<BusinessAPI.PurchaseOrderVO, BusinessAPI.PurchaseOrderPageQry>
|
||||
rowId={"purchaseOrderId"}
|
||||
itemHeight={182}
|
||||
toolbar={toolbar}
|
||||
type={"infinite"}
|
||||
actionRef={actionRef}
|
||||
render={(purchaseOrderVO: BusinessAPI.PurchaseOrderVO, index) => {
|
||||
return (
|
||||
<View className={"mb-2.5"} key={index}>
|
||||
<View
|
||||
className={
|
||||
"relative flex flex-col divide-y-2 divide-neutral-100 rounded-lg bg-white px-2.5"
|
||||
}
|
||||
>
|
||||
<View className={"flex flex-col divide-y-2 divide-neutral-100"}>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-row items-center"}>
|
||||
<View className={"flex flex-1 flex-col gap-2"}>
|
||||
<View className={"flex flex-row gap-1"}>
|
||||
{/* 复制 */}
|
||||
<Text
|
||||
className={"text-neutral-darkest text-xl font-bold"}
|
||||
>
|
||||
{purchaseOrderVO.orderVehicle?.dealerName}{" "}
|
||||
{purchaseOrderVO.orderVehicle?.vehicleNo
|
||||
? "第" +
|
||||
purchaseOrderVO.orderVehicle?.vehicleNo +
|
||||
"车"
|
||||
: "暂未生成车次"}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className={"text-neutral-dark text-sm"}>
|
||||
{purchaseOrderVO.orderVehicle?.origin} {" 至 "}
|
||||
{purchaseOrderVO.orderVehicle?.destination}
|
||||
</Text>
|
||||
</View>
|
||||
<State
|
||||
state={purchaseOrderVO.auditState}
|
||||
stateMap={purchaseOrder.approvalStateMap}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-col gap-2"}>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
采购单号
|
||||
</Label>
|
||||
<CopyText copyData={purchaseOrderVO?.orderSn || "-"}>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{purchaseOrderVO.orderSn}
|
||||
</Text>
|
||||
</CopyText>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
提交人
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{purchaseOrderVO.createdByName}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
提交时间
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{dayjs(purchaseOrderVO.createdAt).format("MM-DD HH:mm")}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
{purchaseOrderVO.state === "WAITING_AUDIT" &&
|
||||
purchaseOrderVO.auditState === "PENDING_BOSS_APPROVAL" && (
|
||||
<View className={"flex flex-row gap-2"}>
|
||||
<View className={"flex-1"}>
|
||||
<PurchaseOrderRejectFinal
|
||||
purchaseOrderVO={purchaseOrderVO}
|
||||
size={"large"}
|
||||
onFinish={() => {
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View className={"flex-1"}>
|
||||
<Button
|
||||
type={"primary"}
|
||||
size={"large"}
|
||||
block
|
||||
onClick={(e) => {
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/approval/audit", {
|
||||
orderId: purchaseOrderVO.orderId,
|
||||
}),
|
||||
});
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
前往审批
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
request={async (params) => {
|
||||
const {
|
||||
data: { data, success, notEmpty },
|
||||
} = await business.purchaseOrder.pagePurchaseOrder({
|
||||
purchaseOrderPageQry: {
|
||||
...params,
|
||||
...bizParams,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
success,
|
||||
hasMore: notEmpty,
|
||||
};
|
||||
}}
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -1,263 +0,0 @@
|
||||
import {
|
||||
ActionType,
|
||||
CopyText,
|
||||
DealerPicker,
|
||||
Icon,
|
||||
PageList,
|
||||
PurchaseOrderRejectApprove,
|
||||
State,
|
||||
SupplierPicker,
|
||||
ToolBar,
|
||||
} from "@/components";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { business } from "@/services";
|
||||
import { Label, Text, View } from "@tarojs/components";
|
||||
import { buildUrl } from "@/utils";
|
||||
import { Button } from "@nutui/nutui-react-taro";
|
||||
import dayjs from "dayjs";
|
||||
import purchaseOrder from "@/constant/purchaseOrder";
|
||||
import Taro from "@tarojs/taro";
|
||||
|
||||
interface IPurchaseOrderAuditListProps {
|
||||
params: BusinessAPI.PurchaseOrderPageQry;
|
||||
toolbar?: ToolBar;
|
||||
actionRef?: React.MutableRefObject<ActionType | undefined>;
|
||||
}
|
||||
|
||||
export default function PurchaseOrderAuditList(
|
||||
props: IPurchaseOrderAuditListProps,
|
||||
) {
|
||||
const {
|
||||
params: bizParams,
|
||||
toolbar: defaultToolbar,
|
||||
actionRef: externalActionRef,
|
||||
} = props;
|
||||
const internalActionRef = useRef<ActionType>();
|
||||
const actionRef = externalActionRef || internalActionRef;
|
||||
const [dealerVO, setDealerVO] = useState<BusinessAPI.DealerVO>();
|
||||
const [supplierVO, setSupplierVO] = useState<BusinessAPI.SupplierVO>();
|
||||
const toolbar: ToolBar = {
|
||||
...defaultToolbar,
|
||||
search: {
|
||||
activeKey: "plate",
|
||||
defaultActiveKey: "plate",
|
||||
items: [
|
||||
{
|
||||
key: "plate",
|
||||
name: "车牌号",
|
||||
placeholder: "请输入车牌号",
|
||||
},
|
||||
],
|
||||
},
|
||||
render: () => (
|
||||
<View className={"item-start flex flex-row gap-2.5"}>
|
||||
<View>
|
||||
<DealerPicker
|
||||
onFinish={(dealerVO) => {
|
||||
setDealerVO(dealerVO);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
trigger={
|
||||
<View
|
||||
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
||||
>
|
||||
<View className={"text-primary text-xs"}>
|
||||
{dealerVO?.shortName || "经销商"}
|
||||
</View>
|
||||
{dealerVO?.shortName ? (
|
||||
<Icon
|
||||
name={"circle-xmark"}
|
||||
size={16}
|
||||
onClick={(event) => {
|
||||
setDealerVO(undefined);
|
||||
actionRef.current?.reload();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Icon name={"chevron-down"} size={16} />
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<SupplierPicker
|
||||
type={"FARMER"}
|
||||
onFinish={(supplierVO) => {
|
||||
setSupplierVO(supplierVO);
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
trigger={
|
||||
<View
|
||||
className={`border-primary flex h-6 items-center rounded-md border-2 px-2.5`}
|
||||
>
|
||||
<View className={"text-primary text-xs"}>
|
||||
{supplierVO?.name || "瓜农"}
|
||||
</View>
|
||||
{supplierVO?.name ? (
|
||||
<Icon
|
||||
name={"circle-xmark"}
|
||||
size={16}
|
||||
onClick={(event) => {
|
||||
setSupplierVO(undefined);
|
||||
actionRef.current?.reload();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Icon name={"chevron-down"} size={16} />
|
||||
)}
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<PageList<BusinessAPI.PurchaseOrderVO, BusinessAPI.PurchaseOrderPageQry>
|
||||
rowId={"purchaseOrderId"}
|
||||
itemHeight={182}
|
||||
toolbar={toolbar}
|
||||
type={"infinite"}
|
||||
actionRef={actionRef}
|
||||
render={(purchaseOrderVO: BusinessAPI.PurchaseOrderVO, index) => {
|
||||
return (
|
||||
<View className={"mb-2.5"} key={index}>
|
||||
<View
|
||||
className={
|
||||
"relative flex flex-col divide-y-2 divide-neutral-100 rounded-lg bg-white px-2.5"
|
||||
}
|
||||
>
|
||||
<View className={"flex flex-col divide-y-2 divide-neutral-100"}>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-row items-center"}>
|
||||
<View className={"flex flex-1 flex-col gap-2"}>
|
||||
<View className={"flex flex-row gap-1"}>
|
||||
{/* 复制 */}
|
||||
<Text
|
||||
className={"text-neutral-darkest text-xl font-bold"}
|
||||
>
|
||||
{purchaseOrderVO.orderVehicle?.dealerName}{" "}
|
||||
{purchaseOrderVO.orderVehicle?.vehicleNo
|
||||
? "第" +
|
||||
purchaseOrderVO.orderVehicle?.vehicleNo +
|
||||
"车"
|
||||
: "暂未生成车次"}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className={"text-neutral-dark text-sm"}>
|
||||
{purchaseOrderVO.orderVehicle?.origin} {" 至 "}
|
||||
{purchaseOrderVO.orderVehicle?.destination}
|
||||
</Text>
|
||||
</View>
|
||||
<State
|
||||
state={purchaseOrderVO.auditState}
|
||||
stateMap={purchaseOrder.auditStateMap}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
<View className={"flex flex-col gap-2"}>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
采购单号
|
||||
</Label>
|
||||
<CopyText copyData={purchaseOrderVO?.orderSn || "-"}>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{purchaseOrderVO.orderSn}
|
||||
</Text>
|
||||
</CopyText>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
提交人
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{purchaseOrderVO.createdByName}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
className={
|
||||
"flex flex-row items-center justify-between gap-2.5"
|
||||
}
|
||||
>
|
||||
<Label className={"text-neutral-dark text-sm"}>
|
||||
提交时间
|
||||
</Label>
|
||||
<Text className={"text-neutral-darkest text-sm"}>
|
||||
{dayjs(purchaseOrderVO.createdAt).format("MM-DD HH:mm")}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className={"py-2.5"}>
|
||||
{purchaseOrderVO.state === "WAITING_AUDIT" &&
|
||||
purchaseOrderVO.auditState === "PENDING_QUOTE_APPROVAL" && (
|
||||
<View className={"flex flex-row gap-2"}>
|
||||
<View className={"flex-1"}>
|
||||
<PurchaseOrderRejectApprove
|
||||
purchaseOrderVO={purchaseOrderVO}
|
||||
size={"large"}
|
||||
onFinish={() => {
|
||||
actionRef.current?.reload();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View className={"flex-1"}>
|
||||
<Button
|
||||
type={"primary"}
|
||||
size={"large"}
|
||||
block
|
||||
onClick={(e) => {
|
||||
Taro.navigateTo({
|
||||
url: buildUrl("/pages/audit/audit", {
|
||||
orderId: purchaseOrderVO.orderId,
|
||||
}),
|
||||
});
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
前往审核
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
request={async (params) => {
|
||||
const {
|
||||
data: { data, success, notEmpty },
|
||||
} = await business.purchaseOrder.pagePurchaseOrder({
|
||||
purchaseOrderPageQry: {
|
||||
...params,
|
||||
...bizParams,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
data,
|
||||
success,
|
||||
hasMore: notEmpty,
|
||||
};
|
||||
}}
|
||||
pagination={{
|
||||
pageSize: 10,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -106,7 +106,7 @@ export default function PurchaseOrderRejectApprove(
|
||||
closeable
|
||||
destroyOnClose
|
||||
title={"驳回"}
|
||||
description={"此采购单将退回到产地录入员"}
|
||||
description={"此采购单将退回到采购员"}
|
||||
>
|
||||
<View className="p-2.5">
|
||||
<View className="mb-2.5 text-sm font-bold">请输入驳回原因</View>
|
||||
|
||||
@ -52,6 +52,7 @@ export { default as MaterialCostSection } from "./section/MaterialCostSection";
|
||||
export { default as ProductionAdvanceSection } from "./section/ProductionAdvanceSection";
|
||||
export { default as WorkerAdvanceSection } from "./section/WorkerAdvanceSection";
|
||||
export { default as DeliveryFormSection } from "./section/DeliveryFormSection";
|
||||
export type { DeliveryFormSectionRef } from "./section/DeliveryFormSection";
|
||||
export { default as PurchaseFormSection } from "./section/PurchaseFormSection";
|
||||
|
||||
export { default as PurchaseStep1Form } from "./document/Step1Form";
|
||||
@ -61,8 +62,6 @@ export { default as PurchaseStep3Success } from "./document/Step3Success";
|
||||
|
||||
export { default as PurchaseOrderItem } from "./PurchaseOrderItem";
|
||||
export { default as PurchaseOrderList } from "./PurchaseOrderList";
|
||||
export { default as PurchaseOrderAuditList } from "./PurchaseOrderAuditList";
|
||||
export { default as PurchaseOrderApprovalList } from "./PurchaseOrderApprovalList";
|
||||
|
||||
export { default as CostCreate } from "./cost/CostCreate";
|
||||
export { default as CostList } from "./cost/CostList";
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
// App 相关常量
|
||||
export const APP_VERSION = "v0.0.50";
|
||||
export const APP_VERSION = "v0.0.52";
|
||||
|
||||
88
packages/app-client/src/constant/audit.ts
Normal file
88
packages/app-client/src/constant/audit.ts
Normal file
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 采购订单审核
|
||||
*/
|
||||
const auditStateList = [
|
||||
{
|
||||
title: "待我审核",
|
||||
value: "WAITING_AUDIT",
|
||||
},
|
||||
{
|
||||
title: "已通过",
|
||||
value: "AUDIT_SUCCESS",
|
||||
},
|
||||
{
|
||||
title: "已驳回",
|
||||
value: "AUDIT_REJECTED",
|
||||
},
|
||||
];
|
||||
const auditStateMap = {
|
||||
WAITING_AUDIT: {
|
||||
label: "待我审核",
|
||||
color: "#7C2D12",
|
||||
bgColor: "#FED7AA",
|
||||
borderColor: "#EA580C",
|
||||
},
|
||||
AUDITING: {
|
||||
label: "审批中",
|
||||
color: "#1E40AF",
|
||||
bgColor: "#DBEAFE",
|
||||
borderColor: "#3B82F6",
|
||||
},
|
||||
AUDIT_SUCCESS: {
|
||||
label: "已通过",
|
||||
color: "#374151",
|
||||
bgColor: "#E5E7EB",
|
||||
borderColor: "#6B7280",
|
||||
},
|
||||
AUDIT_REJECTED: {
|
||||
label: "已驳回",
|
||||
color: "#6B7280",
|
||||
bgColor: "#F3F4F6",
|
||||
borderColor: "#6B7280",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 采购订单审批
|
||||
*/
|
||||
const approvalStateList = [
|
||||
{
|
||||
title: "待我审批",
|
||||
value: "WAITING_AUDIT",
|
||||
},
|
||||
{
|
||||
title: "已通过",
|
||||
value: "AUDIT_SUCCESS",
|
||||
},
|
||||
{
|
||||
title: "已驳回",
|
||||
value: "AUDIT_REJECTED",
|
||||
},
|
||||
];
|
||||
const approvalStateMap = {
|
||||
WAITING_AUDIT: {
|
||||
label: "待我审批",
|
||||
color: "#7C2D12",
|
||||
bgColor: "#FED7AA",
|
||||
borderColor: "#EA580C",
|
||||
},
|
||||
AUDIT_SUCCESS: {
|
||||
label: "已通过",
|
||||
color: "#374151",
|
||||
bgColor: "#E5E7EB",
|
||||
borderColor: "#6B7280",
|
||||
},
|
||||
AUDIT_REJECTED: {
|
||||
label: "已驳回",
|
||||
color: "#991B1B",
|
||||
bgColor: "#FEE2E2",
|
||||
borderColor: "#EF4444",
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
auditStateList,
|
||||
auditStateMap,
|
||||
approvalStateList,
|
||||
approvalStateMap,
|
||||
};
|
||||
@ -56,97 +56,7 @@ const stateMap = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 采购订单审核
|
||||
*/
|
||||
const auditStateList = [
|
||||
{
|
||||
title: "待我审核",
|
||||
value: "PENDING_QUOTE_APPROVAL",
|
||||
},
|
||||
{
|
||||
title: "审批中",
|
||||
value: "PENDING_BOSS_APPROVAL",
|
||||
},
|
||||
{
|
||||
title: "已通过",
|
||||
value: "BOSS_APPROVED",
|
||||
},
|
||||
{
|
||||
title: "已驳回",
|
||||
value: "BOSS_REJECTED",
|
||||
},
|
||||
];
|
||||
const auditStateMap = {
|
||||
PENDING_QUOTE_APPROVAL: {
|
||||
label: "待我审核",
|
||||
color: "#7C2D12",
|
||||
bgColor: "#FED7AA",
|
||||
borderColor: "#EA580C",
|
||||
},
|
||||
PENDING_BOSS_APPROVAL: {
|
||||
label: "审批中",
|
||||
color: "#1E40AF",
|
||||
bgColor: "#DBEAFE",
|
||||
borderColor: "#3B82F6",
|
||||
},
|
||||
BOSS_APPROVED: {
|
||||
label: "已通过",
|
||||
color: "#374151",
|
||||
bgColor: "#E5E7EB",
|
||||
borderColor: "#6B7280",
|
||||
},
|
||||
BOSS_REJECTED: {
|
||||
label: "已驳回",
|
||||
color: "#6B7280",
|
||||
bgColor: "#F3F4F6",
|
||||
borderColor: "#6B7280",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 采购订单审批
|
||||
*/
|
||||
const approvalStateList = [
|
||||
{
|
||||
title: "待我审批",
|
||||
value: "PENDING_BOSS_APPROVAL",
|
||||
},
|
||||
{
|
||||
title: "已通过",
|
||||
value: "BOSS_APPROVED",
|
||||
},
|
||||
{
|
||||
title: "已驳回",
|
||||
value: "BOSS_REJECTED",
|
||||
},
|
||||
];
|
||||
const approvalStateMap = {
|
||||
PENDING_BOSS_APPROVAL: {
|
||||
label: "待我审批",
|
||||
color: "#7C2D12",
|
||||
bgColor: "#FED7AA",
|
||||
borderColor: "#EA580C",
|
||||
},
|
||||
BOSS_APPROVED: {
|
||||
label: "已通过",
|
||||
color: "#374151",
|
||||
bgColor: "#E5E7EB",
|
||||
borderColor: "#6B7280",
|
||||
},
|
||||
BOSS_REJECTED: {
|
||||
label: "已驳回",
|
||||
color: "#991B1B",
|
||||
bgColor: "#FEE2E2",
|
||||
borderColor: "#EF4444",
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
stateList,
|
||||
stateMap,
|
||||
auditStateList,
|
||||
auditStateMap,
|
||||
approvalStateList,
|
||||
approvalStateMap,
|
||||
};
|
||||
|
||||
@ -103,8 +103,8 @@ const reviewCardMap = {
|
||||
|
||||
// 角色标识
|
||||
const roleSlugMap = {
|
||||
"origin-entry": "录入员",
|
||||
"market-buyer": "采购员",
|
||||
"origin-entry": "产地采购员",
|
||||
"market-buyer": "市场采购员",
|
||||
reviewer: "审核员",
|
||||
boss: "老板",
|
||||
};
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
import { ActionType, PurchaseOrderApprovalList } from "@/components";
|
||||
import { ActionType, ApprovalList } from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import { useRef, useState } from "react";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
import purchaseOrder from "@/constant/purchaseOrder";
|
||||
import audit from "@/constant/audit";
|
||||
|
||||
export default hocAuth(function Page(props: CommonComponent) {
|
||||
const { shareOptions } = props;
|
||||
|
||||
const [auditState, setAuditState] = useState<
|
||||
BusinessAPI.PurchaseOrderPageQry["auditState"]
|
||||
>("PENDING_BOSS_APPROVAL");
|
||||
const [state, setState] =
|
||||
useState<BusinessAPI.AuditPageQry["state"]>("WAITING_AUDIT");
|
||||
|
||||
const actionRef = useRef<ActionType>();
|
||||
|
||||
@ -25,24 +24,22 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
});
|
||||
|
||||
return (
|
||||
<PurchaseOrderApprovalList
|
||||
<ApprovalList
|
||||
actionRef={actionRef}
|
||||
toolbar={{
|
||||
tabs: {
|
||||
activeKey: "state",
|
||||
defaultActiveKey: auditState!,
|
||||
items: purchaseOrder.approvalStateList,
|
||||
defaultActiveKey: state!,
|
||||
items: audit.approvalStateList,
|
||||
onChange: (item) => {
|
||||
setAuditState(
|
||||
item as BusinessAPI.PurchaseOrderPageQry["auditState"],
|
||||
);
|
||||
setState(item as BusinessAPI.AuditPageQry["state"]);
|
||||
actionRef.current?.reload();
|
||||
},
|
||||
},
|
||||
}}
|
||||
params={{
|
||||
state: "WAITING_AUDIT",
|
||||
auditState: auditState,
|
||||
state: state,
|
||||
type: "BOSS_AUDIT",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -3,7 +3,7 @@ import { CommonComponent } from "@/types/typings";
|
||||
import Taro from "@tarojs/taro";
|
||||
import { business } from "@/services";
|
||||
import { useEffect, useState } from "react";
|
||||
import { View } from "@tarojs/components";
|
||||
import { Text, View } from "@tarojs/components";
|
||||
import { SafeArea } from "@nutui/nutui-react-taro";
|
||||
import {
|
||||
PurchaseOrderFinalApprove,
|
||||
@ -18,30 +18,51 @@ import {
|
||||
import { DecimalUtils } from "@/utils/classes/calculators/core/DecimalUtils";
|
||||
|
||||
export default hocAuth(function Page(props: CommonComponent) {
|
||||
const { router, isInitialized, setIsInitialized } = props;
|
||||
const { router, isInitialized, setIsInitialized, setLoading } = props;
|
||||
|
||||
const orderId = router.params
|
||||
.orderId as BusinessAPI.PurchaseOrderVO["orderId"];
|
||||
const auditId = router.params.auditId as BusinessAPI.AuditVO["auditId"];
|
||||
|
||||
const [auditVO, setAuditVO] = useState<BusinessAPI.AuditVO>();
|
||||
const [purchaseOrderVO, setPurchaseOrderVO] =
|
||||
useState<BusinessAPI.PurchaseOrderVO>();
|
||||
|
||||
const init = async (orderId: BusinessAPI.PurchaseOrderVO["orderId"]) => {
|
||||
const { data } = await business.purchaseOrder.showPurchaseOrder({
|
||||
const init = async (
|
||||
orderId: BusinessAPI.PurchaseOrderVO["orderId"],
|
||||
auditId: BusinessAPI.AuditVO["auditId"],
|
||||
) => {
|
||||
const {
|
||||
data: { data: auditVO, success: auditSuccess },
|
||||
} = await business.audit.showAudit({
|
||||
auditShowQry: {
|
||||
auditId,
|
||||
},
|
||||
});
|
||||
|
||||
if (auditSuccess && auditVO) {
|
||||
setAuditVO(auditVO);
|
||||
}
|
||||
|
||||
const {
|
||||
data: { data: purchaseOrderVO, success: purchaseSuccess },
|
||||
} = await business.purchaseOrder.showPurchaseOrder({
|
||||
purchaseOrderShowQry: {
|
||||
orderId,
|
||||
},
|
||||
});
|
||||
|
||||
if (data.success) {
|
||||
setPurchaseOrderVO(data.data);
|
||||
if (purchaseSuccess) {
|
||||
setPurchaseOrderVO(purchaseOrderVO);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (orderId && !isInitialized) {
|
||||
init(orderId).then(() => {
|
||||
if (orderId && auditId && !isInitialized) {
|
||||
setLoading(true);
|
||||
init(orderId, auditId).then(() => {
|
||||
setIsInitialized(true);
|
||||
setLoading(false);
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
@ -78,28 +99,59 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
className={"flex flex-1 flex-col gap-2.5 p-2.5"}
|
||||
id={"purchase-order-approve"}
|
||||
>
|
||||
<View>
|
||||
<View className="flex justify-between space-x-2.5">
|
||||
<View className="price-card flex-1 rounded-lg bg-white p-3">
|
||||
<View className="mb-1 text-center text-sm text-gray-500">
|
||||
收购单价
|
||||
{/* 如果有驳回理由,展示一下 */}
|
||||
<View className={"mb-2.5"}>
|
||||
{auditVO?.state === "AUDIT_REJECTED" && (
|
||||
<Text className={"text-sm text-red-500"}>
|
||||
{auditVO.auditReason}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<View className="flex justify-between space-x-2.5">
|
||||
<View className="price-card flex-1 rounded-lg bg-white p-3">
|
||||
<View className="mb-1 text-center text-sm text-gray-500">
|
||||
收购单价
|
||||
</View>
|
||||
<View className="flex flex-row items-center justify-center gap-2.5 text-center">
|
||||
<View className="text-primary text-3xl">
|
||||
{formatUnitPrice(calculator.getAveragePurchasePrice())}
|
||||
</View>
|
||||
<View className="flex flex-row items-center justify-center gap-2.5 text-center">
|
||||
<View className="text-primary text-3xl">
|
||||
{formatUnitPrice(calculator.getAveragePurchasePrice())}
|
||||
</View>
|
||||
<View className="text-sm text-gray-500">元/斤</View>
|
||||
<View className="text-sm text-gray-500">元/斤</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className="price-card flex-1 rounded-lg bg-white p-3">
|
||||
<View className="mb-1 text-center text-sm text-gray-500">
|
||||
市场报价
|
||||
</View>
|
||||
<View className="flex flex-row items-center justify-center gap-2.5 text-center">
|
||||
<View className="text-primary text-2xl">
|
||||
{formatUnitPrice(calculator.getAverageSalesPrice())} 元
|
||||
</View>
|
||||
<View className="text-sm text-gray-500">元/斤</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View className="overflow-hidden rounded-lg bg-white shadow-sm">
|
||||
<View className="border-b border-gray-100 px-4 py-3">
|
||||
<View className="text-sm font-bold">采购信息</View>
|
||||
</View>
|
||||
{/* 采购单号,采购类型 */}
|
||||
<View className="grid grid-cols-2 divide-x divide-y divide-gray-100">
|
||||
<View className="flex flex-col px-3 py-2">
|
||||
<View className="text-sm text-gray-500">经销商</View>
|
||||
<View className="font-medium">
|
||||
{purchaseOrderVO.orderVehicle.dealerName}{" "}
|
||||
{purchaseOrderVO?.orderVehicle?.vehicleNo
|
||||
? "第" + purchaseOrderVO.orderVehicle.vehicleNo + "车"
|
||||
: "暂未生成车次"}
|
||||
</View>
|
||||
</View>
|
||||
<View className="price-card flex-1 rounded-lg bg-white p-3">
|
||||
<View className="mb-1 text-center text-sm text-gray-500">
|
||||
市场报价
|
||||
</View>
|
||||
<View className="flex flex-row items-center justify-center gap-2.5 text-center">
|
||||
<View className="text-primary text-2xl">
|
||||
{formatUnitPrice(calculator.getAverageSalesPrice())} 元
|
||||
</View>
|
||||
<View className="text-sm text-gray-500">元/斤</View>
|
||||
<View className="flex flex-col px-3 py-2">
|
||||
<View className="text-sm text-gray-500">采购类型</View>
|
||||
<View className="font-medium">
|
||||
{purchaseOrderVO.type === "PRODUCTION_PURCHASE"
|
||||
? "产地采购单"
|
||||
: "市场采购单"}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { PurchaseOrderApprovalList } from "@/components";
|
||||
import { ApprovalList } from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
@ -17,10 +17,10 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
});
|
||||
|
||||
return (
|
||||
<PurchaseOrderApprovalList
|
||||
<ApprovalList
|
||||
params={{
|
||||
state: "WAITING_AUDIT",
|
||||
auditState: "PENDING_BOSS_APPROVAL",
|
||||
type: "BOSS_AUDIT",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { PurchaseOrderApprovalList } from "@/components";
|
||||
import { ApprovalList } from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
@ -17,10 +17,10 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
});
|
||||
|
||||
return (
|
||||
<PurchaseOrderApprovalList
|
||||
<ApprovalList
|
||||
params={{
|
||||
state: "REJECTED",
|
||||
auditState: "BOSS_REJECTED",
|
||||
state: "AUDIT_REJECTED",
|
||||
type: "BOSS_AUDIT",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { PurchaseOrderAuditList } from "@/components";
|
||||
import { AuditList } from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
@ -17,10 +17,10 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
});
|
||||
|
||||
return (
|
||||
<PurchaseOrderAuditList
|
||||
<AuditList
|
||||
params={{
|
||||
state: "WAITING_AUDIT",
|
||||
auditState: "PENDING_BOSS_APPROVAL",
|
||||
type: "BOSS_AUDIT",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
import { ActionType, PurchaseOrderAuditList } from "@/components";
|
||||
import { ActionType, AuditList } from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import { useRef, useState } from "react";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
import purchaseOrder from "@/constant/purchaseOrder";
|
||||
import audit from "@/constant/audit";
|
||||
|
||||
export default hocAuth(function Page(props: CommonComponent) {
|
||||
const { shareOptions } = props;
|
||||
|
||||
const [auditState, setAuditState] = useState<
|
||||
BusinessAPI.PurchaseOrderPageQry["auditState"]
|
||||
>("PENDING_QUOTE_APPROVAL");
|
||||
const [state, setState] =
|
||||
useState<BusinessAPI.AuditPageQry["state"]>("WAITING_AUDIT");
|
||||
|
||||
const actionRef = useRef<ActionType>();
|
||||
|
||||
@ -25,24 +24,22 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
});
|
||||
|
||||
return (
|
||||
<PurchaseOrderAuditList
|
||||
<AuditList
|
||||
actionRef={actionRef}
|
||||
toolbar={{
|
||||
tabs: {
|
||||
activeKey: "state",
|
||||
defaultActiveKey: auditState!,
|
||||
items: purchaseOrder.auditStateList,
|
||||
defaultActiveKey: state!,
|
||||
items: audit.auditStateList,
|
||||
onChange: (item) => {
|
||||
setAuditState(
|
||||
item as BusinessAPI.PurchaseOrderPageQry["auditState"],
|
||||
);
|
||||
setState(item as BusinessAPI.AuditPageQry["state"]);
|
||||
actionRef.current?.reload();
|
||||
},
|
||||
},
|
||||
}}
|
||||
params={{
|
||||
state: "WAITING_AUDIT",
|
||||
auditState: auditState,
|
||||
type: "REVIEWER_AUDIT",
|
||||
state: state,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -4,7 +4,6 @@ import Taro, { usePageScroll } from "@tarojs/taro";
|
||||
import { business } from "@/services";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { View } from "@tarojs/components";
|
||||
import purchaseOrder from "@/constant/purchaseOrder";
|
||||
import {
|
||||
ActionSheet,
|
||||
Button,
|
||||
@ -22,6 +21,7 @@ import {
|
||||
CostSummarySection,
|
||||
DealerInfoSection,
|
||||
DeliveryFormSection,
|
||||
DeliveryFormSectionRef,
|
||||
EmptyBoxInfoSection,
|
||||
Icon,
|
||||
MarketPriceSection,
|
||||
@ -39,7 +39,6 @@ import {
|
||||
TaxSubsidySection,
|
||||
WorkerAdvanceSection,
|
||||
} from "@/components";
|
||||
import { type DeliveryFormSectionRef } from "@/components/purchase/section/DeliveryFormSection";
|
||||
import {
|
||||
buildUrl,
|
||||
convertPurchaseOrderToOrderShip,
|
||||
@ -49,6 +48,7 @@ import {
|
||||
} from "@/utils";
|
||||
import classNames from "classnames";
|
||||
import { DecimalUtils } from "@/utils/classes/calculators/core/DecimalUtils";
|
||||
import audit from "@/constant/audit";
|
||||
|
||||
const defaultSections = [
|
||||
"marketPrice",
|
||||
@ -236,10 +236,12 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
|
||||
const orderId = router.params
|
||||
.orderId as BusinessAPI.PurchaseOrderVO["orderId"];
|
||||
const auditId = router.params.auditId as BusinessAPI.AuditVO["auditId"];
|
||||
|
||||
// 费用项目列表
|
||||
const [costList, setCostList] = useState<BusinessAPI.CostVO[]>([]);
|
||||
|
||||
const [auditVO, setAuditVO] = useState<BusinessAPI.AuditVO>();
|
||||
const [purchaseOrderVO, setPurchaseOrderVO] =
|
||||
useState<BusinessAPI.PurchaseOrderVO>();
|
||||
|
||||
@ -531,16 +533,31 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
return null;
|
||||
};
|
||||
|
||||
const init = async (orderId: BusinessAPI.PurchaseOrderVO["orderId"]) => {
|
||||
const init = async (
|
||||
orderId: BusinessAPI.PurchaseOrderVO["orderId"],
|
||||
auditId: BusinessAPI.AuditVO["auditId"],
|
||||
) => {
|
||||
const {
|
||||
data: { data: purchaseOrderVO, success },
|
||||
data: { data: auditVO, success: auditSuccess },
|
||||
} = await business.audit.showAudit({
|
||||
auditShowQry: {
|
||||
auditId,
|
||||
},
|
||||
});
|
||||
|
||||
if (auditSuccess && auditVO) {
|
||||
setAuditVO(auditVO);
|
||||
}
|
||||
|
||||
const {
|
||||
data: { data: purchaseOrderVO, success: purchaseSuccess },
|
||||
} = await business.purchaseOrder.showPurchaseOrder({
|
||||
purchaseOrderShowQry: {
|
||||
orderId,
|
||||
},
|
||||
});
|
||||
|
||||
if (success && purchaseOrderVO) {
|
||||
if (purchaseSuccess && purchaseOrderVO) {
|
||||
if (
|
||||
!purchaseOrderVO.orderShipList ||
|
||||
purchaseOrderVO.orderShipList.length === 0
|
||||
@ -688,9 +705,9 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (orderId && !isInitialized) {
|
||||
if (orderId && auditId && !isInitialized) {
|
||||
setLoading(true);
|
||||
init(orderId).then(() => {
|
||||
init(orderId, auditId).then(() => {
|
||||
setIsInitialized(true);
|
||||
setLoading(false);
|
||||
});
|
||||
@ -802,10 +819,9 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
{purchaseOrderVO?.orderVehicle?.vehicleNo || "-"}车
|
||||
</View>
|
||||
|
||||
<State
|
||||
state={purchaseOrderVO.state}
|
||||
stateMap={purchaseOrder.stateMap}
|
||||
/>
|
||||
{auditVO && (
|
||||
<State state={auditVO.state} stateMap={audit.auditStateMap} />
|
||||
)}
|
||||
</View>
|
||||
<View className="text-neutral-darker text-sm font-medium">
|
||||
{purchaseOrderVO?.orderVehicle.origin || "-"} 至{" "}
|
||||
@ -815,7 +831,9 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
{/* 展示产地负责人*/}
|
||||
<View className="flex flex-row items-center gap-2.5">
|
||||
<View className="flex-shrink-0 text-base font-bold text-gray-900">
|
||||
产地负责人
|
||||
{purchaseOrderVO.type === "PRODUCTION_PURCHASE"
|
||||
? "产地负责人"
|
||||
: "市场负责人"}
|
||||
</View>
|
||||
|
||||
<View
|
||||
@ -832,7 +850,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
purchaseOrderVO.auditState !== "BOSS_REJECTED")
|
||||
)
|
||||
}
|
||||
placeholder="请输入产地负责人姓名"
|
||||
placeholder="请输入姓名"
|
||||
value={originPrincipal || purchaseOrderVO.createdByName}
|
||||
onChange={(value) => setOriginPrincipal(value)}
|
||||
onBlur={() => {
|
||||
@ -1000,7 +1018,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
},
|
||||
{
|
||||
name: "驳回审核",
|
||||
description: "此采购单将退回到产地录入员",
|
||||
description: "此采购单将退回到采购员",
|
||||
danger: true,
|
||||
},
|
||||
{
|
||||
@ -1042,7 +1060,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
closeable
|
||||
destroyOnClose
|
||||
title={"驳回"}
|
||||
description={"此采购单将退回到产地录入员"}
|
||||
description={"此采购单将退回到采购员"}
|
||||
>
|
||||
<View className="p-2.5">
|
||||
<View className="mb-2.5 text-sm font-bold">请输入驳回原因</View>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { PurchaseOrderAuditList } from "@/components";
|
||||
import { AuditList } from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
@ -17,10 +17,10 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
});
|
||||
|
||||
return (
|
||||
<PurchaseOrderAuditList
|
||||
<AuditList
|
||||
params={{
|
||||
state: "WAITING_AUDIT",
|
||||
auditState: "PENDING_QUOTE_APPROVAL",
|
||||
type: "REVIEWER_AUDIT",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { PurchaseOrderList } from "@/components";
|
||||
import { AuditList } from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
@ -17,10 +17,10 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
});
|
||||
|
||||
return (
|
||||
<PurchaseOrderList
|
||||
<AuditList
|
||||
params={{
|
||||
state: "REJECTED",
|
||||
auditState: "QUOTE_REJECTED",
|
||||
state: "AUDIT_REJECTED",
|
||||
type: "REVIEWER_AUDIT",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { PurchaseOrderList } from "@/components";
|
||||
import { useShareAppMessage } from "@tarojs/taro";
|
||||
import hocAuth from "@/hocs/auth";
|
||||
import { CommonComponent } from "@/types/typings";
|
||||
import { AuditList } from "@/components";
|
||||
|
||||
export default hocAuth(function Page(props: CommonComponent) {
|
||||
const { shareOptions } = props;
|
||||
@ -17,9 +17,10 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
});
|
||||
|
||||
return (
|
||||
<PurchaseOrderList
|
||||
<AuditList
|
||||
params={{
|
||||
state: "WAITING_AUDIT",
|
||||
type: "REVIEWER_AUDIT",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -8,6 +8,7 @@ import { Button, Calendar, SafeArea } from "@nutui/nutui-react-taro";
|
||||
import { useEffect, useState } from "react";
|
||||
import { business } from "@/services";
|
||||
import { globalStore } from "@/store/global-store";
|
||||
import { exportExpenseStatisticsExcel } from "@/utils/functions";
|
||||
|
||||
interface PageProps extends CommonComponent {
|
||||
expenseRecordId?: string;
|
||||
@ -178,6 +179,40 @@ export default hocAuth(function Page(props: PageProps) {
|
||||
return costMap;
|
||||
};
|
||||
|
||||
// 导出费用统计数据
|
||||
const exportStatistics = async () => {
|
||||
if (!expenseRecordList || expenseRecordList.length === 0) {
|
||||
Taro.showToast({
|
||||
title: "暂无数据可导出",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const stats = calculateStatistics();
|
||||
const startDate = currentDate[0];
|
||||
const endDate = currentDate[1];
|
||||
|
||||
// 使用工具函数导出Excel
|
||||
await exportExpenseStatisticsExcel({
|
||||
title: "费用统计报表",
|
||||
startDate,
|
||||
endDate,
|
||||
statistics: stats,
|
||||
recordList: expenseRecordList,
|
||||
fileName: `费用统计_${dayjs(startDate).format("YYYYMMDD")}_${dayjs(endDate).format("YYYYMMDD")}.xlsx`,
|
||||
sheetName: "费用统计",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("导出失败:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 渲染计提明细
|
||||
const renderProvisionDetails = (record: BusinessAPI.ExpenseRecordVO) => {
|
||||
const provisionList = record.expenseProvisionList || [];
|
||||
@ -581,6 +616,20 @@ export default hocAuth(function Page(props: PageProps) {
|
||||
返回
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
{/* 导出按钮 */}
|
||||
<View className="flex-1">
|
||||
<Button
|
||||
icon={<Icon name="download" size={12} color={"white"} />}
|
||||
size={"large"}
|
||||
block
|
||||
type={"warning"}
|
||||
onClick={exportStatistics}
|
||||
>
|
||||
导出统计
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
{userRoleVO.slug === "boss" && (
|
||||
<View className="flex-1">
|
||||
<Button
|
||||
|
||||
@ -37,6 +37,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
} = await auth.user.userEmployee({
|
||||
employeeShowQry: {
|
||||
userId: user.userId,
|
||||
//@ts-ignore
|
||||
platformId: platformId,
|
||||
},
|
||||
});
|
||||
@ -45,6 +46,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
setEmployeeVO(employeeVO);
|
||||
const userRoleVOList =
|
||||
employeeVO.userRoleList?.filter(
|
||||
//@ts-ignore
|
||||
(item) => item.platformId === platformId,
|
||||
) || [];
|
||||
setUserRoleVOList(userRoleVOList);
|
||||
@ -333,7 +335,9 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
© {dayjs().format("YYYY")} {channel?.technicalSupport} 版权所有
|
||||
</Text>
|
||||
</View>
|
||||
<CustomTabBar userRoleVO={userRoleVO} />
|
||||
{process.env.TARO_ENV === "weapp" && (
|
||||
<CustomTabBar userRoleVO={userRoleVO} />
|
||||
)}
|
||||
|
||||
{/* 选择身份 */}
|
||||
<Popup
|
||||
|
||||
@ -133,7 +133,9 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<CustomTabBar userRoleVO={userRoleVO} />
|
||||
{process.env.TARO_ENV === "weapp" && (
|
||||
<CustomTabBar userRoleVO={userRoleVO} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@ -91,7 +91,9 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
return (
|
||||
<>
|
||||
<View className="p-2.5">{renderMenuTree(menuList)}</View>
|
||||
<CustomTabBar userRoleVO={userRoleVO} />
|
||||
{process.env.TARO_ENV === "weapp" && (
|
||||
<CustomTabBar userRoleVO={userRoleVO} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@ -381,7 +381,9 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
{activeTab === "done" && renderDoneList()}
|
||||
{activeTab === "message" && renderMessageList()}
|
||||
</View>
|
||||
<CustomTabBar userRoleVO={userRoleVO} />
|
||||
{process.env.TARO_ENV === "weapp" && (
|
||||
<CustomTabBar userRoleVO={userRoleVO} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
@ -3,7 +3,11 @@ import { CommonComponent } from "@/types/typings";
|
||||
import { View } from "@tarojs/components";
|
||||
import { Button, SafeArea } from "@nutui/nutui-react-taro";
|
||||
import { useEffect, useState } from "react";
|
||||
import { MarketPreview, PurchaseOrderWithdrawReview } from "@/components";
|
||||
import {
|
||||
MarketPreview,
|
||||
PurchaseOrderSubmitReview,
|
||||
PurchaseOrderWithdrawReview,
|
||||
} from "@/components";
|
||||
import { business } from "@/services";
|
||||
import Taro from "@tarojs/taro";
|
||||
import { buildUrl } from "@/utils";
|
||||
@ -73,7 +77,7 @@ export default hocAuth(function Page(props: CommonComponent) {
|
||||
</Button>
|
||||
</View>
|
||||
<View className={"flex-1"}>
|
||||
<PurchaseOrderWithdrawReview
|
||||
<PurchaseOrderSubmitReview
|
||||
purchaseOrderVO={purchaseOrder}
|
||||
size={"xlarge"}
|
||||
onFinish={() => {
|
||||
|
||||
67
packages/app-client/src/services/business/audit.ts
Normal file
67
packages/app-client/src/services/business/audit.ts
Normal file
@ -0,0 +1,67 @@
|
||||
// @ts-ignore
|
||||
/* eslint-disable */
|
||||
import request from "../request";
|
||||
|
||||
/** 审核列表 GET /operation/pageAudit */
|
||||
export async function pageAudit(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: BusinessAPI.pageAuditParams,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.PageResponseAuditVO>("/operation/pageAudit", {
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
auditPageQry: undefined,
|
||||
...params["auditPageQry"],
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 审核详情 GET /operation/showAudit */
|
||||
export async function showAudit(
|
||||
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
|
||||
params: BusinessAPI.showAuditParams,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.SingleResponseAuditVO>("/operation/showAudit", {
|
||||
method: "GET",
|
||||
params: {
|
||||
...params,
|
||||
auditShowQry: undefined,
|
||||
...params["auditShowQry"],
|
||||
},
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 审核更新 PUT /operation/updateAudit */
|
||||
export async function updateAudit(
|
||||
body: BusinessAPI.AuditUpdateCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.SingleResponseAuditVO>("/operation/updateAudit", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 审核更新 PATCH /operation/updateAudit */
|
||||
export async function updateAudit1(
|
||||
body: BusinessAPI.AuditUpdateCmd,
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
return request<BusinessAPI.SingleResponseAuditVO>("/operation/updateAudit", {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
data: body,
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
@ -29,6 +29,7 @@ import * as channel from "./channel";
|
||||
import * as boxSpec from "./boxSpec";
|
||||
import * as boxProduct from "./boxProduct";
|
||||
import * as boxBrand from "./boxBrand";
|
||||
import * as audit from "./audit";
|
||||
import * as agreement from "./agreement";
|
||||
import * as role from "./role";
|
||||
import * as permission from "./permission";
|
||||
@ -64,6 +65,7 @@ export default {
|
||||
boxSpec,
|
||||
boxProduct,
|
||||
boxBrand,
|
||||
audit,
|
||||
agreement,
|
||||
role,
|
||||
permission,
|
||||
|
||||
@ -96,6 +96,110 @@ declare namespace BusinessAPI {
|
||||
notifyUrl?: string;
|
||||
};
|
||||
|
||||
type AuditPageQry = {
|
||||
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 */
|
||||
auditId?: string;
|
||||
/** 资源类型 */
|
||||
subjectType?: "PURCHASE_ORDER";
|
||||
/** 审核状态: 1_待审核;2_审核中;3_审核通过;4_审核驳回;5_审核撤回 */
|
||||
state?:
|
||||
| "WAITING_AUDIT"
|
||||
| "AUDITING"
|
||||
| "AUDIT_SUCCESS"
|
||||
| "AUDIT_REJECTED"
|
||||
| "AUDIT_CANCEL";
|
||||
/** 审核类型:1_审核员审核;2_老板审核 */
|
||||
type: "REVIEWER_AUDIT" | "BOSS_AUDIT";
|
||||
offset?: number;
|
||||
};
|
||||
|
||||
type AuditShowQry = {
|
||||
/** 状态:1_启用;0_禁用; */
|
||||
status?: boolean;
|
||||
/** 审核ID */
|
||||
auditId?: string;
|
||||
};
|
||||
|
||||
type AuditUpdateCmd = {
|
||||
/** 创建人ID */
|
||||
createdBy: string;
|
||||
/** 创建人姓名 */
|
||||
createdByName?: string;
|
||||
/** 审核Id */
|
||||
auditId: string;
|
||||
/** 资源Id */
|
||||
subjectId: string;
|
||||
/** 资源类型 */
|
||||
subjectType: "PURCHASE_ORDER";
|
||||
/** 审核状态: 1_待审核;2_审核中;3_审核通过;4_审核驳回;5_审核撤回 */
|
||||
state?:
|
||||
| "WAITING_AUDIT"
|
||||
| "AUDITING"
|
||||
| "AUDIT_SUCCESS"
|
||||
| "AUDIT_REJECTED"
|
||||
| "AUDIT_CANCEL";
|
||||
/** 审核类型:1_审核员审核;2_老板审核 */
|
||||
type: "REVIEWER_AUDIT" | "BOSS_AUDIT";
|
||||
/** 驳回原因 */
|
||||
auditReason?: string;
|
||||
/** 审核时间 */
|
||||
auditAt?: string;
|
||||
/** 审核人ID */
|
||||
auditBy?: string;
|
||||
/** 审核人名称 */
|
||||
auditByName?: string;
|
||||
/** 创建时间 */
|
||||
createdAt?: string;
|
||||
};
|
||||
|
||||
type AuditVO = {
|
||||
/** 审核Id */
|
||||
auditId: string;
|
||||
/** 资源Id */
|
||||
subjectId: string;
|
||||
/** 资源类型 */
|
||||
subjectType: "PURCHASE_ORDER";
|
||||
/** 审核状态: 1_待审核;2_审核中;3_审核通过;4_审核驳回;5_审核撤回 */
|
||||
state?:
|
||||
| "WAITING_AUDIT"
|
||||
| "AUDITING"
|
||||
| "AUDIT_SUCCESS"
|
||||
| "AUDIT_REJECTED"
|
||||
| "AUDIT_CANCEL";
|
||||
/** 审核类型:1_审核员审核;2_老板审核 */
|
||||
type: "REVIEWER_AUDIT" | "BOSS_AUDIT";
|
||||
/** 驳回原因 */
|
||||
auditReason?: string;
|
||||
/** 审核时间 */
|
||||
auditAt?: string;
|
||||
/** 审核人ID */
|
||||
auditBy?: string;
|
||||
/** 审核人名称 */
|
||||
auditByName?: string;
|
||||
/** 创建人ID */
|
||||
createdBy: string;
|
||||
/** 创建人姓名 */
|
||||
createdByName?: string;
|
||||
/** 创建时间 */
|
||||
createdAt?: string;
|
||||
/** 采购单信息 */
|
||||
purchaseOrderVO?: PurchaseOrderVO;
|
||||
};
|
||||
|
||||
type BoxBrandCreateCmd = {
|
||||
/** 品牌ID */
|
||||
brandId: string;
|
||||
@ -1957,7 +2061,7 @@ declare namespace BusinessAPI {
|
||||
/** 费用类型名称 */
|
||||
costName: string;
|
||||
/** 花销金额 */
|
||||
expenseAmount: string;
|
||||
expenseAmount: number;
|
||||
/** 备注(可填员工、事由等) */
|
||||
remark?: string;
|
||||
};
|
||||
@ -1975,6 +2079,8 @@ declare namespace BusinessAPI {
|
||||
provisionAmount: number;
|
||||
/** 采购单ID */
|
||||
orderId?: string;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
};
|
||||
|
||||
type ExpenseRecordCreateCmd = {
|
||||
@ -3130,10 +3236,6 @@ declare namespace BusinessAPI {
|
||||
watermelonGrade: string;
|
||||
/** 瓜农姓名逗号隔开 */
|
||||
farmerInfo?: string;
|
||||
/** 发货单据 */
|
||||
pdfUrl: string;
|
||||
picUrl: string;
|
||||
|
||||
/** 发货单状态:0_草稿;1_待发货;2_待回款;3_待改签;4_部分回款;5_已回款;6_拒收完结;7_已完结; */
|
||||
state:
|
||||
| "DRAFT"
|
||||
@ -3148,6 +3250,10 @@ declare namespace BusinessAPI {
|
||||
remark?: string;
|
||||
/** 发货单明细 */
|
||||
orderShipItemList?: OrderShipItem[];
|
||||
/** PDF 文件地址 */
|
||||
pdfUrl?: string;
|
||||
/** 图片文件地址 */
|
||||
picUrl?: string;
|
||||
};
|
||||
|
||||
type OrderShipCreateCmd = {
|
||||
@ -3201,10 +3307,10 @@ declare namespace BusinessAPI {
|
||||
remark?: string;
|
||||
/** 发货单明细 */
|
||||
orderShipItemList?: OrderShipItem[];
|
||||
/** 发货单据 */
|
||||
picUrl?: string;
|
||||
/** 发货单据 */
|
||||
/** PDF 文件地址 */
|
||||
pdfUrl?: string;
|
||||
/** 图片文件地址 */
|
||||
picUrl?: string;
|
||||
};
|
||||
|
||||
type OrderShipItem = {
|
||||
@ -3303,8 +3409,10 @@ declare namespace BusinessAPI {
|
||||
remark?: string;
|
||||
/** 发货单明细 */
|
||||
orderShipItemList?: OrderShipItem[];
|
||||
/** 发货单据 */
|
||||
document?: string;
|
||||
/** PDF 文件地址 */
|
||||
pdfUrl?: string;
|
||||
/** 图片文件地址 */
|
||||
picUrl?: string;
|
||||
};
|
||||
|
||||
type OrderShipVO = {
|
||||
@ -3338,8 +3446,10 @@ declare namespace BusinessAPI {
|
||||
watermelonGrade?: string;
|
||||
/** 瓜农姓名逗号隔开 */
|
||||
farmerInfo?: string;
|
||||
/** 发货单据 */
|
||||
document?: string;
|
||||
/** PDF 文件地址 */
|
||||
pdfUrl?: string;
|
||||
/** 图片文件地址 */
|
||||
picUrl?: string;
|
||||
/** 发货单状态:0_草稿;1_待发货;2_待回款;3_待改签;4_部分回款;5_已回款;6_拒收完结;7_已完结; */
|
||||
state?:
|
||||
| "DRAFT"
|
||||
@ -3385,7 +3495,7 @@ declare namespace BusinessAPI {
|
||||
phone: string;
|
||||
/** 微信二维码 */
|
||||
wechatQr?: string;
|
||||
/** 供应商类型:1_瓜农;2_档口; */
|
||||
/** 供应商类型:1_瓜农;2_自家档口;3_其他家档口 */
|
||||
type: "FARMER" | "STALL" | "OTHER_STALL";
|
||||
/** 是否最后一家 */
|
||||
isLast: boolean;
|
||||
@ -3538,8 +3648,8 @@ declare namespace BusinessAPI {
|
||||
phone: string;
|
||||
/** 微信二维码 */
|
||||
wechatQr: string;
|
||||
/** 供应商类型:1_瓜农;2_档口; */
|
||||
type: "FARMER" | "STALL";
|
||||
/** 供应商类型:1_瓜农;2_自家档口;3_其他家档口 */
|
||||
type: "FARMER" | "STALL" | "OTHER_STALL";
|
||||
/** 是否最后一家 */
|
||||
isLast: boolean;
|
||||
/** 空磅是否包含纸箱 */
|
||||
@ -3640,6 +3750,10 @@ declare namespace BusinessAPI {
|
||||
agreementPageQry: AgreementPageQry;
|
||||
};
|
||||
|
||||
type pageAuditParams = {
|
||||
auditPageQry: AuditPageQry;
|
||||
};
|
||||
|
||||
type pageBoxBrandParams = {
|
||||
boxBrandPageQry: BoxBrandPageQry;
|
||||
};
|
||||
@ -3749,6 +3863,19 @@ declare namespace BusinessAPI {
|
||||
totalPages?: number;
|
||||
};
|
||||
|
||||
type PageResponseAuditVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
errMessage?: string;
|
||||
totalCount?: number;
|
||||
pageSize?: number;
|
||||
pageIndex?: number;
|
||||
data?: AuditVO[];
|
||||
empty?: boolean;
|
||||
notEmpty?: boolean;
|
||||
totalPages?: number;
|
||||
};
|
||||
|
||||
type PageResponseBoxBrandVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
@ -4579,9 +4706,9 @@ declare namespace BusinessAPI {
|
||||
/** 报价方式:1_按毛重报价;2_按净重报价; */
|
||||
pricingMethod?: "BY_GROSS_WEIGHT" | "BY_NET_WEIGHT";
|
||||
/** 采购订单状态: 0_草稿;1_审核中;2_已完成;3_已驳回;4_已关闭; */
|
||||
state?: "DRAFT" | "WAITING_AUDIT" | "COMPLETED" | "REJECTED" | "CLOSED";
|
||||
state: "DRAFT" | "WAITING_AUDIT" | "COMPLETED" | "REJECTED" | "CLOSED";
|
||||
/** 采购单审核状态: 1_待报价审核;2_待老板审批;3_老板审批通过;4_报价审核驳回;5_老板审批驳回 */
|
||||
auditState?:
|
||||
auditState:
|
||||
| "NONE"
|
||||
| "PENDING_QUOTE_APPROVAL"
|
||||
| "PENDING_BOSS_APPROVAL"
|
||||
@ -4845,6 +4972,10 @@ declare namespace BusinessAPI {
|
||||
agreementShowQry: AgreementShowQry;
|
||||
};
|
||||
|
||||
type showAuditParams = {
|
||||
auditShowQry: AuditShowQry;
|
||||
};
|
||||
|
||||
type showBoxBrandParams = {
|
||||
boxBrandShowQry: BoxBrandShowQry;
|
||||
};
|
||||
@ -4964,6 +5095,13 @@ declare namespace BusinessAPI {
|
||||
data?: AgreementVO;
|
||||
};
|
||||
|
||||
type SingleResponseAuditVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
errMessage?: string;
|
||||
data?: AuditVO;
|
||||
};
|
||||
|
||||
type SingleResponseBoxBrandVO = {
|
||||
success?: boolean;
|
||||
errCode?: string;
|
||||
@ -5254,6 +5392,10 @@ declare namespace BusinessAPI {
|
||||
remark?: string;
|
||||
/** 状态:1_启用;0_禁用; */
|
||||
status: boolean;
|
||||
/** 供应商类型:1_瓜农;2_自家档口;3_其他家档口 */
|
||||
type: "FARMER" | "STALL" | "OTHER_STALL";
|
||||
/** 经销商ID */
|
||||
dealerId?: number;
|
||||
};
|
||||
|
||||
type SupplierDestroyCmd = {
|
||||
@ -5266,10 +5408,12 @@ declare namespace BusinessAPI {
|
||||
status?: boolean;
|
||||
/** 供应商ID */
|
||||
supplierId?: string;
|
||||
/** 经销商ID */
|
||||
dealerId?: string;
|
||||
/** 供应商名称 */
|
||||
name?: string;
|
||||
/** 供应商类型:1_瓜农;2_档口; */
|
||||
type?: "FARMER" | "STALL";
|
||||
/** 供应商类型:1_瓜农;2_自家档口;3_其他家档口 */
|
||||
type?: "FARMER" | "STALL" | "OTHER_STALL";
|
||||
};
|
||||
|
||||
type SupplierPackageUsage = {
|
||||
@ -5296,6 +5440,8 @@ declare namespace BusinessAPI {
|
||||
status?: boolean;
|
||||
/** 供应商ID */
|
||||
supplierId?: string;
|
||||
/** 经销商ID */
|
||||
dealerId?: string;
|
||||
/** 供应商名称 */
|
||||
name?: string;
|
||||
/** 身份证号 */
|
||||
@ -5304,8 +5450,8 @@ declare namespace BusinessAPI {
|
||||
phone?: string;
|
||||
/** 银行卡号 */
|
||||
bankCard?: string;
|
||||
/** 供应商类型:1_瓜农;2_档口; */
|
||||
type?: "FARMER" | "STALL";
|
||||
/** 供应商类型:1_瓜农;2_自家档口;3_其他家档口 */
|
||||
type?: "FARMER" | "STALL" | "OTHER_STALL";
|
||||
offset?: number;
|
||||
};
|
||||
|
||||
@ -5335,6 +5481,10 @@ declare namespace BusinessAPI {
|
||||
remark?: string;
|
||||
/** 状态:1_启用;0_禁用; */
|
||||
status: boolean;
|
||||
/** 供应商类型:1_瓜农;2_自家档口;3_其他家档口 */
|
||||
type: "FARMER" | "STALL" | "OTHER_STALL";
|
||||
/** 经销商ID */
|
||||
dealerId?: number;
|
||||
};
|
||||
|
||||
type SupplierVO = {
|
||||
@ -5352,8 +5502,10 @@ declare namespace BusinessAPI {
|
||||
bankCard: string;
|
||||
/** 微信收款码URL */
|
||||
wechatQr?: string;
|
||||
/** 供应商类型:1_瓜农;2_档口; */
|
||||
type: "FARMER" | "STALL";
|
||||
/** 供应商类型:1_瓜农;2_自家档口;3_其他家档口 */
|
||||
type: "FARMER" | "STALL" | "OTHER_STALL";
|
||||
/** 经销商ID */
|
||||
dealerId?: number;
|
||||
/** 备注 */
|
||||
remark?: string;
|
||||
/** 状态:1_启用;0_禁用; */
|
||||
@ -5364,6 +5516,8 @@ declare namespace BusinessAPI {
|
||||
createdByName?: string;
|
||||
/** 创建时间 */
|
||||
createdAt?: string;
|
||||
/** 经销商信息 */
|
||||
dealerVO?: DealerVO;
|
||||
};
|
||||
|
||||
type TencentMapConfigValue =
|
||||
|
||||
@ -19,7 +19,6 @@ export async function postApiV1Poster(
|
||||
type?: string;
|
||||
/** 编码类型 */
|
||||
encoding?: string;
|
||||
format?: 'custom' | 'a4';
|
||||
},
|
||||
options?: { [key: string]: any },
|
||||
) {
|
||||
|
||||
338
packages/app-client/src/utils/functions/exportExcel.ts
Normal file
338
packages/app-client/src/utils/functions/exportExcel.ts
Normal file
@ -0,0 +1,338 @@
|
||||
import Taro from "@tarojs/taro";
|
||||
import dayjs from "dayjs";
|
||||
import { utils, write } from "xlsx";
|
||||
|
||||
// 费用统计数据接口
|
||||
interface ExpenseStatistics {
|
||||
totalVehicles: number;
|
||||
totalProvision: number;
|
||||
totalExpense: number;
|
||||
dailyProfit: number;
|
||||
dealerStatistics: Map<string, { vehicleCount: number; totalAmount: number }>;
|
||||
costCategoryStatistics: Map<string, number>;
|
||||
}
|
||||
|
||||
interface ExpenseRecordVO {
|
||||
recordDate?: string;
|
||||
totalProvision?: number;
|
||||
totalExpense?: number;
|
||||
expenseProvisionList?: Array<{
|
||||
dealerName?: string;
|
||||
provisionAmount?: number;
|
||||
}>;
|
||||
expenseCostList?: Array<{ costName?: string; expenseAmount?: number }>;
|
||||
}
|
||||
|
||||
interface ExportExcelOptions {
|
||||
title?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
statistics?: ExpenseStatistics;
|
||||
recordList?: ExpenseRecordVO[];
|
||||
fileName?: string;
|
||||
sheetName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出费用统计Excel文件
|
||||
* @param options 导出配置选项
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
export const exportExpenseStatisticsExcel = async (
|
||||
options: ExportExcelOptions,
|
||||
): Promise<void> => {
|
||||
const {
|
||||
title = "费用统计报表",
|
||||
startDate,
|
||||
endDate,
|
||||
statistics,
|
||||
recordList,
|
||||
fileName,
|
||||
sheetName = "费用统计",
|
||||
} = options;
|
||||
|
||||
if (!recordList || recordList.length === 0) {
|
||||
Taro.showToast({
|
||||
title: "暂无数据可导出",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!startDate || !endDate || !statistics) {
|
||||
Taro.showToast({
|
||||
title: "导出参数不完整",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 创建工作簿
|
||||
const wb = utils.book_new();
|
||||
|
||||
// 创建工作表数据
|
||||
const wsData: string[][] = [];
|
||||
|
||||
// 添加标题信息
|
||||
wsData.push([title]);
|
||||
wsData.push([
|
||||
`统计时间:${dayjs(startDate).format("YYYY年MM月DD日")} ~ ${dayjs(endDate).format("YYYY年MM月DD日")}`,
|
||||
]);
|
||||
wsData.push([]); // 空行
|
||||
|
||||
// 汇总概览
|
||||
wsData.push(["汇总概览"]);
|
||||
wsData.push(["总车次", statistics.totalVehicles + "车"]);
|
||||
wsData.push(["计提总额", statistics.totalProvision.toLocaleString()]);
|
||||
wsData.push(["费用总额", statistics.totalExpense.toLocaleString()]);
|
||||
wsData.push(["日常利润", statistics.dailyProfit.toLocaleString()]);
|
||||
wsData.push([]); // 空行
|
||||
|
||||
// 计提方统计
|
||||
if (statistics.dealerStatistics.size > 0) {
|
||||
wsData.push(["计提方统计"]);
|
||||
wsData.push(["计提方", "车次", "计提金额"]);
|
||||
statistics.dealerStatistics.forEach((stat, dealerName) => {
|
||||
wsData.push([
|
||||
dealerName,
|
||||
stat.vehicleCount + "车",
|
||||
stat.totalAmount.toLocaleString(),
|
||||
]);
|
||||
});
|
||||
wsData.push([]); // 空行
|
||||
}
|
||||
|
||||
// 费用分类汇总
|
||||
if (statistics.costCategoryStatistics.size > 0) {
|
||||
wsData.push(["费用分类汇总"]);
|
||||
wsData.push(["费用类型", "金额"]);
|
||||
statistics.costCategoryStatistics.forEach((amount, costName) => {
|
||||
wsData.push([costName, amount.toLocaleString()]);
|
||||
});
|
||||
wsData.push([]); // 空行
|
||||
}
|
||||
|
||||
// 每日明细
|
||||
wsData.push(["每日花销明细"]);
|
||||
wsData.push(["日期", "车次", "计提金额", "费用金额", "当日利润"]);
|
||||
recordList.forEach((record) => {
|
||||
const vehicleCount = record.expenseProvisionList?.length || 0;
|
||||
const dayProfit =
|
||||
(record.totalProvision || 0) - (record.totalExpense || 0);
|
||||
wsData.push([
|
||||
record.recordDate
|
||||
? dayjs(record.recordDate).format("YYYY年MM月DD日")
|
||||
: "",
|
||||
vehicleCount + "车",
|
||||
(record.totalProvision || 0).toLocaleString(),
|
||||
(record.totalExpense || 0).toLocaleString(),
|
||||
dayProfit.toLocaleString(),
|
||||
]);
|
||||
});
|
||||
|
||||
// 创建工作表
|
||||
const ws = utils.aoa_to_sheet(wsData);
|
||||
|
||||
// 设置列宽
|
||||
const wscols = [
|
||||
{ wch: 20 }, // A列宽度
|
||||
{ wch: 15 }, // B列宽度
|
||||
{ wch: 15 }, // C列宽度
|
||||
{ wch: 15 }, // D列宽度
|
||||
{ wch: 15 }, // E列宽度
|
||||
];
|
||||
ws["!cols"] = wscols;
|
||||
|
||||
// 设置标题行样式(加粗)
|
||||
wsData.forEach((row, index) => {
|
||||
if (
|
||||
row.length > 0 &&
|
||||
typeof row[0] === "string" &&
|
||||
(row[0].includes("统计") ||
|
||||
row[0].includes("汇总") ||
|
||||
row[0].includes("明细"))
|
||||
) {
|
||||
const cellAddress = utils.encode_cell({ r: index, c: 0 });
|
||||
if (!ws[cellAddress]) ws[cellAddress] = {};
|
||||
ws[cellAddress].s = { font: { bold: true } };
|
||||
}
|
||||
});
|
||||
|
||||
// 将工作表添加到工作簿
|
||||
utils.book_append_sheet(wb, ws, sheetName);
|
||||
|
||||
// 生成默认文件名
|
||||
const finalFileName =
|
||||
fileName ||
|
||||
`费用统计_${dayjs(startDate).format("YYYYMMDD")}_${dayjs(endDate).format("YYYYMMDD")}.xlsx`;
|
||||
|
||||
// 根据环境选择不同的导出方式
|
||||
const processEnv = process.env.TARO_ENV;
|
||||
|
||||
if (processEnv === "h5") {
|
||||
// H5环境:创建下载链接
|
||||
const excelBuffer = write(wb, { type: "array", bookType: "xlsx" });
|
||||
const blob = new Blob([excelBuffer], {
|
||||
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
});
|
||||
|
||||
// 创建下载链接
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = finalFileName;
|
||||
link.style.display = "none";
|
||||
|
||||
// 触发下载
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
// 清理URL对象
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
await Taro.showToast({
|
||||
title: "导出成功",
|
||||
icon: "success",
|
||||
});
|
||||
} else {
|
||||
// 小程序环境:使用文件系统API
|
||||
const excelBuffer = write(wb, { type: "array", bookType: "xlsx" });
|
||||
|
||||
// 将文件保存到本地
|
||||
const filePath = `${Taro.env.USER_DATA_PATH}/${finalFileName}`;
|
||||
Taro.getFileSystemManager().writeFile({
|
||||
filePath,
|
||||
data: new Uint8Array(excelBuffer),
|
||||
encoding: "binary",
|
||||
success() {
|
||||
console.log("文件保存成功");
|
||||
// 分享文件
|
||||
Taro.shareFileMessage({
|
||||
filePath,
|
||||
});
|
||||
Taro.showToast({
|
||||
title: "导出成功",
|
||||
icon: "success",
|
||||
});
|
||||
},
|
||||
fail(error) {
|
||||
console.error("文件保存失败:", error);
|
||||
Taro.showToast({
|
||||
title: "导出失败",
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("导出失败:", error);
|
||||
Taro.showToast({
|
||||
title: "导出失败",
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 通用Excel导出函数
|
||||
* @param data 工作表数据
|
||||
* @param fileName 文件名
|
||||
* @param sheetName 工作表名称
|
||||
* @param colWidths 列宽配置(可选)
|
||||
*/
|
||||
export const exportExcel = async (
|
||||
data: any[][],
|
||||
fileName: string,
|
||||
sheetName: string = "Sheet1",
|
||||
colWidths?: Array<{ wch: number }>,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
// 创建工作簿
|
||||
const wb = utils.book_new();
|
||||
|
||||
// 创建工作表
|
||||
const ws = utils.aoa_to_sheet(data);
|
||||
|
||||
// 设置列宽(如果提供)
|
||||
if (colWidths) {
|
||||
ws["!cols"] = colWidths;
|
||||
}
|
||||
|
||||
// 将工作表添加到工作簿
|
||||
utils.book_append_sheet(wb, ws, sheetName);
|
||||
|
||||
// 根据环境选择不同的导出方式
|
||||
const processEnv = process.env.TARO_ENV;
|
||||
|
||||
if (processEnv === "h5") {
|
||||
// H5环境:创建下载链接
|
||||
const excelBuffer = write(wb, { type: "array", bookType: "xlsx" });
|
||||
const blob = new Blob([excelBuffer], {
|
||||
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
});
|
||||
|
||||
// 创建下载链接
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = fileName.endsWith(".xlsx")
|
||||
? fileName
|
||||
: `${fileName}.xlsx`;
|
||||
link.style.display = "none";
|
||||
|
||||
// 触发下载
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
// 清理URL对象
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
await Taro.showToast({
|
||||
title: "导出成功",
|
||||
icon: "success",
|
||||
});
|
||||
} else {
|
||||
// 小程序环境:使用文件系统API
|
||||
const excelBuffer = write(wb, { type: "array", bookType: "xlsx" });
|
||||
|
||||
// 确保文件名有.xlsx后缀
|
||||
const finalFileName = fileName.endsWith(".xlsx")
|
||||
? fileName
|
||||
: `${fileName}.xlsx`;
|
||||
// 将文件保存到本地
|
||||
const filePath = `${Taro.env.USER_DATA_PATH}/${finalFileName}`;
|
||||
Taro.getFileSystemManager().writeFile({
|
||||
filePath,
|
||||
data: new Uint8Array(excelBuffer),
|
||||
encoding: "binary",
|
||||
success() {
|
||||
console.log("文件保存成功");
|
||||
// 分享文件
|
||||
Taro.shareFileMessage({
|
||||
filePath,
|
||||
});
|
||||
Taro.showToast({
|
||||
title: "导出成功",
|
||||
icon: "success",
|
||||
});
|
||||
},
|
||||
fail(error) {
|
||||
console.error("文件保存失败:", error);
|
||||
Taro.showToast({
|
||||
title: "导出失败",
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("导出失败:", error);
|
||||
Taro.showToast({
|
||||
title: "导出失败",
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -49,3 +49,6 @@ export * from "./reporter";
|
||||
|
||||
// 路由相关
|
||||
export * from "./routeGuard";
|
||||
|
||||
// Excel导出相关
|
||||
export * from "./exportExcel";
|
||||
|
||||
30437
pnpm-lock.yaml
30437
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user