import React, { useEffect, useState } from "react"; import { Plus, Search, X, Pencil, Trash2, History } from "lucide-react"; import { formatDateTime } from "./time.js"; const endpoint = "/api/admin/refund-payment-accounts"; const money = (fen) => (fen / 100).toFixed(2); const emptyForm = () => ({ name: "", alipay_account: "", balance: "0.00", single_limit: "500.00", is_active: true }); export default function RefundManagementPage({ api }) { const [data, setData] = useState({ items: [], total: 0, summary: {} }); const [query, setQuery] = useState(""); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(10); const [reload, setReload] = useState(0); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [editing, setEditing] = useState(null); const [form, setForm] = useState(emptyForm); const [saving, setSaving] = useState(false); const [saveError, setSaveError] = useState(""); const [deleting, setDeleting] = useState(null); const [deleteError, setDeleteError] = useState(""); const [ledger, setLedger] = useState(null); const [ledgerLoading, setLedgerLoading] = useState(false); const [ledgerPage, setLedgerPage] = useState(1); const [ledgerPageSize, setLedgerPageSize] = useState(10); const [funding, setFunding] = useState(null); const [fundAmount, setFundAmount] = useState(""); const [fundNote, setFundNote] = useState(""); const [fundSaving, setFundSaving] = useState(false); const [fundError, setFundError] = useState(""); useEffect(() => { let cancelled = false; setLoading(true); setError(""); const timer = setTimeout(async () => { try { const result = await api(`${endpoint}?${new URLSearchParams({ q: query, page, page_size: pageSize })}`); if (!cancelled) setData(result.data); } catch (err) { if (!cancelled) setError(err.message); } finally { if (!cancelled) setLoading(false); } }, 250); return () => { cancelled = true; clearTimeout(timer); }; }, [api, query, page, pageSize, reload]); function open(account) { setEditing(account || {}); setForm(account ? { name: account.name, alipay_account: account.alipay_account, balance: money(account.balance_fen), single_limit: money(account.single_limit_fen), is_active: account.is_active } : emptyForm()); setSaveError(""); } async function save(event) { event.preventDefault(); if (saving) return; setSaving(true); setSaveError(""); try { if (!form.name.trim() || !form.alipay_account.trim()) throw new Error("请填写账户名称和支付宝账户"); const moneyFields = editing.id ? [["single_limit", "单次付款限额"]] : [["balance", "初始资金"], ["single_limit", "单次付款限额"]]; for (const [key, label] of moneyFields) { if (!/^\d+(\.\d{1,2})?$/.test(form[key]) || Number(form[key]) > 9999999.99 || (key === "single_limit" && Number(form[key]) <= 0)) { throw new Error(`${label}需填写有效金额,最多两位小数,最高 9999999.99 元${key === "single_limit" ? ",且必须大于 0" : ""}`); } } await api(editing.id ? `${endpoint}/${editing.id}` : endpoint, { method: editing.id ? "PATCH" : "POST", body: JSON.stringify(form), }); setEditing(null); setPage(1); setReload((n) => n + 1); } catch (err) { setSaveError(typeof err.message === "string" ? err.message : "保存失败,请检查填写内容"); } finally { setSaving(false); } } async function remove(account) { if (deleting !== null || !window.confirm(`确定删除付款账户“${account.name}”(${account.alipay_account})吗?删除后无法恢复。`)) return; setDeleting(account.id); setDeleteError(""); try { await api(`${endpoint}/${account.id}`, { method: "DELETE" }); setPage(1); setReload((n) => n + 1); } catch (err) { setDeleteError(err.message || "删除失败,请重试"); } finally { setDeleting(null); } } async function loadLedger(account, targetPage = 1, targetPageSize = ledgerPageSize) { setLedger({ account, items: [] }); setLedgerLoading(true); try { const result = await api(endpoint + "/" + account.id + "/ledger?" + new URLSearchParams({ page: targetPage, page_size: targetPageSize })); setLedger(result.data); setLedgerPage(result.data.page); setLedgerPageSize(result.data.page_size); } catch (err) { setLedger({ account, items: [], error: err.message }); } finally { setLedgerLoading(false); } } async function openLedger(account) { setLedgerPage(1); await loadLedger(account, 1, ledgerPageSize); } function openFunding(account, type) { setFunding({ account, type }); setFundAmount(""); setFundNote(""); setFundError(""); } async function saveFunds(event) { event.preventDefault(); if (fundSaving) return; setFundSaving(true); setFundError(""); try { const amountPattern = funding.type === "追加资金" ? /^\d+(\.\d{1,2})?$/ : /^-?\d+(\.\d{1,2})?$/; const amount = Number(fundAmount); if (!amountPattern.test(fundAmount) || !Number.isFinite(amount) || amount === 0 || Math.abs(amount) > 9999999.99 || (funding.type === "追加资金" && amount <= 0)) { throw new Error(funding.type === "追加资金" ? "追加金额必须大于 0,最多两位小数" : "请输入非 0 的调整金额,减少资金请填写负数"); } if (funding.type === "资金调整" && !fundNote.trim()) throw new Error("资金调整必须填写原因"); await api(`${endpoint}/${funding.account.id}/funds`, { method: "POST", body: JSON.stringify({ adjustment_type: funding.type, amount: fundAmount, note: fundNote.trim() }), }); setFunding(null); setReload((n) => n + 1); } catch (err) { setFundError(err.message || "资金操作失败,请重试"); } finally { setFundSaving(false); } } const pages = Math.max(1, Math.ceil(data.total / pageSize)); return <>

返款管理

管理返款使用的支付宝付款账户。

累计入账¥{money(data.summary?.balance_fen || 0)}初始资金与后续追加合计
累计已使用¥{money(data.summary?.used_fen || 0)}已确认成功的返款
处理中¥{money(data.summary?.processing_fen || 0)}结果未明确,暂时冻结
可用余额¥{money(data.summary?.available_fen || 0)}累计入账减已使用和冻结
页面显示的是系统账面资金,不代表支付宝实际余额。返款成功后自动计入已使用,处理中订单会冻结对应金额。
{error ?
{error}
: null} {deleteError &&
{deleteError}
}
{loading ? : error ? null : data.items.length ? data.items.map((account) => ) : }
类型账户名称支付宝账户累计入账已使用处理中可用余额单次限额状态操作
加载中…
支付宝{account.name}{account.alipay_account} ¥{money(account.balance_fen)}¥{money(account.used_fen)}¥{money(account.processing_fen)} ¥{money(account.available_fen)}¥{money(account.single_limit_fen)} {account.is_active ? "启用" : "禁用"}
{query ? "未找到匹配账户" : "暂无付款账户,请点击新增付款账户"}
共 {data.total} 条记录 {page} / {pages}
{editing &&

{editing.id ? "编辑付款账户" : "新增付款账户"}

{editing.id ? : }

{editing.id ? "账户资金请使用“追加资金”或“资金调整”,每次变化都会记录流水。" : "初始资金保存后不能在编辑账户中直接修改,后续通过追加资金或资金调整维护。"}

{saveError &&
{saveError}
}
} {ledger &&

{ledger.account?.name || "付款账户"}资金流水

资金调整、成功返款和处理中冻结记录

{ledgerLoading ?
加载中…
: ledger.error ?
{ledger.error}
: <>
累计入账¥{money(ledger.account.balance_fen)}已使用¥{money(ledger.account.used_fen)}处理中¥{money(ledger.account.processing_fen)}可用余额¥{money(ledger.account.available_fen)}
{ledger.items.length ? ledger.items.map((item) =>
{item.type_label}{item.order_no || item.note || "--"}
= 0 ? "income" : "expense"}>{item.amount_fen >= 0 ? "+" : "-"}¥{money(Math.abs(item.amount_fen))}{formatDateTime(item.created_at)} · {item.operator_name || "系统"}
) :
暂无资金流水
}
共 {ledger.total || 0} 条 {ledgerPage} / {ledger.total_pages || 1}
}
} {funding &&

{funding.type}

{funding.account.name}

当前累计入账¥{money(funding.account.balance_fen)}当前可用余额¥{money(funding.account.available_fen)}

{funding.type === "追加资金" ? "仅允许增加资金,提交后会立即计入累计入账并生成流水。" : "允许增加或减少,但调整后的累计入账不能低于已使用与处理中金额之和。"}

{fundError &&
{fundError}
}
} ; }