地区
This commit is contained in:
parent
f6822d2411
commit
ea78619f5f
@ -20,7 +20,7 @@ import {
|
|||||||
listFinanceWithdrawalApplications,
|
listFinanceWithdrawalApplications,
|
||||||
refreshFinanceGoogleRechargePaid,
|
refreshFinanceGoogleRechargePaid,
|
||||||
rejectFinanceApplication,
|
rejectFinanceApplication,
|
||||||
rejectFinanceWithdrawalApplication
|
rejectFinanceWithdrawalApplication,
|
||||||
} from "./api.js";
|
} from "./api.js";
|
||||||
import { FinanceApplicationForm } from "./components/FinanceApplicationForm.jsx";
|
import { FinanceApplicationForm } from "./components/FinanceApplicationForm.jsx";
|
||||||
import { FinanceApplicationList } from "./components/FinanceApplicationList.jsx";
|
import { FinanceApplicationList } from "./components/FinanceApplicationList.jsx";
|
||||||
@ -36,7 +36,7 @@ import {
|
|||||||
EMPTY_RECHARGE_OVERVIEW,
|
EMPTY_RECHARGE_OVERVIEW,
|
||||||
EMPTY_RECHARGE_SUMMARY,
|
EMPTY_RECHARGE_SUMMARY,
|
||||||
buildApplicationPayload,
|
buildApplicationPayload,
|
||||||
validateApplicationPayload
|
validateApplicationPayload,
|
||||||
} from "./format.js";
|
} from "./format.js";
|
||||||
import { downloadCsv } from "@/shared/api/download";
|
import { downloadCsv } from "@/shared/api/download";
|
||||||
import { TimeRangeFilter } from "@/shared/ui/TimeRangeFilter.jsx";
|
import { TimeRangeFilter } from "@/shared/ui/TimeRangeFilter.jsx";
|
||||||
@ -62,7 +62,7 @@ function timePresets() {
|
|||||||
{ key: "7d", label: "近7天", range: { endMs: todayStart + DAY_MS, startMs: todayStart - 6 * DAY_MS } },
|
{ key: "7d", label: "近7天", range: { endMs: todayStart + DAY_MS, startMs: todayStart - 6 * DAY_MS } },
|
||||||
{ key: "30d", label: "近30天", range: { endMs: todayStart + DAY_MS, startMs: todayStart - 29 * DAY_MS } },
|
{ key: "30d", label: "近30天", range: { endMs: todayStart + DAY_MS, startMs: todayStart - 29 * DAY_MS } },
|
||||||
{ key: "month", label: "本月", range: { endMs: todayStart + DAY_MS, startMs: monthStart } },
|
{ key: "month", label: "本月", range: { endMs: todayStart + DAY_MS, startMs: monthStart } },
|
||||||
{ key: "all", label: "不限", range: { endMs: "", startMs: "" } }
|
{ key: "all", label: "不限", range: { endMs: "", startMs: "" } },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ function reconMonthMeta(offset) {
|
|||||||
endMs,
|
endMs,
|
||||||
isCurrent: offset === 0,
|
isCurrent: offset === 0,
|
||||||
label: `${startDate.getUTCFullYear()}年${startDate.getUTCMonth() + 1}月`,
|
label: `${startDate.getUTCFullYear()}年${startDate.getUTCMonth() + 1}月`,
|
||||||
startMs
|
startMs,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,17 +85,45 @@ export function FinanceApp() {
|
|||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
const [sessionState, setSessionState] = useState({ error: "", loading: true, session: null });
|
const [sessionState, setSessionState] = useState({ error: "", loading: true, session: null });
|
||||||
const [optionsState, setOptionsState] = useState({ data: emptyOptions, error: "", loading: false });
|
const [optionsState, setOptionsState] = useState({ data: emptyOptions, error: "", loading: false });
|
||||||
const [rechargeDetailsState, setRechargeDetailsState] = useState({ data: { items: [], page: 1, pageSize, total: 0 }, error: "", loading: false });
|
const [rechargeDetailsState, setRechargeDetailsState] = useState({
|
||||||
const [rechargeSummaryState, setRechargeSummaryState] = useState({ merged: EMPTY_RECHARGE_SUMMARY, loading: false, perApp: [], prev: null });
|
data: { items: [], page: 1, pageSize, total: 0 },
|
||||||
const [rechargeOverviewState, setRechargeOverviewState] = useState({ data: EMPTY_RECHARGE_OVERVIEW, loading: false });
|
error: "",
|
||||||
const [rechargeRegionsState, setRechargeRegionsState] = useState({ appCode: "", items: [], loading: false });
|
loading: false,
|
||||||
|
});
|
||||||
|
const [rechargeSummaryState, setRechargeSummaryState] = useState({
|
||||||
|
merged: EMPTY_RECHARGE_SUMMARY,
|
||||||
|
loading: false,
|
||||||
|
perApp: [],
|
||||||
|
prev: null,
|
||||||
|
});
|
||||||
|
const [rechargeOverviewState, setRechargeOverviewState] = useState({
|
||||||
|
data: EMPTY_RECHARGE_OVERVIEW,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
const [rechargeRegionsState, setRechargeRegionsState] = useState({ byApp: {}, loading: false });
|
||||||
const [rechargeAppsState, setRechargeAppsState] = useState({ items: [], loaded: false });
|
const [rechargeAppsState, setRechargeAppsState] = useState({ items: [], loaded: false });
|
||||||
const [googlePaidRefreshing, setGooglePaidRefreshing] = useState(false);
|
const [googlePaidRefreshing, setGooglePaidRefreshing] = useState(false);
|
||||||
const [reconMonthOffset, setReconMonthOffset] = useState(0);
|
const [reconMonthOffset, setReconMonthOffset] = useState(0);
|
||||||
const [reconState, setReconState] = useState({ loading: false, overview: EMPTY_RECHARGE_OVERVIEW, summary: EMPTY_RECHARGE_SUMMARY });
|
const [reconState, setReconState] = useState({
|
||||||
const [myApplicationsState, setMyApplicationsState] = useState({ data: { items: [], page: 1, pageSize, total: 0 }, error: "", loading: false });
|
loading: false,
|
||||||
const [applicationsState, setApplicationsState] = useState({ data: { items: [], page: 1, pageSize, total: 0 }, error: "", loading: false });
|
overview: EMPTY_RECHARGE_OVERVIEW,
|
||||||
const [withdrawalsState, setWithdrawalsState] = useState({ data: { items: [], page: 1, pageSize, total: 0 }, error: "", loading: false });
|
summary: EMPTY_RECHARGE_SUMMARY,
|
||||||
|
});
|
||||||
|
const [myApplicationsState, setMyApplicationsState] = useState({
|
||||||
|
data: { items: [], page: 1, pageSize, total: 0 },
|
||||||
|
error: "",
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
const [applicationsState, setApplicationsState] = useState({
|
||||||
|
data: { items: [], page: 1, pageSize, total: 0 },
|
||||||
|
error: "",
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
const [withdrawalsState, setWithdrawalsState] = useState({
|
||||||
|
data: { items: [], page: 1, pageSize, total: 0 },
|
||||||
|
error: "",
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
const [activeView, setActiveView] = useState("create");
|
const [activeView, setActiveView] = useState("create");
|
||||||
const [rechargeDetailFilters, setRechargeDetailFilters] = useState(() => ({
|
const [rechargeDetailFilters, setRechargeDetailFilters] = useState(() => ({
|
||||||
appCode: "",
|
appCode: "",
|
||||||
@ -105,7 +133,7 @@ export function FinanceApp() {
|
|||||||
paidState: "",
|
paidState: "",
|
||||||
rechargeType: "",
|
rechargeType: "",
|
||||||
regionId: "",
|
regionId: "",
|
||||||
timeRange: timePresets().find((preset) => preset.key === "30d").range
|
timeRange: timePresets().find((preset) => preset.key === "30d").range,
|
||||||
}));
|
}));
|
||||||
const [rechargeExporting, setRechargeExporting] = useState(false);
|
const [rechargeExporting, setRechargeExporting] = useState(false);
|
||||||
const [myFilters, setMyFilters] = useState({ appCode: "", keyword: "", operation: "", page: 1, status: "" });
|
const [myFilters, setMyFilters] = useState({ appCode: "", keyword: "", operation: "", page: 1, status: "" });
|
||||||
@ -134,7 +162,7 @@ export function FinanceApp() {
|
|||||||
? "applications"
|
? "applications"
|
||||||
: session.canCreateApplication
|
: session.canCreateApplication
|
||||||
? "create"
|
? "create"
|
||||||
: "withdrawals"
|
: "withdrawals",
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
@ -161,18 +189,18 @@ export function FinanceApp() {
|
|||||||
region_id: rechargeDetailFilters.appCode ? rechargeDetailFilters.regionId : "",
|
region_id: rechargeDetailFilters.appCode ? rechargeDetailFilters.regionId : "",
|
||||||
start_at_ms: rechargeDetailFilters.timeRange.startMs,
|
start_at_ms: rechargeDetailFilters.timeRange.startMs,
|
||||||
stat_tz: "Asia/Shanghai",
|
stat_tz: "Asia/Shanghai",
|
||||||
status: "succeeded"
|
status: "succeeded",
|
||||||
}),
|
}),
|
||||||
[rechargeDetailFilters]
|
[rechargeDetailFilters],
|
||||||
);
|
);
|
||||||
const rechargeDetailQuery = useMemo(
|
const rechargeDetailQuery = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
...rechargeBaseQuery,
|
...rechargeBaseQuery,
|
||||||
page: rechargeDetailFilters.page,
|
page: rechargeDetailFilters.page,
|
||||||
page_size: pageSize,
|
page_size: pageSize,
|
||||||
paid_state: rechargeDetailFilters.paidState
|
paid_state: rechargeDetailFilters.paidState,
|
||||||
}),
|
}),
|
||||||
[rechargeBaseQuery, rechargeDetailFilters.page, rechargeDetailFilters.paidState]
|
[rechargeBaseQuery, rechargeDetailFilters.page, rechargeDetailFilters.paidState],
|
||||||
);
|
);
|
||||||
const myApplicationQuery = useMemo(
|
const myApplicationQuery = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -181,9 +209,9 @@ export function FinanceApp() {
|
|||||||
operation: myFilters.operation,
|
operation: myFilters.operation,
|
||||||
page: myFilters.page,
|
page: myFilters.page,
|
||||||
page_size: pageSize,
|
page_size: pageSize,
|
||||||
status: myFilters.status
|
status: myFilters.status,
|
||||||
}),
|
}),
|
||||||
[myFilters]
|
[myFilters],
|
||||||
);
|
);
|
||||||
const applicationQuery = useMemo(
|
const applicationQuery = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -192,18 +220,18 @@ export function FinanceApp() {
|
|||||||
operation: filters.operation,
|
operation: filters.operation,
|
||||||
page: filters.page,
|
page: filters.page,
|
||||||
page_size: pageSize,
|
page_size: pageSize,
|
||||||
status: filters.status
|
status: filters.status,
|
||||||
}),
|
}),
|
||||||
[filters]
|
[filters],
|
||||||
);
|
);
|
||||||
const withdrawalQuery = useMemo(
|
const withdrawalQuery = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
app_code: withdrawalFilters.appCode,
|
app_code: withdrawalFilters.appCode,
|
||||||
keyword: withdrawalFilters.keyword,
|
keyword: withdrawalFilters.keyword,
|
||||||
page: withdrawalFilters.page,
|
page: withdrawalFilters.page,
|
||||||
page_size: pageSize
|
page_size: pageSize,
|
||||||
}),
|
}),
|
||||||
[withdrawalFilters]
|
[withdrawalFilters],
|
||||||
);
|
);
|
||||||
|
|
||||||
const loadOptions = useCallback(async () => {
|
const loadOptions = useCallback(async () => {
|
||||||
@ -228,14 +256,21 @@ export function FinanceApp() {
|
|||||||
const data = await listMyFinanceApplications(myApplicationQuery);
|
const data = await listMyFinanceApplications(myApplicationQuery);
|
||||||
setMyApplicationsState({ data, error: "", loading: false });
|
setMyApplicationsState({ data, error: "", loading: false });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setMyApplicationsState((current) => ({ ...current, error: err.message || "加载我的申请列表失败", loading: false }));
|
setMyApplicationsState((current) => ({
|
||||||
|
...current,
|
||||||
|
error: err.message || "加载我的申请列表失败",
|
||||||
|
loading: false,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}, [myApplicationQuery, session?.canCreateApplication]);
|
}, [myApplicationQuery, session?.canCreateApplication]);
|
||||||
|
|
||||||
// 充值详情的 App 目录来自 recharge-apps(含 Yumi/Aslan 等 legacy 外部账单源);接口未就绪时回退到财务通用 App 列表。
|
// 充值详情的 App 目录来自 recharge-apps(含 Yumi/Aslan 等 legacy 外部账单源);接口未就绪时回退到财务通用 App 列表。
|
||||||
const rechargeApps = useMemo(
|
const rechargeApps = useMemo(
|
||||||
() => (rechargeAppsState.loaded && rechargeAppsState.items.length ? rechargeAppsState.items : optionsState.data.apps),
|
() =>
|
||||||
[optionsState.data.apps, rechargeAppsState]
|
rechargeAppsState.loaded && rechargeAppsState.items.length
|
||||||
|
? rechargeAppsState.items
|
||||||
|
: optionsState.data.apps,
|
||||||
|
[optionsState.data.apps, rechargeAppsState],
|
||||||
);
|
);
|
||||||
|
|
||||||
const loadRechargeApps = useCallback(async () => {
|
const loadRechargeApps = useCallback(async () => {
|
||||||
@ -259,7 +294,11 @@ export function FinanceApp() {
|
|||||||
const data = await listFinanceRechargeDetails(rechargeDetailQuery, rechargeApps);
|
const data = await listFinanceRechargeDetails(rechargeDetailQuery, rechargeApps);
|
||||||
setRechargeDetailsState({ data, error: "", loading: false });
|
setRechargeDetailsState({ data, error: "", loading: false });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setRechargeDetailsState((current) => ({ ...current, error: err.message || "加载充值流水失败", loading: false }));
|
setRechargeDetailsState((current) => ({
|
||||||
|
...current,
|
||||||
|
error: err.message || "加载充值流水失败",
|
||||||
|
loading: false,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}, [canViewFinance, rechargeApps, rechargeDetailQuery]);
|
}, [canViewFinance, rechargeApps, rechargeDetailQuery]);
|
||||||
|
|
||||||
@ -307,13 +346,13 @@ export function FinanceApp() {
|
|||||||
end_at_ms: month.endMs,
|
end_at_ms: month.endMs,
|
||||||
keyword: "",
|
keyword: "",
|
||||||
recharge_type: "",
|
recharge_type: "",
|
||||||
start_at_ms: month.startMs
|
start_at_ms: month.startMs,
|
||||||
};
|
};
|
||||||
setReconState((current) => ({ ...current, loading: true }));
|
setReconState((current) => ({ ...current, loading: true }));
|
||||||
try {
|
try {
|
||||||
const [{ merged }, overview] = await Promise.all([
|
const [{ merged }, overview] = await Promise.all([
|
||||||
fetchFinanceRechargeSummaries(query, rechargeApps),
|
fetchFinanceRechargeSummaries(query, rechargeApps),
|
||||||
fetchFinanceRechargeOverview(query, rechargeApps)
|
fetchFinanceRechargeOverview(query, rechargeApps),
|
||||||
]);
|
]);
|
||||||
setReconState({ loading: false, overview, summary: merged });
|
setReconState({ loading: false, overview, summary: merged });
|
||||||
} catch {
|
} catch {
|
||||||
@ -322,19 +361,27 @@ export function FinanceApp() {
|
|||||||
}, [activeView, canViewFinance, rechargeApps, rechargeBaseQuery, reconMonthOffset]);
|
}, [activeView, canViewFinance, rechargeApps, rechargeBaseQuery, reconMonthOffset]);
|
||||||
|
|
||||||
const rechargeAppCode = rechargeDetailFilters.appCode;
|
const rechargeAppCode = rechargeDetailFilters.appCode;
|
||||||
|
// 一次拉齐所有 App 的区域目录:区域筛选下拉用当前 App 的,流水区域列在“全部 App”下要跨 App 显示名称。
|
||||||
const loadRechargeRegions = useCallback(async () => {
|
const loadRechargeRegions = useCallback(async () => {
|
||||||
if (!canViewFinance || !rechargeAppCode) {
|
if (!canViewFinance || !rechargeApps.length) {
|
||||||
setRechargeRegionsState({ appCode: "", items: [], loading: false });
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setRechargeRegionsState((current) => ({ ...current, appCode: rechargeAppCode, loading: true }));
|
setRechargeRegionsState((current) => ({ ...current, loading: true }));
|
||||||
try {
|
try {
|
||||||
const items = await listFinanceRechargeRegions(rechargeAppCode);
|
const entries = await Promise.all(
|
||||||
setRechargeRegionsState({ appCode: rechargeAppCode, items, loading: false });
|
rechargeApps.map(async (app) => {
|
||||||
|
try {
|
||||||
|
return [app.appCode, await listFinanceRechargeRegions(app.appCode)];
|
||||||
} catch {
|
} catch {
|
||||||
setRechargeRegionsState({ appCode: rechargeAppCode, items: [], loading: false });
|
return [app.appCode, []];
|
||||||
}
|
}
|
||||||
}, [canViewFinance, rechargeAppCode]);
|
}),
|
||||||
|
);
|
||||||
|
setRechargeRegionsState({ byApp: Object.fromEntries(entries), loading: false });
|
||||||
|
} catch {
|
||||||
|
setRechargeRegionsState((current) => ({ ...current, loading: false }));
|
||||||
|
}
|
||||||
|
}, [canViewFinance, rechargeApps]);
|
||||||
|
|
||||||
const refreshGooglePaid = useCallback(
|
const refreshGooglePaid = useCallback(
|
||||||
async (transactionIds) => {
|
async (transactionIds) => {
|
||||||
@ -347,8 +394,10 @@ export function FinanceApp() {
|
|||||||
const failed = results.filter((item) => item.error).length;
|
const failed = results.filter((item) => item.error).length;
|
||||||
const succeeded = results.length - failed;
|
const succeeded = results.length - failed;
|
||||||
showToast(
|
showToast(
|
||||||
failed ? `谷歌实付同步完成:成功 ${succeeded} 笔,失败 ${failed} 笔` : `谷歌实付同步完成:${succeeded} 笔`,
|
failed
|
||||||
failed ? "warning" : "success"
|
? `谷歌实付同步完成:成功 ${succeeded} 笔,失败 ${failed} 笔`
|
||||||
|
: `谷歌实付同步完成:${succeeded} 笔`,
|
||||||
|
failed ? "warning" : "success",
|
||||||
);
|
);
|
||||||
await Promise.all([loadRechargeDetails(), loadRechargeOverview()]);
|
await Promise.all([loadRechargeDetails(), loadRechargeOverview()]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -357,7 +406,7 @@ export function FinanceApp() {
|
|||||||
setGooglePaidRefreshing(false);
|
setGooglePaidRefreshing(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[googlePaidRefreshing, loadRechargeDetails, loadRechargeOverview, rechargeAppCode, showToast]
|
[googlePaidRefreshing, loadRechargeDetails, loadRechargeOverview, rechargeAppCode, showToast],
|
||||||
);
|
);
|
||||||
|
|
||||||
const exportRechargeBills = useCallback(async () => {
|
const exportRechargeBills = useCallback(async () => {
|
||||||
@ -371,7 +420,7 @@ export function FinanceApp() {
|
|||||||
.replaceAll(/[: ]/g, "-");
|
.replaceAll(/[: ]/g, "-");
|
||||||
await downloadCsv(
|
await downloadCsv(
|
||||||
() => exportFinanceRechargeBills(rechargeAppCode, rechargeDetailQuery),
|
() => exportFinanceRechargeBills(rechargeAppCode, rechargeDetailQuery),
|
||||||
`充值明细-${rechargeAppCode}-${timestamp}.csv`
|
`充值明细-${rechargeAppCode}-${timestamp}.csv`,
|
||||||
);
|
);
|
||||||
showToast("充值明细已导出", "success");
|
showToast("充值明细已导出", "success");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -390,7 +439,11 @@ export function FinanceApp() {
|
|||||||
const data = await listFinanceApplications(applicationQuery);
|
const data = await listFinanceApplications(applicationQuery);
|
||||||
setApplicationsState({ data, error: "", loading: false });
|
setApplicationsState({ data, error: "", loading: false });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setApplicationsState((current) => ({ ...current, error: err.message || "加载申请列表失败", loading: false }));
|
setApplicationsState((current) => ({
|
||||||
|
...current,
|
||||||
|
error: err.message || "加载申请列表失败",
|
||||||
|
loading: false,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}, [applicationQuery, session?.canAuditApplication]);
|
}, [applicationQuery, session?.canAuditApplication]);
|
||||||
|
|
||||||
@ -403,7 +456,11 @@ export function FinanceApp() {
|
|||||||
const data = await listFinanceWithdrawalApplications(withdrawalQuery);
|
const data = await listFinanceWithdrawalApplications(withdrawalQuery);
|
||||||
setWithdrawalsState({ data, error: "", loading: false });
|
setWithdrawalsState({ data, error: "", loading: false });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setWithdrawalsState((current) => ({ ...current, error: err.message || "加载提现申请列表失败", loading: false }));
|
setWithdrawalsState((current) => ({
|
||||||
|
...current,
|
||||||
|
error: err.message || "加载提现申请列表失败",
|
||||||
|
loading: false,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}, [session?.canViewWithdrawalApplications, withdrawalQuery]);
|
}, [session?.canViewWithdrawalApplications, withdrawalQuery]);
|
||||||
|
|
||||||
@ -449,7 +506,7 @@ export function FinanceApp() {
|
|||||||
|
|
||||||
const operationOptions = useMemo(
|
const operationOptions = useMemo(
|
||||||
() => filterOperationsByPermissions(optionsState.data.operations, session?.permissions || []),
|
() => filterOperationsByPermissions(optionsState.data.operations, session?.permissions || []),
|
||||||
[optionsState.data.operations, session?.permissions]
|
[optionsState.data.operations, session?.permissions],
|
||||||
);
|
);
|
||||||
|
|
||||||
const submitApplication = async (event) => {
|
const submitApplication = async (event) => {
|
||||||
@ -471,7 +528,10 @@ export function FinanceApp() {
|
|||||||
const result = await createFinanceApplication(cleanPayload(payload));
|
const result = await createFinanceApplication(cleanPayload(payload));
|
||||||
setForm({ ...DEFAULT_APPLICATION_FORM, appCode: payload.appCode });
|
setForm({ ...DEFAULT_APPLICATION_FORM, appCode: payload.appCode });
|
||||||
setCreateDialogOpen(false);
|
setCreateDialogOpen(false);
|
||||||
showToast(result?.dingTalkNotified === false ? "申请已提交,钉钉通知未确认" : "申请已提交并通知财务", "success");
|
showToast(
|
||||||
|
result?.dingTalkNotified === false ? "申请已提交,钉钉通知未确认" : "申请已提交并通知财务",
|
||||||
|
"success",
|
||||||
|
);
|
||||||
await loadMyApplications();
|
await loadMyApplications();
|
||||||
if (session.canAuditApplication) {
|
if (session.canAuditApplication) {
|
||||||
await loadApplications();
|
await loadApplications();
|
||||||
@ -507,7 +567,8 @@ export function FinanceApp() {
|
|||||||
}
|
}
|
||||||
setWithdrawalAuditLoading(true);
|
setWithdrawalAuditLoading(true);
|
||||||
try {
|
try {
|
||||||
const submitter = decision === "approved" ? approveFinanceWithdrawalApplication : rejectFinanceWithdrawalApplication;
|
const submitter =
|
||||||
|
decision === "approved" ? approveFinanceWithdrawalApplication : rejectFinanceWithdrawalApplication;
|
||||||
await submitter(withdrawalAuditTarget.id, cleanPayload({ auditImageUrl, auditRemark: remark }));
|
await submitter(withdrawalAuditTarget.id, cleanPayload({ auditImageUrl, auditRemark: remark }));
|
||||||
showToast(decision === "approved" ? "提现申请已通过" : "提现申请已拒绝", "success");
|
showToast(decision === "approved" ? "提现申请已通过" : "提现申请已拒绝", "success");
|
||||||
setWithdrawalAuditTarget(null);
|
setWithdrawalAuditTarget(null);
|
||||||
@ -558,7 +619,7 @@ export function FinanceApp() {
|
|||||||
const activePreset = presets.find(
|
const activePreset = presets.find(
|
||||||
(preset) =>
|
(preset) =>
|
||||||
String(preset.range.startMs || "") === String(rechargeDetailFilters.timeRange.startMs || "") &&
|
String(preset.range.startMs || "") === String(rechargeDetailFilters.timeRange.startMs || "") &&
|
||||||
String(preset.range.endMs || "") === String(rechargeDetailFilters.timeRange.endMs || "")
|
String(preset.range.endMs || "") === String(rechargeDetailFilters.timeRange.endMs || ""),
|
||||||
);
|
);
|
||||||
const isFinanceView = FINANCE_VIEWS.has(activeView);
|
const isFinanceView = FINANCE_VIEWS.has(activeView);
|
||||||
const financeToolbar =
|
const financeToolbar =
|
||||||
@ -584,13 +645,15 @@ export function FinanceApp() {
|
|||||||
<div className="finance-seg" role="group" aria-label="计价单位">
|
<div className="finance-seg" role="group" aria-label="计价单位">
|
||||||
{[
|
{[
|
||||||
["usd", "USD"],
|
["usd", "USD"],
|
||||||
["coin", "金币"]
|
["coin", "金币"],
|
||||||
].map(([value, label]) => (
|
].map(([value, label]) => (
|
||||||
<button
|
<button
|
||||||
className={rechargeDetailFilters.currency === value ? "is-on" : ""}
|
className={rechargeDetailFilters.currency === value ? "is-on" : ""}
|
||||||
key={value}
|
key={value}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => updateRechargeDetailFilters({ currency: value, page: rechargeDetailFilters.page })}
|
onClick={() =>
|
||||||
|
updateRechargeDetailFilters({ currency: value, page: rechargeDetailFilters.page })
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</button>
|
</button>
|
||||||
@ -603,7 +666,9 @@ export function FinanceApp() {
|
|||||||
isFinanceView && session.canViewAppRechargeDetails ? (
|
isFinanceView && session.canViewAppRechargeDetails ? (
|
||||||
<div className="finance-appbar">
|
<div className="finance-appbar">
|
||||||
<button
|
<button
|
||||||
className={["finance-appchip", rechargeDetailFilters.appCode === "" ? "is-on" : ""].filter(Boolean).join(" ")}
|
className={["finance-appchip", rechargeDetailFilters.appCode === "" ? "is-on" : ""]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" ")}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => updateRechargeDetailFilters({ appCode: "", regionId: "" })}
|
onClick={() => updateRechargeDetailFilters({ appCode: "", regionId: "" })}
|
||||||
>
|
>
|
||||||
@ -611,7 +676,9 @@ export function FinanceApp() {
|
|||||||
</button>
|
</button>
|
||||||
{rechargeApps.map((app) => (
|
{rechargeApps.map((app) => (
|
||||||
<button
|
<button
|
||||||
className={["finance-appchip", rechargeDetailFilters.appCode === app.appCode ? "is-on" : ""].filter(Boolean).join(" ")}
|
className={["finance-appchip", rechargeDetailFilters.appCode === app.appCode ? "is-on" : ""]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" ")}
|
||||||
key={app.appCode}
|
key={app.appCode}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => updateRechargeDetailFilters({ appCode: app.appCode, regionId: "" })}
|
onClick={() => updateRechargeDetailFilters({ appCode: app.appCode, regionId: "" })}
|
||||||
@ -629,7 +696,13 @@ export function FinanceApp() {
|
|||||||
canCreate={session.canCreateApplication}
|
canCreate={session.canCreateApplication}
|
||||||
canViewRechargeDetails={session.canViewAppRechargeDetails}
|
canViewRechargeDetails={session.canViewAppRechargeDetails}
|
||||||
canViewWithdrawals={session.canViewWithdrawalApplications}
|
canViewWithdrawals={session.canViewWithdrawalApplications}
|
||||||
loading={optionsState.loading || rechargeDetailsState.loading || myApplicationsState.loading || applicationsState.loading || withdrawalsState.loading}
|
loading={
|
||||||
|
optionsState.loading ||
|
||||||
|
rechargeDetailsState.loading ||
|
||||||
|
myApplicationsState.loading ||
|
||||||
|
applicationsState.loading ||
|
||||||
|
withdrawalsState.loading
|
||||||
|
}
|
||||||
session={session}
|
session={session}
|
||||||
subtitle={isFinanceView ? "中国时区 · 数据实时" : ""}
|
subtitle={isFinanceView ? "中国时区 · 数据实时" : ""}
|
||||||
toolbar={financeToolbar}
|
toolbar={financeToolbar}
|
||||||
@ -675,7 +748,8 @@ export function FinanceApp() {
|
|||||||
filters={rechargeDetailFilters}
|
filters={rechargeDetailFilters}
|
||||||
googlePaidRefreshing={googlePaidRefreshing}
|
googlePaidRefreshing={googlePaidRefreshing}
|
||||||
loading={rechargeDetailsState.loading}
|
loading={rechargeDetailsState.loading}
|
||||||
regions={rechargeRegionsState.items}
|
regions={rechargeRegionsState.byApp[rechargeAppCode] || []}
|
||||||
|
regionsByApp={rechargeRegionsState.byApp}
|
||||||
summary={rechargeSummaryState.merged}
|
summary={rechargeSummaryState.merged}
|
||||||
onExport={exportRechargeBills}
|
onExport={exportRechargeBills}
|
||||||
onFiltersChange={updateRechargeDetailFilters}
|
onFiltersChange={updateRechargeDetailFilters}
|
||||||
|
|||||||
@ -37,6 +37,7 @@ export function FinanceRechargeDetailList({
|
|||||||
onRefreshGooglePaid,
|
onRefreshGooglePaid,
|
||||||
onReload,
|
onReload,
|
||||||
regions,
|
regions,
|
||||||
|
regionsByApp,
|
||||||
summary,
|
summary,
|
||||||
}) {
|
}) {
|
||||||
const [expandedId, setExpandedId] = useState("");
|
const [expandedId, setExpandedId] = useState("");
|
||||||
@ -231,7 +232,7 @@ export function FinanceRechargeDetailList({
|
|||||||
</AmountText>
|
</AmountText>
|
||||||
</td>
|
</td>
|
||||||
<td className="r num">{taxDeductionText(item)}</td>
|
<td className="r num">{taxDeductionText(item)}</td>
|
||||||
<td>{regionText(item, regionNames)}</td>
|
<td>{regionText(item, regionsByApp, apps, !filters.appCode)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{expanded ? (
|
{expanded ? (
|
||||||
<tr className="finance-detailrow">
|
<tr className="finance-detailrow">
|
||||||
@ -445,12 +446,15 @@ function appName(appCode, apps) {
|
|||||||
return (apps || []).find((app) => app.appCode === appCode)?.appName || appCode || "-";
|
return (apps || []).find((app) => app.appCode === appCode)?.appName || appCode || "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
function regionText(item, regionNames) {
|
// regionText 解析区域列:全部 App 视图下带上 App 前缀(如 “Lalu-南亚区”),单 App 视图只显示区域名。
|
||||||
|
function regionText(item, regionsByApp, apps, withAppPrefix) {
|
||||||
const regionId = item.targetRegionId || item.sellerRegionId;
|
const regionId = item.targetRegionId || item.sellerRegionId;
|
||||||
if (!regionId) {
|
if (!regionId) {
|
||||||
return "—";
|
return "—";
|
||||||
}
|
}
|
||||||
return regionNames.get(String(regionId)) || `区域 ${regionId}`;
|
const appRegions = (regionsByApp || {})[item.appCode] || [];
|
||||||
|
const name = appRegions.find((region) => String(region.regionId) === String(regionId))?.name || `区域 ${regionId}`;
|
||||||
|
return withAppPrefix ? `${appName(item.appCode, apps)}-${name}` : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function secondaryOrderNo(item) {
|
function secondaryOrderNo(item) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user