feat(core/frontend): wire P0 team mgmt / recharge / notifications

- App.tsx: load notifications, expose team/recharge/notification handlers, real unread bell count (was hardcoded 12)
- team.tsx: create/edit/reset-password/remove member + team recharge modals
- account.tsx: recharge via wechat/alipay buttons + custom amount
- messages.tsx: real notification inbox, mark-read on select, mark-all-read
- verified: tsc --noEmit clean; e2e create->update->reset->recharge->mark-read->delete all green

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209
2026-06-05 12:48:51 +08:00
co-authored by Claude Opus 4.8
parent d41e487f08
commit 25bf3293df
6 changed files with 407 additions and 38 deletions
+22 -10
View File
@@ -4,11 +4,11 @@ import { money } from "./stage-config";
type Tab = "overview" | "by-project" | "by-member" | "bills";
const RECHARGE: Array<{ amt: number; gift: string; bonus: boolean; ribbon?: string }> = [
{ amt: 100, gift: "无赠送", bonus: false },
{ amt: 500, gift: "+ ¥30 赠送", bonus: true, ribbon: "推荐" },
{ amt: 1000, gift: "+ ¥80 赠送", bonus: true },
{ amt: 3000, gift: "+ ¥300 赠送", bonus: true }
const RECHARGE: Array<{ amt: number; gift: string; bonus: boolean; bonusAmt: number; ribbon?: string }> = [
{ amt: 100, gift: "无赠送", bonus: false, bonusAmt: 0 },
{ amt: 500, gift: "+ ¥30 赠送", bonus: true, bonusAmt: 30, ribbon: "推荐" },
{ amt: 1000, gift: "+ ¥80 赠送", bonus: true, bonusAmt: 80 },
{ amt: 3000, gift: "+ ¥300 赠送", bonus: true, bonusAmt: 300 }
];
const STAGES: Array<{ k: string; color: string }> = [
@@ -18,14 +18,26 @@ const STAGES: Array<{ k: string; color: string }> = [
{ k: "脚本 LLM", color: "var(--black-alpha-32)" }
];
export function AccountPage({ billing, ledgers, projects, teamMembers }: {
export function AccountPage({ billing, ledgers, projects, teamMembers, onRecharge }: {
billing: BillingSummary | null;
ledgers: Ledger[];
projects: Project[];
teamMembers: TeamMember[];
onRecharge: (amount: number, bonus: number) => void | Promise<unknown>;
}) {
const [tab, setTab] = useState<Tab>("overview");
const [recharge, setRecharge] = useState(500);
const [customAmt, setCustomAmt] = useState("");
const selectedCard = RECHARGE.find((item) => item.amt === recharge);
const effectiveAmount = Number(customAmt) > 0 ? Number(customAmt) : recharge;
const effectiveBonus = Number(customAmt) > 0 ? 0 : selectedCard?.bonusAmt || 0;
async function submitRecharge() {
if (effectiveAmount <= 0) return;
await onRecharge(effectiveAmount, effectiveBonus);
setCustomAmt("");
}
const balance = Number(billing?.account.balance || 0);
const used = Number(billing?.charged_total || 0);
@@ -78,7 +90,7 @@ export function AccountPage({ billing, ledgers, projects, teamMembers }: {
<h3></h3>
<div className="desc">// 充值后立刻到账,可开发票 · 仅超管可操作</div>
</div>
<div className="topup-selected"> ¥{recharge}</div>
<div className="topup-selected"> ¥{effectiveAmount}{effectiveBonus > 0 ? ` + ¥${effectiveBonus} 赠送` : ""}</div>
</div>
<div className="recharge-row">
{RECHARGE.map((item) => (
@@ -98,13 +110,13 @@ export function AccountPage({ billing, ledgers, projects, teamMembers }: {
</div>
<div className="pay-row">
<div className="pay-title"></div>
<input className="input" placeholder="最低 ¥50,可输入任意金额" />
<input className="input" placeholder="最低 ¥50,可输入任意金额" type="number" value={customAmt} onChange={(event) => setCustomAmt(event.target.value)} />
<div className="pay-btn-row">
<button className="btn pay-method-btn pay-wechat" type="button" aria-label="微信支付">
<button className="btn pay-method-btn pay-wechat" type="button" aria-label="微信支付" onClick={submitRecharge}>
<span className="pay-logo" aria-hidden="true"><img src="/assets/pay-wechat.png" alt="" /></span>
</button>
<button className="btn pay-method-btn pay-alipay" type="button" aria-label="支付宝">
<button className="btn pay-method-btn pay-alipay" type="button" aria-label="支付宝" onClick={submitRecharge}>
<span className="pay-logo" aria-hidden="true"><img src="/assets/pay-alipay.png" alt="" /></span>
</button>