feat(search): 更新搜索功能和审核流程

- 将默认搜索字段从车牌号改为采购单号
- 添加采购单号和车次号搜索选项
- 在搜索时清除其他搜索字段的值
- 修复Picker组件的默认值设置
- 优化搜索类型选择的安全性
- 在审核列表跳转时传递审核ID参数
- 添加审核驳回状态显示功能
- 更新消息处理中的审核页面跳转逻辑
- 修复模板配置更新中的空指针问题
- 移除订单项目中的审核进度按钮
- 重构基本信息服务中的成本计算逻辑
- 使用新的利润计算服务替代旧方法
- 将个人利润标签更新为利润标签
- 提升应用版本号至v0.0.77
This commit is contained in:
shenyifei 2026-01-16 11:04:58 +08:00
parent cb24afa3ee
commit 51a261fdf2
15 changed files with 301 additions and 206 deletions

View File

@ -44,9 +44,19 @@ export default function AuditList(props: IAuditListProps) {
const toolbar: ToolBar<BusinessAPI.AuditVO> = { const toolbar: ToolBar<BusinessAPI.AuditVO> = {
...defaultToolbar, ...defaultToolbar,
search: { search: {
activeKey: "plate", activeKey: "orderSn",
defaultActiveKey: "plate", defaultActiveKey: "orderSn",
items: [ items: [
{
key: "orderSn",
name: "采购单号",
placeholder: "请输入采购单号",
},
{
key: "vehicleNo",
name: "车次号",
placeholder: "请输入车次号",
},
{ {
key: "plate", key: "plate",
name: "车牌号", name: "车牌号",
@ -349,6 +359,7 @@ export default function AuditList(props: IAuditListProps) {
Taro.navigateTo({ Taro.navigateTo({
url: buildUrl(purchase.path[orderVO.type].create, { url: buildUrl(purchase.path[orderVO.type].create, {
orderId: orderVO.orderId, orderId: orderVO.orderId,
auditId: auditVO.auditId,
}), }),
}); });
e.stopPropagation(); e.stopPropagation();

View File

@ -210,8 +210,19 @@ export default <T extends {}, Q extends Query = Query>(
} }
onClear={() => actionRef.current.reload()} onClear={() => actionRef.current.reload()}
onSearch={(val) => { onSearch={(val) => {
// 将所有 search items 的 key 设置为 undefined
const clearedSearchKeys = (toolbar?.search?.items || []).reduce(
(acc, item) => ({
...acc,
[item.key]: undefined,
}),
{},
);
// 只保留当前搜索类型的值
setQuery({ setQuery({
...query, ...query,
...clearedSearchKeys,
[searchType]: val == "" ? undefined : val, [searchType]: val == "" ? undefined : val,
pageIndex: 1, pageIndex: 1,
}); });
@ -399,6 +410,11 @@ export default <T extends {}, Q extends Query = Query>(
<Picker <Picker
title="请选择查询条件" title="请选择查询条件"
visible={lightTheme} visible={lightTheme}
defaultValue={
toolbar?.search?.defaultActiveKey
? [toolbar?.search?.defaultActiveKey]
: []
}
options={[ options={[
toolbar?.search?.items?.map((c) => ({ toolbar?.search?.items?.map((c) => ({
value: c.key, value: c.key,
@ -406,7 +422,7 @@ export default <T extends {}, Q extends Query = Query>(
})) || [], })) || [],
]} ]}
onConfirm={(value: any) => { onConfirm={(value: any) => {
setSearchType(value[0].value); setSearchType(value[0]?.value);
}} }}
onClose={() => setLightTheme(false)} onClose={() => setLightTheme(false)}
/> />

View File

@ -10,6 +10,7 @@ import {
ProfitTableTemplate, ProfitTableTemplate,
} from "@/utils"; } from "@/utils";
import dayjs from "dayjs"; import dayjs from "dayjs";
import { ProfitCalculationService } from "@/utils/classes/calculators";
interface Step3SuccessProps { interface Step3SuccessProps {
pdfUrl: string; pdfUrl: string;
@ -60,7 +61,7 @@ export default function Step3Success(props: Step3SuccessProps) {
for (const order of orderVOList) { for (const order of orderVOList) {
// 如果还没有到达当前车次,继续 // 如果还没有到达当前车次,继续
if (includeNext) { if (includeNext) {
const profitRow = calculateOrderProfit(order); const profitRow = ProfitCalculationService.calculateOrderProfit(order);
profitData.push(profitRow); profitData.push(profitRow);
// 如果是当前车次,停止添加 // 如果是当前车次,停止添加

View File

@ -375,17 +375,22 @@ export default function OrderItem(props: IOrderItemProps) {
</> </>
)} )}
{orderVO.state === "AUDITING" && ( {/*{orderVO.state === "AUDITING" && (*/}
<Button {/* <Button*/}
type={"primary"} {/* type={"primary"}*/}
size={"small"} {/* size={"small"}*/}
onClick={(e) => { {/* onClick={(e) => {*/}
e.stopPropagation(); {/* Taro.navigateTo({*/}
}} {/* url: buildUrl(purchase.path[orderVO.type].result, {*/}
> {/* orderId: orderVO.orderId,*/}
{/* }),*/}
</Button> {/* });*/}
)} {/* e.stopPropagation();*/}
{/* }}*/}
{/* >*/}
{/* 审核进度*/}
{/* </Button>*/}
{/*)}*/}
</View> </View>
</View> </View>
); );

View File

@ -38,9 +38,19 @@ export default function OrderList(props: IOrderListProps) {
const toolbar: ToolBar<BusinessAPI.OrderVO> = { const toolbar: ToolBar<BusinessAPI.OrderVO> = {
...defaultToolbar, ...defaultToolbar,
search: { search: {
activeKey: "plate", activeKey: "orderSn",
defaultActiveKey: "plate", defaultActiveKey: "orderSn",
items: [ items: [
{
key: "orderSn",
name: "采购单号",
placeholder: "请输入采购单号",
},
{
key: "vehicleNo",
name: "车次号",
placeholder: "请输入车次号",
},
{ {
key: "plate", key: "plate",
name: "车牌号", name: "车牌号",

View File

@ -63,11 +63,6 @@ export default forwardRef<
(cost) => cost.type === "LOGISTICS_TYPE" && cost.name === "短驳费", (cost) => cost.type === "LOGISTICS_TYPE" && cost.name === "短驳费",
); );
// 草帘费
const curtainCost = costList.find(
(cost) => cost.type === "LOGISTICS_TYPE" && cost.name === "草帘费",
);
const formatter = (type: string, option: PickerOption) => { const formatter = (type: string, option: PickerOption) => {
switch (type) { switch (type) {
case "year": case "year":
@ -98,6 +93,8 @@ export default forwardRef<
// 编辑值的状态(用于弹窗中的临时编辑) // 编辑值的状态(用于弹窗中的临时编辑)
const [editValues, setEditValues] = useState({ const [editValues, setEditValues] = useState({
driver: orderVehicle?.driver || "",
dealerName: orderVehicle?.dealerName || "",
vehicleNo: orderVehicle?.vehicleNo || "", vehicleNo: orderVehicle?.vehicleNo || "",
origin: orderVehicle?.origin || "", origin: orderVehicle?.origin || "",
destination: orderVehicle?.destination || "", destination: orderVehicle?.destination || "",
@ -177,6 +174,8 @@ export default forwardRef<
const openBasicInfoPopup = () => { const openBasicInfoPopup = () => {
if (readOnly) return; if (readOnly) return;
setEditValues({ setEditValues({
driver: orderVehicle?.driver || "",
dealerName: orderVehicle?.dealerName || "",
vehicleNo: orderVehicle?.vehicleNo || "", vehicleNo: orderVehicle?.vehicleNo || "",
origin: orderVehicle?.origin || "", origin: orderVehicle?.origin || "",
destination: orderVehicle?.destination || "", destination: orderVehicle?.destination || "",
@ -194,74 +193,50 @@ export default forwardRef<
// 保存基础信息 // 保存基础信息
const saveBasicInfo = () => { const saveBasicInfo = () => {
if (onChange) { if (onChange) {
const newOrderCostList = orderVO.orderCostList.map((orderCost) => { const newOrderCostList = orderVO.orderCostList.filter((cost) => {
if (orderCost.type === "LOGISTICS_TYPE") { return cost.type !== "LOGISTICS_TYPE";
if (editValues.priceType === "MAIN_FREIGHT" && mainCost) {
return {
...orderCost,
costId: mainCost.costId,
name: mainCost.name,
belong: mainCost.belong,
price: Number(editValues.price),
unit: mainCost.unit || orderCost.unit || "元",
};
}
if (editValues.priceType === "SHORT_TRANSPORT" && shortCost) {
return {
...orderCost,
costId: shortCost.costId,
name: shortCost.name,
belong: shortCost.belong,
price: Number(editValues.price),
unit: shortCost.unit || orderCost.unit || "元",
};
}
}
return orderCost;
}); });
if (editValues.strawCurtainPrice) { const orderVehicle = editValues;
if (curtainCost) { const costName =
const orderStrawCost = newOrderCostList.find( orderVehicle.priceType === "SHORT_TRANSPORT" ? "短驳费" : "主运费";
(orderCost) => const cost2 = costList?.find(
orderCost.type === "LOGISTICS_TYPE" && (cost) => cost.name === costName && cost.type === "LOGISTICS_TYPE",
orderCost.name === "草帘费",
); );
if (orderStrawCost) {
newOrderCostList.map((orderCost) => { // 加运费
if ( if (orderVehicle.price && cost2) {
orderCost.type === "LOGISTICS_TYPE" &&
orderCost.name === "草帘费"
) {
return {
...orderCost,
costId: orderStrawCost.costId,
name: orderStrawCost.name,
belong: orderStrawCost.belong,
price: editValues.openStrawCurtain
? editValues.strawCurtainPrice
: 0,
unit: orderStrawCost.unit || orderCost.unit || "元",
};
}
});
} else {
newOrderCostList.push({ newOrderCostList.push({
orderCostId: generateShortId(), orderCostId: generateShortId(),
costId: curtainCost.costId || "", costId: cost2.costId || "",
name: curtainCost.name || "", name: cost2.name || "",
price: editValues.openStrawCurtain price: orderVehicle.price,
? editValues.strawCurtainPrice unit: cost2.unit || "元",
: 0,
unit: curtainCost.unit || "元",
count: 1, count: 1,
type: curtainCost.type, type: "LOGISTICS_TYPE",
costItemIds: [], costItemIds: [],
belong: curtainCost.belong, belong: cost2.belong,
selected: true, selected: true,
}); });
} }
}
const cost3 = costList?.find(
(cost) => cost.name === "草帘费" && cost.type === "LOGISTICS_TYPE",
);
// 加草帘
if (orderVehicle.openStrawCurtain && cost3) {
newOrderCostList.push({
orderCostId: generateShortId(),
costId: cost3.costId || "",
name: cost3.name || "",
price: orderVehicle.strawCurtainPrice!,
unit: cost3.unit || "元",
count: 1,
type: "LOGISTICS_TYPE",
costItemIds: [],
belong: cost3.belong,
selected: true,
});
} }
const updatedOrder = { const updatedOrder = {

View File

@ -55,7 +55,7 @@ export default forwardRef<
// 更新模板配置 // 更新模板配置
const updateTemplateConfig = (template: any[], data: any) => { const updateTemplateConfig = (template: any[], data: any) => {
let templateList: any[] = []; let templateList: any[] = [];
template.map(async (module: any) => { template?.map(async (module: any) => {
let newModule = { ...module }; let newModule = { ...module };
if (data[module.type]) { if (data[module.type]) {
newModule.config = { ...module.config, ...data[module.type] }; newModule.config = { ...module.config, ...data[module.type] };

View File

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

View File

@ -90,7 +90,7 @@ export default hocAuth(function Page(props: CommonComponent) {
const estimatedArrivalDate = orderVO.orderShipList[0].estimatedArrivalDate; const estimatedArrivalDate = orderVO.orderShipList[0].estimatedArrivalDate;
const personalProfit = calculator.getPersonalProfit(); const personalProfit = calculator.getNetProfit();
return ( return (
<> <>
<View <View

View File

@ -376,7 +376,7 @@ export default hocAuth(function Page(props: CommonComponent) {
orderVO.orderDealer.profitSharing === undefined) && orderVO.orderDealer.profitSharing === undefined) &&
orderVO.orderDealer.shareAdjusted orderVO.orderDealer.shareAdjusted
) { ) {
orderVO.orderDealer.profitSharing = calculator.getPersonalProfit(); orderVO.orderDealer.profitSharing = calculator.getNetProfit();
} }
// 损失金额 // 损失金额
@ -525,6 +525,7 @@ export default hocAuth(function Page(props: CommonComponent) {
0, 0,
); );
} }
item.selected = true;
return item; return item;
}); });
@ -652,7 +653,7 @@ export default hocAuth(function Page(props: CommonComponent) {
} }
const calculator = new OrderCalculator(orderVO); const calculator = new OrderCalculator(orderVO);
const personalProfit = calculator.getPersonalProfit(); const personalProfit = calculator.getNetProfit();
const sections = ( const sections = (
orderVO.orderDealer.shortName === "信誉楼" orderVO.orderDealer.shortName === "信誉楼"
@ -854,7 +855,7 @@ export default hocAuth(function Page(props: CommonComponent) {
}} }}
> >
<View className="flex items-center justify-between px-4 py-3"> <View className="flex items-center justify-between px-4 py-3">
<View className="text-base font-bold text-gray-700"></View> <View className="text-base font-bold text-gray-700"></View>
<View <View
className={classNames("text-2xl font-bold", { className={classNames("text-2xl font-bold", {
"text-primary": personalProfit > 0, "text-primary": personalProfit > 0,

View File

@ -143,7 +143,7 @@ export default hocAuth(function Page(props: CommonComponent) {
orderVO: BusinessAPI.OrderVO, orderVO: BusinessAPI.OrderVO,
) => { ) => {
let templateList: any[] = []; let templateList: any[] = [];
template.map(async (module: any) => { template?.map(async (module: any) => {
let newModule = { ...module }; let newModule = { ...module };
if (data[module.type]) { if (data[module.type]) {
newModule.config = { ...module.config, ...data[module.type] }; newModule.config = { ...module.config, ...data[module.type] };

View File

@ -101,6 +101,7 @@ export default hocAuth(function Page() {
render={(messageReceiverVO: BusinessAPI.MessageReceiverVO, index) => { render={(messageReceiverVO: BusinessAPI.MessageReceiverVO, index) => {
const { messageVO } = messageReceiverVO; const { messageVO } = messageReceiverVO;
return ( return (
<View className={"mb-2.5"} key={index}>
<View <View
className={classNames( className={classNames(
"relative flex flex-col divide-y divide-neutral-100 overflow-hidden rounded-xl bg-white shadow-sm", "relative flex flex-col divide-y divide-neutral-100 overflow-hidden rounded-xl bg-white shadow-sm",
@ -161,7 +162,9 @@ export default hocAuth(function Page() {
<View className="flex flex-row items-center justify-between"> <View className="flex flex-row items-center justify-between">
<Text className="text-neutral-dark text-xs"></Text> <Text className="text-neutral-dark text-xs"></Text>
<Text className="text-neutral-darkest text-xs font-medium"> <Text className="text-neutral-darkest text-xs font-medium">
{dayjs(messageReceiverVO.readAt).format("YYYY-MM-DD HH:mm")} {dayjs(messageReceiverVO.readAt).format(
"YYYY-MM-DD HH:mm",
)}
</Text> </Text>
</View> </View>
)} )}
@ -195,10 +198,15 @@ export default hocAuth(function Page() {
}, },
}); });
if (!success || !auditVO) {
return;
}
if (auditVO.subjectType === "PURCHASE_ORDER") {
if ( if (
success && auditVO.type === "REVIEWER_AUDIT" ||
auditVO && (auditVO.type === "BOSS_AUDIT" &&
auditVO.subjectType === "PURCHASE_ORDER" auditVO.state === "AUDIT_REJECTED")
) { ) {
await Taro.navigateTo({ await Taro.navigateTo({
url: buildUrl("/pages/audit/audit", { url: buildUrl("/pages/audit/audit", {
@ -206,6 +214,17 @@ export default hocAuth(function Page() {
auditId: auditVO.auditId, auditId: auditVO.auditId,
}), }),
}); });
return;
}
if (auditVO.type === "BOSS_AUDIT") {
await Taro.navigateTo({
url: buildUrl("/pages/approval/audit", {
orderId: auditVO.subjectId,
auditId: auditVO.auditId,
}),
});
return;
}
} }
} }
}} }}
@ -224,6 +243,7 @@ export default hocAuth(function Page() {
</Button> </Button>
</View> </View>
</View> </View>
</View>
); );
}} }}
request={async (params) => { request={async (params) => {

View File

@ -84,6 +84,7 @@ export default hocAuth(function Page(props: CommonComponent) {
const defaultActive = router.params.active as number; const defaultActive = router.params.active as number;
const defaultSupplierId = router.params.supplierId as string; const defaultSupplierId = router.params.supplierId as string;
const defaultOrderSupplierId = router.params.orderSupplierId as string; const defaultOrderSupplierId = router.params.orderSupplierId as string;
const auditId = router.params.auditId as BusinessAPI.AuditVO["auditId"];
const orderOptionRef = useRef<MadeOptionRef>(null); const orderOptionRef = useRef<MadeOptionRef>(null);
const vehicleRef = useRef<OrderVehicleRef>(null); const vehicleRef = useRef<OrderVehicleRef>(null);
@ -99,6 +100,23 @@ export default hocAuth(function Page(props: CommonComponent) {
const supplierPackageRefs = useRef<SupplierPackageRef[]>([]); const supplierPackageRefs = useRef<SupplierPackageRef[]>([]);
const [order, setOrder] = useState<BusinessAPI.OrderVO>(); const [order, setOrder] = useState<BusinessAPI.OrderVO>();
const [auditVO, setAuditVO] = useState<BusinessAPI.AuditVO>();
useEffect(() => {
if (auditId) {
business.audit
.showAudit({
auditShowQry: {
auditId,
},
})
.then(({ data: { data: auditVO, success: auditSuccess } }) => {
if (auditSuccess && auditVO) {
setAuditVO(auditVO);
}
});
}
}, [auditId]);
const [step, setStep] = useState<any>(); const [step, setStep] = useState<any>();
@ -257,6 +275,17 @@ export default hocAuth(function Page(props: CommonComponent) {
return ( return (
<> <>
<View className={"sticky top-0 z-11"}> <View className={"sticky top-0 z-11"}>
{auditVO?.state === "AUDIT_REJECTED" && (
<View className="flex flex-col gap-2 bg-red-50 p-3">
<View className="flex items-center gap-2">
<Icon name="exclamation" color="red" size={16} />
<View className="text-base font-bold text-red-700"></View>
</View>
<View className="pl-6 text-sm text-red-600">
{auditVO?.auditReason || "暂无驳回原因"}
</View>
</View>
)}
{step.value < purchase.madeSteps.length && ( {step.value < purchase.madeSteps.length && (
<View className="h-12 bg-white p-2.5 shadow-sm"> <View className="h-12 bg-white p-2.5 shadow-sm">
<View className="step-indicator flex h-2 rounded-full bg-gray-200"> <View className="step-indicator flex h-2 rounded-full bg-gray-200">

View File

@ -70,6 +70,7 @@ export default hocAuth(function Page(props: CommonComponent) {
const defaultActive = router.params.active as number; const defaultActive = router.params.active as number;
const defaultSupplierId = router.params.supplierId as string; const defaultSupplierId = router.params.supplierId as string;
const defaultOrderSupplierId = router.params.orderSupplierId as string; const defaultOrderSupplierId = router.params.orderSupplierId as string;
const auditId = router.params.auditId as BusinessAPI.AuditVO["auditId"];
const orderOptionRef = useRef<MadeOptionRef>(null); const orderOptionRef = useRef<MadeOptionRef>(null);
const vehicleRef = useRef<OrderVehicleRef>(null); const vehicleRef = useRef<OrderVehicleRef>(null);
@ -81,8 +82,23 @@ export default hocAuth(function Page(props: CommonComponent) {
const stallPackageRefs = useRef<StallPackageRef[]>([]); const stallPackageRefs = useRef<StallPackageRef[]>([]);
const [orderVO, setOrderVO] = useState<BusinessAPI.OrderVO>(); const [orderVO, setOrderVO] = useState<BusinessAPI.OrderVO>();
const [auditVO, setAuditVO] = useState<BusinessAPI.AuditVO>();
console.log("orderVO", orderVO); useEffect(() => {
if (auditId) {
business.audit
.showAudit({
auditShowQry: {
auditId,
},
})
.then(({ data: { data: auditVO, success: auditSuccess } }) => {
if (auditSuccess && auditVO) {
setAuditVO(auditVO);
}
});
}
}, [auditId]);
const [step, setStep] = useState<any>(); const [step, setStep] = useState<any>();
@ -243,6 +259,17 @@ export default hocAuth(function Page(props: CommonComponent) {
return ( return (
<> <>
<View className={"sticky top-0 z-11"}> <View className={"sticky top-0 z-11"}>
{auditVO?.state === "AUDIT_REJECTED" && (
<View className="flex flex-col gap-2 bg-red-50 p-3">
<View className="flex items-center gap-2">
<Icon name="exclamation" color="red" size={16} />
<View className="text-base font-bold text-red-700"></View>
</View>
<View className="pl-6 text-sm text-red-600">
{auditVO?.auditReason || "暂无驳回原因"}
</View>
</View>
)}
{step.value < purchase.marketSteps.length && ( {step.value < purchase.marketSteps.length && (
<View className="h-12 bg-white p-2.5 shadow-sm"> <View className="h-12 bg-white p-2.5 shadow-sm">
<View className="step-indicator flex h-2 rounded-full bg-gray-200"> <View className="step-indicator flex h-2 rounded-full bg-gray-200">

View File

@ -21,7 +21,7 @@ export class ProfitCalculationService {
// 报价金额 // 报价金额
const quoteAmount = orderCalculator.getSalesAmount(); const quoteAmount = orderCalculator.getSalesAmount();
// 计算利润 // 计算利润
const profit = orderCalculator.getPersonalProfit(); const profit = orderCalculator.getNetProfit();
return { return {
vehicleNo, vehicleNo,