feat(expenses): 新增费用统计页面及功能优化
- 在Icon组件中新增箭头图标(arrow-up、arrow-down) - 优化费用创建页面,支持从路由参数获取默认日期 - 费用创建页面增加返回按钮 - 移除旧版日期选择器注释代码 - 新增费用统计页面,实现按日期范围查询费用记录 - 实现费用统计计算逻辑,包括总车次、计提总额、费用总额和日常利润 - 添加计提方统计和费用分类汇总功能 - 支持每日花销明细的展开与收起 - 增加日期范围选择日历组件 - 页面布局优化,提升用户体验
This commit is contained in:
parent
8562aed7d1
commit
c98d4313fd
@ -22,6 +22,11 @@ export default function ExpenseCostList(props: IExpenseCostProps) {
|
|||||||
已录入费用
|
已录入费用
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
{expenseRecord?.expenseCostList?.length === 0 && (
|
||||||
|
<View className="py-2 text-center text-sm text-gray-500">
|
||||||
|
暂无费用数据
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
<View className="divide-y divide-gray-100">
|
<View className="divide-y divide-gray-100">
|
||||||
{expenseCosts.map((expense) => {
|
{expenseCosts.map((expense) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -61,6 +61,12 @@ export default function ExpenseCostList(props: IExpenseCostProps) {
|
|||||||
计提汇总
|
计提汇总
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{expenseRecord?.expenseProvisionList?.length === 0 && (
|
||||||
|
<View className="py-2 text-center text-sm text-gray-500">
|
||||||
|
暂无计提数据
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
{Object.entries(dealerGroups).map(([dealerName, expenseProvisions]) => (
|
{Object.entries(dealerGroups).map(([dealerName, expenseProvisions]) => (
|
||||||
<View
|
<View
|
||||||
key={dealerName}
|
key={dealerName}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import classNames from "classnames";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export type IconNames =
|
export type IconNames =
|
||||||
|
| "arrow-up"
|
||||||
|
| "arrow-down"
|
||||||
| "trash-can"
|
| "trash-can"
|
||||||
| "pen"
|
| "pen"
|
||||||
| "chevron-up"
|
| "chevron-up"
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 5042354 */
|
font-family: "iconfont"; /* Project id 5042354 */
|
||||||
src: url('//at.alicdn.com/t/c/font_5042354_coygo8knq0j.woff2?t=1766029596765') format('woff2'),
|
src: url('//at.alicdn.com/t/c/font_5042354_iq8kowp9bio.woff2?t=1766132042848') format('woff2'),
|
||||||
url('//at.alicdn.com/t/c/font_5042354_coygo8knq0j.woff?t=1766029596765') format('woff'),
|
url('//at.alicdn.com/t/c/font_5042354_iq8kowp9bio.woff?t=1766132042848') format('woff'),
|
||||||
url('//at.alicdn.com/t/c/font_5042354_coygo8knq0j.ttf?t=1766029596765') format('truetype');
|
url('//at.alicdn.com/t/c/font_5042354_iq8kowp9bio.ttf?t=1766132042848') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
@ -13,6 +13,14 @@
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-arrow-down:before {
|
||||||
|
content: "\e62d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-arrow-up:before {
|
||||||
|
content: "\e633";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-chevron-up:before {
|
.icon-chevron-up:before {
|
||||||
content: "\e62c";
|
content: "\e62c";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,27 @@
|
|||||||
import { useShareAppMessage } from "@tarojs/taro";
|
import Taro, { useShareAppMessage } from "@tarojs/taro";
|
||||||
import hocAuth from "@/hocs/auth";
|
import hocAuth from "@/hocs/auth";
|
||||||
import { CommonComponent } from "@/types/typings";
|
import { CommonComponent } from "@/types/typings";
|
||||||
import { View } from "@tarojs/components";
|
import { View } from "@tarojs/components";
|
||||||
import { ExpenseCostList, ExpenseProvisionList, Icon } from "@/components";
|
import { ExpenseCostList, ExpenseProvisionList, Icon } from "@/components";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Button, Calendar, Dialog, SafeArea, Toast } from "@nutui/nutui-react-taro";
|
import {
|
||||||
|
Button,
|
||||||
|
Calendar,
|
||||||
|
Dialog,
|
||||||
|
SafeArea,
|
||||||
|
Toast,
|
||||||
|
} from "@nutui/nutui-react-taro";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { business } from "@/services";
|
import { business } from "@/services";
|
||||||
import { globalStore } from "@/store/global-store";
|
import { globalStore } from "@/store/global-store";
|
||||||
|
|
||||||
export default hocAuth(function Page(props: CommonComponent) {
|
export default hocAuth(function Page(props: CommonComponent) {
|
||||||
const { shareOptions } = props;
|
const { shareOptions, router } = props;
|
||||||
|
const date = router.params.date as string;
|
||||||
|
|
||||||
const [currentDate, setCurrentDate] = useState<string>(
|
const [currentDate, setCurrentDate] = useState<string>(() => {
|
||||||
dayjs().format("YYYY-MM-DD"),
|
return dayjs(date || new Date()).format("YYYY-MM-DD");
|
||||||
);
|
});
|
||||||
const [expenseRecord, setExpenseRecord] =
|
const [expenseRecord, setExpenseRecord] =
|
||||||
useState<BusinessAPI.ExpenseRecordVO>();
|
useState<BusinessAPI.ExpenseRecordVO>();
|
||||||
const { setLoading } = globalStore((state: any) => state);
|
const { setLoading } = globalStore((state: any) => state);
|
||||||
@ -266,12 +273,28 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
<View className="border-t border-gray-200 pt-2.5">
|
<View className="border-t border-gray-200 pt-2.5">
|
||||||
<View className="flex items-center justify-between">
|
<View className="flex items-center justify-between">
|
||||||
<View className="text-neutral-darker text-sm">日常利润</View>
|
<View className="text-neutral-darker text-sm">日常利润</View>
|
||||||
<View className="text-primary font-medium">
|
<View
|
||||||
|
className={`text-sm font-medium ${(expenseRecord?.dailyProfit || 0) >= 0 ? "text-green-600" : "text-red-600"}`}
|
||||||
|
>
|
||||||
¥{(expenseRecord?.dailyProfit || 0).toLocaleString()}
|
¥{(expenseRecord?.dailyProfit || 0).toLocaleString()}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className="text-primary bg-primary/10 mt-1 inline-block rounded px-2 py-1 text-sm">
|
<View className={"flex flex-row items-center"}>
|
||||||
<Icon name={"arrow-up"} className="mr-1" />
|
<Icon
|
||||||
|
name={
|
||||||
|
(expenseRecord?.dailyProfit || 0) >= 0
|
||||||
|
? "arrow-up"
|
||||||
|
: "arrow-down"
|
||||||
|
}
|
||||||
|
color={
|
||||||
|
(expenseRecord?.dailyProfit || 0) >= 0 ? "green" : "red"
|
||||||
|
}
|
||||||
|
className="mr-1"
|
||||||
|
size={14}
|
||||||
|
/>
|
||||||
|
<View
|
||||||
|
className={`text-sm font-medium ${(expenseRecord?.dailyProfit || 0) >= 0 ? "text-green-600" : "text-red-600"}`}
|
||||||
|
>
|
||||||
{(expenseRecord?.dailyProfit || 0) >= 0
|
{(expenseRecord?.dailyProfit || 0) >= 0
|
||||||
? "盈利状态"
|
? "盈利状态"
|
||||||
: "亏损状态"}
|
: "亏损状态"}
|
||||||
@ -280,8 +303,22 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
</View>
|
||||||
<View className="sticky bottom-0 z-10 bg-white">
|
<View className="sticky bottom-0 z-10 bg-white">
|
||||||
<View className="flex justify-between gap-2 border-t border-gray-200 p-2.5">
|
<View className="flex justify-between gap-2 border-t border-gray-200 p-2.5">
|
||||||
|
{/* 返回 */}
|
||||||
|
<View className="flex-1">
|
||||||
|
<Button
|
||||||
|
size={"large"}
|
||||||
|
block
|
||||||
|
type={"default"}
|
||||||
|
onClick={() => {
|
||||||
|
Taro.navigateBack();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
返回
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
<View className="flex-1">
|
<View className="flex-1">
|
||||||
<Button
|
<Button
|
||||||
size={"large"}
|
size={"large"}
|
||||||
@ -325,28 +362,6 @@ export default hocAuth(function Page(props: CommonComponent) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/*<DatePicker*/}
|
|
||||||
{/* title="日期选择"*/}
|
|
||||||
{/* type="date"*/}
|
|
||||||
{/* visible={show}*/}
|
|
||||||
{/* value={new Date(currentDate)}*/}
|
|
||||||
{/* showChinese*/}
|
|
||||||
{/* onClose={() => setShow(false)}*/}
|
|
||||||
{/* threeDimensional={false}*/}
|
|
||||||
{/* onConfirm={(_, values) => {*/}
|
|
||||||
{/* const newDate = dayjs(values.join("-")).format("YYYY-MM-DD");*/}
|
|
||||||
|
|
||||||
{/* // 如果没有未保存变更,直接切换日期*/}
|
|
||||||
{/* if (!hasUnsavedChanges) {*/}
|
|
||||||
{/* setCurrentDate(newDate);*/}
|
|
||||||
{/* } else {*/}
|
|
||||||
{/* // 有未保存变更时,保存待切换日期,显示确认对话框*/}
|
|
||||||
{/* setPendingDate(newDate);*/}
|
|
||||||
{/* setConfirmVisible(true);*/}
|
|
||||||
{/* }*/}
|
|
||||||
{/* }}*/}
|
|
||||||
{/*/>*/}
|
|
||||||
|
|
||||||
{/* 日期切换确认对话框 */}
|
{/* 日期切换确认对话框 */}
|
||||||
<Dialog
|
<Dialog
|
||||||
visible={confirmVisible}
|
visible={confirmVisible}
|
||||||
|
|||||||
@ -1,6 +1,13 @@
|
|||||||
import { useShareAppMessage } from "@tarojs/taro";
|
import Taro, { useShareAppMessage } from "@tarojs/taro";
|
||||||
import hocAuth from "@/hocs/auth";
|
import hocAuth from "@/hocs/auth";
|
||||||
import { CommonComponent } from "@/types/typings";
|
import { CommonComponent } from "@/types/typings";
|
||||||
|
import { View } from "@tarojs/components";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { Icon } from "@/components";
|
||||||
|
import { Button, Calendar, SafeArea } from "@nutui/nutui-react-taro";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { business } from "@/services";
|
||||||
|
import { globalStore } from "@/store/global-store";
|
||||||
|
|
||||||
interface PageProps extends CommonComponent {
|
interface PageProps extends CommonComponent {
|
||||||
expenseRecordId?: string;
|
expenseRecordId?: string;
|
||||||
@ -8,6 +15,7 @@ interface PageProps extends CommonComponent {
|
|||||||
|
|
||||||
export default hocAuth(function Page(props: PageProps) {
|
export default hocAuth(function Page(props: PageProps) {
|
||||||
const { shareOptions } = props;
|
const { shareOptions } = props;
|
||||||
|
const { setLoading } = globalStore((state: any) => state);
|
||||||
|
|
||||||
useShareAppMessage((res) => {
|
useShareAppMessage((res) => {
|
||||||
console.log("useShareAppMessage1", res, shareOptions);
|
console.log("useShareAppMessage1", res, shareOptions);
|
||||||
@ -19,5 +27,590 @@ export default hocAuth(function Page(props: PageProps) {
|
|||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
|
|
||||||
return <></>;
|
const [show, setShow] = useState(false);
|
||||||
|
const [currentDate, setCurrentDate] = useState<string[]>([
|
||||||
|
//这个月的开始时间
|
||||||
|
dayjs().startOf("month").format("YYYY-MM-DD"),
|
||||||
|
//这个月的结束时间
|
||||||
|
dayjs().endOf("month").format("YYYY-MM-DD"),
|
||||||
|
]);
|
||||||
|
const [expenseRecordList, setExpenseRecordList] =
|
||||||
|
useState<BusinessAPI.ExpenseRecordVO[]>();
|
||||||
|
const [expandedDays, setExpandedDays] = useState<Set<string>>(new Set()); // 展开的日期
|
||||||
|
const [summaryExpanded, setSummaryExpanded] = useState(false); // 汇总概览展开状态
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentDate) {
|
||||||
|
loadExpenseData(currentDate).then();
|
||||||
|
}
|
||||||
|
}, [currentDate]);
|
||||||
|
|
||||||
|
// 数据加载完成后默认展开所有日期
|
||||||
|
// useEffect(() => {
|
||||||
|
// if (expenseRecordList && expenseRecordList.length > 0) {
|
||||||
|
// const allDates = new Set(
|
||||||
|
// expenseRecordList.map((record) => record.recordDate).filter(Boolean),
|
||||||
|
// );
|
||||||
|
// setExpandedDays(allDates as any);
|
||||||
|
// }
|
||||||
|
// }, [expenseRecordList]);
|
||||||
|
|
||||||
|
const loadExpenseData = async (currentDate: string[]) => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const {
|
||||||
|
data: { data: expenseRecordList, success },
|
||||||
|
} = await business.expenseRecord.listExpenseRecord({
|
||||||
|
expenseRecordListQry: {
|
||||||
|
startDate: currentDate[0], // 使用今天的日期
|
||||||
|
endDate: currentDate[1],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
setExpenseRecordList(expenseRecordList || []);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("加载费用数据失败:", error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 计算统计数据
|
||||||
|
const calculateStatistics = () => {
|
||||||
|
if (!expenseRecordList || expenseRecordList.length === 0) {
|
||||||
|
return {
|
||||||
|
totalVehicles: 0,
|
||||||
|
totalProvision: 0,
|
||||||
|
totalExpense: 0,
|
||||||
|
dailyProfit: 0,
|
||||||
|
dealerStatistics: new Map<
|
||||||
|
string,
|
||||||
|
{ vehicleCount: number; totalAmount: number }
|
||||||
|
>(),
|
||||||
|
costCategoryStatistics: new Map<string, number>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalVehicles = expenseRecordList.reduce((sum, record) => {
|
||||||
|
return sum + (record.expenseProvisionList?.length || 0);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
const totalProvision = expenseRecordList.reduce((sum, record) => {
|
||||||
|
return sum + (record.totalProvision || 0);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
const totalExpense = expenseRecordList.reduce((sum, record) => {
|
||||||
|
return sum + (record.totalExpense || 0);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
const dailyProfit = totalProvision - totalExpense;
|
||||||
|
|
||||||
|
// 计提方统计(按客户/计提方分组)
|
||||||
|
const dealerStatistics = new Map<
|
||||||
|
string,
|
||||||
|
{ vehicleCount: number; totalAmount: number }
|
||||||
|
>();
|
||||||
|
expenseRecordList.forEach((record) => {
|
||||||
|
record.expenseProvisionList?.forEach((provision) => {
|
||||||
|
const dealerName = provision.dealerName || "未分组客户";
|
||||||
|
const current = dealerStatistics.get(dealerName) || {
|
||||||
|
vehicleCount: 0,
|
||||||
|
totalAmount: 0,
|
||||||
|
};
|
||||||
|
dealerStatistics.set(dealerName, {
|
||||||
|
vehicleCount: current.vehicleCount + 1,
|
||||||
|
totalAmount: current.totalAmount + (provision.provisionAmount || 0),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 费用分类汇总(按费用类型分组)
|
||||||
|
const costCategoryStatistics = new Map<string, number>();
|
||||||
|
expenseRecordList.forEach((record) => {
|
||||||
|
record.expenseCostList?.forEach((cost) => {
|
||||||
|
const costName = cost.costName || "未知费用";
|
||||||
|
const currentAmount = costCategoryStatistics.get(costName) || 0;
|
||||||
|
costCategoryStatistics.set(
|
||||||
|
costName,
|
||||||
|
currentAmount + (cost.expenseAmount || 0),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalVehicles,
|
||||||
|
totalProvision,
|
||||||
|
totalExpense,
|
||||||
|
dailyProfit,
|
||||||
|
dealerStatistics,
|
||||||
|
costCategoryStatistics,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 切换日期展开状态
|
||||||
|
const toggleDayExpansion = (recordDate: string) => {
|
||||||
|
setExpandedDays((prev) => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
if (newSet.has(recordDate)) {
|
||||||
|
newSet.delete(recordDate);
|
||||||
|
} else {
|
||||||
|
newSet.add(recordDate);
|
||||||
|
}
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取某天的费用统计
|
||||||
|
const getDayCostStatistics = (record: BusinessAPI.ExpenseRecordVO) => {
|
||||||
|
const costMap = new Map<string, number>();
|
||||||
|
|
||||||
|
// 统计每种费用类型的金额
|
||||||
|
record.expenseCostList?.forEach((cost) => {
|
||||||
|
const currentAmount = costMap.get(cost.costName || "") || 0;
|
||||||
|
costMap.set(
|
||||||
|
cost.costName || "",
|
||||||
|
currentAmount + (cost.expenseAmount || 0),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return costMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染计提明细
|
||||||
|
const renderProvisionDetails = (record: BusinessAPI.ExpenseRecordVO) => {
|
||||||
|
const provisionList = record.expenseProvisionList || [];
|
||||||
|
|
||||||
|
if (provisionList.length === 0) {
|
||||||
|
return (
|
||||||
|
<View className="p-2.5 text-center text-sm text-gray-500">
|
||||||
|
当日无计提记录
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按客户分组统计
|
||||||
|
const dealerGroups = provisionList.reduce(
|
||||||
|
(groups, provision) => {
|
||||||
|
const dealerName = provision.dealerName || "未分组客户";
|
||||||
|
if (!groups[dealerName]) {
|
||||||
|
groups[dealerName] = [];
|
||||||
|
}
|
||||||
|
groups[dealerName].push(provision);
|
||||||
|
return groups;
|
||||||
|
},
|
||||||
|
{} as Record<string, BusinessAPI.ExpenseProvision[]>,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View className="border-b border-gray-100 bg-white p-2.5">
|
||||||
|
<View className="mb-3 text-xs font-medium tracking-wider text-blue-600 uppercase">
|
||||||
|
计提明细 ({provisionList.length}车次)
|
||||||
|
</View>
|
||||||
|
<View className="space-y-3">
|
||||||
|
{Object.entries(dealerGroups).map(([dealerName, provisions]) => {
|
||||||
|
const totalAmount = provisions.reduce(
|
||||||
|
(sum, p) => sum + (p.provisionAmount || 0),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
key={dealerName}
|
||||||
|
className="rounded-lg border border-blue-100 bg-blue-50 p-3"
|
||||||
|
>
|
||||||
|
<View className="mb-2 flex items-center justify-between">
|
||||||
|
<View className="flex items-center">
|
||||||
|
<View className="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-blue-100 text-xs font-medium text-blue-600">
|
||||||
|
{provisions.length}
|
||||||
|
</View>
|
||||||
|
<View className="text-sm font-medium text-blue-900">
|
||||||
|
{dealerName}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className="text-sm font-medium text-blue-700">
|
||||||
|
¥{totalAmount.toLocaleString()}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className="flex flex-wrap gap-2">
|
||||||
|
{provisions.map((provision) => (
|
||||||
|
<View
|
||||||
|
key={provision.expenseProvisionId}
|
||||||
|
className="rounded border border-gray-200 bg-white px-2 py-1 text-xs text-gray-600"
|
||||||
|
>
|
||||||
|
{provision.vehicleNo || "未分配"}: ¥
|
||||||
|
{provision.provisionAmount?.toLocaleString()}
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染费用明细
|
||||||
|
const renderCostDetails = (record: BusinessAPI.ExpenseRecordVO) => {
|
||||||
|
const costStatistics = getDayCostStatistics(record);
|
||||||
|
|
||||||
|
if (costStatistics.size === 0) {
|
||||||
|
return (
|
||||||
|
<View className="bg-gray-50 p-2.5 text-center text-sm text-gray-500">
|
||||||
|
当日无费用记录
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View className="bg-white p-2.5">
|
||||||
|
<View className="mb-3 text-xs font-medium tracking-wider text-orange-600 uppercase">
|
||||||
|
费用明细
|
||||||
|
</View>
|
||||||
|
<View className="flex flex-wrap gap-3">
|
||||||
|
{Array.from(costStatistics.entries()).map(([costName, amount]) => (
|
||||||
|
<View
|
||||||
|
key={costName}
|
||||||
|
className="min-w-[45%] flex-1 items-center justify-between rounded-lg border border-orange-200 bg-orange-50 p-3"
|
||||||
|
>
|
||||||
|
<View className="min-w-0 flex-1">
|
||||||
|
<View className="truncate text-sm font-medium text-gray-900">
|
||||||
|
{costName}
|
||||||
|
</View>
|
||||||
|
<View className="mt-1 text-xs text-gray-500">
|
||||||
|
¥{amount.toFixed(2)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<View className={"flex flex-1 flex-col gap-2.5 p-2.5"}>
|
||||||
|
<View className="overflow-hidden rounded-md bg-white">
|
||||||
|
<View className="bg-gray-50">
|
||||||
|
<View
|
||||||
|
className={`flex h-10 w-full items-center rounded-md border-4 border-gray-300`}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
className={
|
||||||
|
"flex flex-1 flex-row items-center justify-between px-5"
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
color: "var(--nutui-color-title, #1a1a1a)",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
setShow(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View className={"text-sm"}>
|
||||||
|
{currentDate
|
||||||
|
? dayjs(currentDate[0]).format("YYYY年MM月DD日") +
|
||||||
|
" ~ " +
|
||||||
|
dayjs(currentDate[1]).format("YYYY年MM月DD日")
|
||||||
|
: "请选择录入花销时间"}
|
||||||
|
</View>
|
||||||
|
<Icon name={"chevron-down"} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className="overflow-hidden rounded-md bg-white shadow-md">
|
||||||
|
<View className={"flex flex-col gap-2.5 p-2.5"}>
|
||||||
|
{/* 头部 - 可点击展开/收起 */}
|
||||||
|
<View
|
||||||
|
className="flex cursor-pointer items-center justify-between"
|
||||||
|
onClick={() => setSummaryExpanded(!summaryExpanded)}
|
||||||
|
>
|
||||||
|
<View className="font-medium text-gray-900">时间段汇总概览</View>
|
||||||
|
<View className="flex items-center space-x-2">
|
||||||
|
<View className="text-xs text-gray-500">
|
||||||
|
{currentDate
|
||||||
|
? dayjs(currentDate[0]).format("YYYY年MM月DD日") +
|
||||||
|
" ~ " +
|
||||||
|
dayjs(currentDate[1]).format("YYYY年MM月DD日")
|
||||||
|
: ""}
|
||||||
|
</View>
|
||||||
|
<Icon
|
||||||
|
name={summaryExpanded ? "chevron-up" : "chevron-down"}
|
||||||
|
size={16}
|
||||||
|
className="text-gray-500"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 基础统计 - 始终显示 */}
|
||||||
|
<View className="space-y-2">
|
||||||
|
<View className="flex justify-between">
|
||||||
|
<View className="text-sm text-gray-600">总车次</View>
|
||||||
|
<View className="text-sm font-medium">
|
||||||
|
{calculateStatistics().totalVehicles}车
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className="flex justify-between">
|
||||||
|
<View className="text-sm text-gray-600">计提总额</View>
|
||||||
|
<View className="text-sm font-medium">
|
||||||
|
¥{calculateStatistics().totalProvision.toLocaleString()}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className="flex justify-between">
|
||||||
|
<View className="text-sm text-gray-600">费用总额</View>
|
||||||
|
<View className="text-sm font-medium">
|
||||||
|
¥{calculateStatistics().totalExpense.toLocaleString()}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className="flex justify-between">
|
||||||
|
<View className="text-sm text-gray-600">日常利润</View>
|
||||||
|
<View className={"flex flex-row items-center"}>
|
||||||
|
<View
|
||||||
|
className={`text-sm font-medium ${calculateStatistics().dailyProfit >= 0 ? "text-green-600" : "text-red-600"}`}
|
||||||
|
>
|
||||||
|
¥{calculateStatistics().dailyProfit.toLocaleString()}
|
||||||
|
</View>
|
||||||
|
<Icon
|
||||||
|
name={
|
||||||
|
calculateStatistics().dailyProfit >= 0
|
||||||
|
? "arrow-up"
|
||||||
|
: "arrow-down"
|
||||||
|
}
|
||||||
|
color={
|
||||||
|
calculateStatistics().dailyProfit >= 0 ? "green" : "red"
|
||||||
|
}
|
||||||
|
className="ml-1"
|
||||||
|
size={16}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 展开的详细统计 */}
|
||||||
|
{summaryExpanded && (
|
||||||
|
<View className="space-y-4 border-t border-gray-200 pt-4">
|
||||||
|
{/* 计提方统计 */}
|
||||||
|
<View>
|
||||||
|
<View className="mb-3 text-sm font-medium text-blue-600">
|
||||||
|
计提方统计
|
||||||
|
</View>
|
||||||
|
<View className="space-y-2">
|
||||||
|
{Array.from(
|
||||||
|
calculateStatistics().dealerStatistics.entries(),
|
||||||
|
).map(([dealerName, stats]) => (
|
||||||
|
<View
|
||||||
|
key={dealerName}
|
||||||
|
className="flex items-center justify-between rounded-lg border border-blue-100 bg-blue-50 p-3"
|
||||||
|
>
|
||||||
|
<View className="flex items-center">
|
||||||
|
<View className="mr-2 flex h-6 w-6 items-center justify-center rounded-full bg-blue-100 text-xs font-medium text-blue-600">
|
||||||
|
{stats.vehicleCount}
|
||||||
|
</View>
|
||||||
|
<View className="text-sm font-medium text-blue-900">
|
||||||
|
{dealerName}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className="text-sm font-medium text-blue-700">
|
||||||
|
¥{stats.totalAmount.toLocaleString()}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
{calculateStatistics().dealerStatistics.size === 0 && (
|
||||||
|
<View className="py-2 text-center text-sm text-gray-500">
|
||||||
|
暂无计提数据
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 费用分类汇总 */}
|
||||||
|
<View>
|
||||||
|
<View className="mb-3 text-sm font-medium text-orange-600">
|
||||||
|
费用分类汇总
|
||||||
|
</View>
|
||||||
|
<View className="flex flex-wrap gap-3">
|
||||||
|
{Array.from(
|
||||||
|
calculateStatistics().costCategoryStatistics.entries(),
|
||||||
|
).map(([costName, amount]) => (
|
||||||
|
<View
|
||||||
|
key={costName}
|
||||||
|
className="min-w-[45%] flex-1 items-center justify-between rounded-lg border border-orange-200 bg-orange-50 p-3"
|
||||||
|
>
|
||||||
|
<View className="min-w-0 flex-1">
|
||||||
|
<View className="truncate text-sm font-medium text-gray-900">
|
||||||
|
{costName}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className="ml-2 text-sm font-medium text-orange-700">
|
||||||
|
¥{amount.toFixed(0)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
{calculateStatistics().costCategoryStatistics.size ===
|
||||||
|
0 && (
|
||||||
|
<View className="w-full py-2 text-center text-sm text-gray-500">
|
||||||
|
暂无费用数据
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className="overflow-hidden rounded-md bg-white shadow-md">
|
||||||
|
<View className="border-b border-gray-100 p-2.5">
|
||||||
|
<View className="text-neutral-darkest text-base font-medium">
|
||||||
|
每日花销明细
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{expenseRecordList && expenseRecordList.length > 0 ? (
|
||||||
|
expenseRecordList.map((record) => {
|
||||||
|
const isExpanded = expandedDays.has(record.recordDate || "");
|
||||||
|
const vehicleCount = record.expenseProvisionList?.length || 0;
|
||||||
|
const dayProfit =
|
||||||
|
(record.totalProvision || 0) - (record.totalExpense || 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
key={record.recordDate}
|
||||||
|
className="border-b border-gray-100 last:border-b-0"
|
||||||
|
>
|
||||||
|
{/* 日期头部 - 可点击展开 */}
|
||||||
|
<View
|
||||||
|
className="cursor-pointer bg-gray-50 p-2.5 hover:bg-gray-100"
|
||||||
|
onClick={() => toggleDayExpansion(record.recordDate || "")}
|
||||||
|
>
|
||||||
|
{/* 第一行:日期 */}
|
||||||
|
<View className="mb-2 flex items-center justify-between">
|
||||||
|
<View className="flex items-center space-x-2">
|
||||||
|
<View className="text-sm font-medium text-gray-900">
|
||||||
|
{dayjs(record.recordDate).format("YYYY年MM月DD日")}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className="flex items-center space-x-2">
|
||||||
|
<View
|
||||||
|
className={`text-sm font-medium ${dayProfit >= 0 ? "text-green-600" : "text-red-600"}`}
|
||||||
|
>
|
||||||
|
¥{dayProfit.toLocaleString()}
|
||||||
|
</View>
|
||||||
|
<Icon
|
||||||
|
name={isExpanded ? "chevron-up" : "chevron-down"}
|
||||||
|
size={16}
|
||||||
|
className="text-gray-500"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 第二行:统计数据 */}
|
||||||
|
<View className="flex items-center justify-between text-xs">
|
||||||
|
<View className="flex items-center space-x-6">
|
||||||
|
<View className="text-gray-600">
|
||||||
|
<View className="font-medium">车次</View>
|
||||||
|
<View>{vehicleCount}车</View>
|
||||||
|
</View>
|
||||||
|
<View className="text-blue-600">
|
||||||
|
<View className="font-medium">计提</View>
|
||||||
|
<View>
|
||||||
|
¥{(record.totalProvision || 0).toLocaleString()}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className="text-orange-600">
|
||||||
|
<View className="font-medium">费用</View>
|
||||||
|
<View>
|
||||||
|
¥{(record.totalExpense || 0).toLocaleString()}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
icon={<Icon name="plus" size={12} color={"white"} />}
|
||||||
|
size={"mini"}
|
||||||
|
type={"primary"}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
Taro.navigateTo({
|
||||||
|
url: `/pages/expenses/create?date=${record.recordDate}`,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
录入
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 展开的明细内容 */}
|
||||||
|
{isExpanded && (
|
||||||
|
<View className="max-h-96 overflow-y-auto">
|
||||||
|
{renderProvisionDetails(record)}
|
||||||
|
{renderCostDetails(record)}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
) : (
|
||||||
|
<View className="p-8 text-center">
|
||||||
|
<View className="text-sm text-gray-500">暂无数据</View>
|
||||||
|
<View className="mt-2 text-xs text-gray-400">
|
||||||
|
请选择其他时间范围
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className="sticky bottom-0 z-10 bg-white">
|
||||||
|
<View className="flex justify-between gap-2 border-t border-gray-200 p-2.5">
|
||||||
|
{/* 返回 */}
|
||||||
|
<View className="flex-1">
|
||||||
|
<Button
|
||||||
|
size={"large"}
|
||||||
|
block
|
||||||
|
type={"default"}
|
||||||
|
onClick={() => {
|
||||||
|
Taro.navigateBack();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
返回
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
<View className="flex-1">
|
||||||
|
<Button
|
||||||
|
icon={<Icon name="plus" size={12} color={"white"} />}
|
||||||
|
size={"large"}
|
||||||
|
block
|
||||||
|
type={"primary"}
|
||||||
|
onClick={() => {
|
||||||
|
Taro.navigateTo({
|
||||||
|
url: "/pages/expenses/create",
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
花销录入
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<SafeArea position="bottom" />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Calendar
|
||||||
|
visible={show}
|
||||||
|
defaultValue={currentDate}
|
||||||
|
type="range"
|
||||||
|
startDate={"2025-01-01"}
|
||||||
|
onClose={() => setShow(false)}
|
||||||
|
onConfirm={(data) => {
|
||||||
|
setCurrentDate([
|
||||||
|
dayjs(data[0][3]).format("YYYY-MM-DD"),
|
||||||
|
dayjs(data[1][3]).format("YYYY-MM-DD"),
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -898,7 +898,8 @@ declare namespace BusinessAPI {
|
|||||||
| "ARTIFICIAL_TYPE"
|
| "ARTIFICIAL_TYPE"
|
||||||
| "PRODUCTION_TYPE"
|
| "PRODUCTION_TYPE"
|
||||||
| "OTHER_TYPE"
|
| "OTHER_TYPE"
|
||||||
| "LOGISTICS_TYPE";
|
| "LOGISTICS_TYPE"
|
||||||
|
| "EXPENSE_TYPE";
|
||||||
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
||||||
belong: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
belong: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
||||||
/** 费用名称 */
|
/** 费用名称 */
|
||||||
@ -1061,7 +1062,8 @@ declare namespace BusinessAPI {
|
|||||||
| "ARTIFICIAL_TYPE"
|
| "ARTIFICIAL_TYPE"
|
||||||
| "PRODUCTION_TYPE"
|
| "PRODUCTION_TYPE"
|
||||||
| "OTHER_TYPE"
|
| "OTHER_TYPE"
|
||||||
| "LOGISTICS_TYPE";
|
| "LOGISTICS_TYPE"
|
||||||
|
| "EXPENSE_TYPE";
|
||||||
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
||||||
belong?: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
belong?: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
||||||
/** 费用名称 */
|
/** 费用名称 */
|
||||||
@ -1091,7 +1093,8 @@ declare namespace BusinessAPI {
|
|||||||
| "ARTIFICIAL_TYPE"
|
| "ARTIFICIAL_TYPE"
|
||||||
| "PRODUCTION_TYPE"
|
| "PRODUCTION_TYPE"
|
||||||
| "OTHER_TYPE"
|
| "OTHER_TYPE"
|
||||||
| "LOGISTICS_TYPE";
|
| "LOGISTICS_TYPE"
|
||||||
|
| "EXPENSE_TYPE";
|
||||||
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
||||||
belong?: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
belong?: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
||||||
offset?: number;
|
offset?: number;
|
||||||
@ -1113,7 +1116,8 @@ declare namespace BusinessAPI {
|
|||||||
| "ARTIFICIAL_TYPE"
|
| "ARTIFICIAL_TYPE"
|
||||||
| "PRODUCTION_TYPE"
|
| "PRODUCTION_TYPE"
|
||||||
| "OTHER_TYPE"
|
| "OTHER_TYPE"
|
||||||
| "LOGISTICS_TYPE";
|
| "LOGISTICS_TYPE"
|
||||||
|
| "EXPENSE_TYPE";
|
||||||
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
||||||
belong: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
belong: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
||||||
/** 费用名称 */
|
/** 费用名称 */
|
||||||
@ -1141,7 +1145,8 @@ declare namespace BusinessAPI {
|
|||||||
| "ARTIFICIAL_TYPE"
|
| "ARTIFICIAL_TYPE"
|
||||||
| "PRODUCTION_TYPE"
|
| "PRODUCTION_TYPE"
|
||||||
| "OTHER_TYPE"
|
| "OTHER_TYPE"
|
||||||
| "LOGISTICS_TYPE";
|
| "LOGISTICS_TYPE"
|
||||||
|
| "EXPENSE_TYPE";
|
||||||
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
/** 费用归属:0_无归属;1_工头;2_产地;3_司机; */
|
||||||
belong: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
belong: "NONE_TYPE" | "WORKER_TYPE" | "PRODUCTION_TYPE" | "DRIVER_TYPE";
|
||||||
/** 费用名称 */
|
/** 费用名称 */
|
||||||
@ -1979,8 +1984,10 @@ declare namespace BusinessAPI {
|
|||||||
type ExpenseRecordListQry = {
|
type ExpenseRecordListQry = {
|
||||||
/** 状态:1_启用;0_禁用; */
|
/** 状态:1_启用;0_禁用; */
|
||||||
status?: boolean;
|
status?: boolean;
|
||||||
/** 花销统计记录ID */
|
/** 开始日期 */
|
||||||
expenseRecordId?: string;
|
startDate?: string;
|
||||||
|
/** 结束日期 */
|
||||||
|
endDate?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ExpenseRecordShowQry = {
|
type ExpenseRecordShowQry = {
|
||||||
@ -2008,18 +2015,20 @@ declare namespace BusinessAPI {
|
|||||||
expenseRecordId: string;
|
expenseRecordId: string;
|
||||||
/** 记录日期(YYYY-MM-DD) */
|
/** 记录日期(YYYY-MM-DD) */
|
||||||
recordDate?: string;
|
recordDate?: string;
|
||||||
|
/** 计提车次数量 */
|
||||||
|
totalVehicleCount?: number;
|
||||||
/** 计提总金额 */
|
/** 计提总金额 */
|
||||||
totalProvision?: number;
|
totalProvision?: number;
|
||||||
/** 花销总额 */
|
/** 花销总额 */
|
||||||
totalExpense?: number;
|
totalExpense?: number;
|
||||||
/** 日常利润 */
|
/** 日常利润 */
|
||||||
dailyProfit?: number;
|
dailyProfit?: number;
|
||||||
/** 创建时间 */
|
|
||||||
createdAt?: string;
|
|
||||||
/** 花销费用明细 */
|
|
||||||
expenseCostList?: ExpenseCost[];
|
|
||||||
/** 花销计提明细 */
|
/** 花销计提明细 */
|
||||||
expenseProvisionList?: ExpenseProvision[];
|
expenseProvisionList?: ExpenseProvision[];
|
||||||
|
/** 花销费用明细 */
|
||||||
|
expenseCostList?: ExpenseCost[];
|
||||||
|
/** 创建时间 */
|
||||||
|
createdAt?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type getLastVehicleNoParams = {
|
type getLastVehicleNoParams = {
|
||||||
@ -2767,7 +2776,8 @@ declare namespace BusinessAPI {
|
|||||||
| "ARTIFICIAL_TYPE"
|
| "ARTIFICIAL_TYPE"
|
||||||
| "PRODUCTION_TYPE"
|
| "PRODUCTION_TYPE"
|
||||||
| "OTHER_TYPE"
|
| "OTHER_TYPE"
|
||||||
| "LOGISTICS_TYPE";
|
| "LOGISTICS_TYPE"
|
||||||
|
| "EXPENSE_TYPE";
|
||||||
/** 关联项目id */
|
/** 关联项目id */
|
||||||
costItemIds?: string[];
|
costItemIds?: string[];
|
||||||
/** 是否选中 */
|
/** 是否选中 */
|
||||||
@ -2799,7 +2809,8 @@ declare namespace BusinessAPI {
|
|||||||
| "ARTIFICIAL_TYPE"
|
| "ARTIFICIAL_TYPE"
|
||||||
| "PRODUCTION_TYPE"
|
| "PRODUCTION_TYPE"
|
||||||
| "OTHER_TYPE"
|
| "OTHER_TYPE"
|
||||||
| "LOGISTICS_TYPE";
|
| "LOGISTICS_TYPE"
|
||||||
|
| "EXPENSE_TYPE";
|
||||||
/** 关联项目id */
|
/** 关联项目id */
|
||||||
costItemIds?: string[];
|
costItemIds?: string[];
|
||||||
/** 是否付款 */
|
/** 是否付款 */
|
||||||
@ -2897,7 +2908,8 @@ declare namespace BusinessAPI {
|
|||||||
| "ARTIFICIAL_TYPE"
|
| "ARTIFICIAL_TYPE"
|
||||||
| "PRODUCTION_TYPE"
|
| "PRODUCTION_TYPE"
|
||||||
| "OTHER_TYPE"
|
| "OTHER_TYPE"
|
||||||
| "LOGISTICS_TYPE";
|
| "LOGISTICS_TYPE"
|
||||||
|
| "EXPENSE_TYPE";
|
||||||
/** 关联项目id */
|
/** 关联项目id */
|
||||||
costItemIds?: string[];
|
costItemIds?: string[];
|
||||||
/** 创建时间 */
|
/** 创建时间 */
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user