完善项目工作台入口与账户兑换码

修复 DirectProject 提交时的项目快照空值类型错误

将运行中项目列表移入窗口标题栏并支持展开查看

增加项目内打开项目目录按钮

在账户资产条中直接显示兑换码入口并保留兑换弹窗

补充相关测试、类型检查与产品文档
This commit is contained in:
Git Hooks Test
2026-09-16 01:54:29 +08:00
parent 9722442b44
commit d650bf9b74
18 changed files with 712 additions and 34 deletions
@@ -60,6 +60,25 @@ test('shows only permanent and daily free points in the shared wallet panel', as
expect(onRecharge).toHaveBeenCalledTimes(1);
});
test('shows the redeem-code entry directly in the wallet bar when provided', async () => {
const user = userEvent.setup();
const onRedeemCode = vi.fn();
render(
<PlatformMudPointWalletEntry
balance={207}
breakdown={breakdown}
onRequestDetails={vi.fn()}
onRecharge={vi.fn()}
onOpenLedger={vi.fn()}
onRedeemCode={onRedeemCode}
/>,
);
await user.click(screen.getByRole('button', { name: '兑换码' }));
expect(onRedeemCode).toHaveBeenCalledTimes(1);
});
test('keeps the chip on the live balance when cached details are stale', () => {
const props = {
breakdown,
@@ -22,6 +22,7 @@ export type PlatformMudPointWalletEntryProps = {
onRequestDetails: () => void;
onRecharge: () => void;
onOpenLedger: () => void;
onRedeemCode?: () => void;
};
function MudPointBalanceRow({
@@ -62,6 +63,7 @@ export function PlatformMudPointWalletEntry({
onRequestDetails,
onRecharge,
onOpenLedger,
onRedeemCode,
}: PlatformMudPointWalletEntryProps) {
const rootRef = useRef<HTMLDivElement | null>(null);
const isOpenRef = useRef(false);
@@ -224,6 +226,24 @@ export function PlatformMudPointWalletEntry({
>
</button>
{onRedeemCode ? (
<>
<span
className="my-1.5 w-px shrink-0 bg-[rgba(196,153,120,0.36)]"
aria-hidden="true"
/>
<button
type="button"
className="shrink-0 px-2.5 font-black outline-none transition-colors hover:bg-white/75 focus-visible:bg-white/80"
onClick={() => {
closeDetails();
onRedeemCode();
}}
>
</button>
</>
) : null}
</div>
{isOpen ? (
@@ -281,6 +301,19 @@ export function PlatformMudPointWalletEntry({
使
<ChevronRight className="h-3.5 w-3.5" aria-hidden="true" />
</button>
{onRedeemCode ? (
<button
type="button"
className="flex w-full items-center justify-center gap-2 border-t border-[rgba(194,145,111,0.28)] px-4 py-3 text-[13px] font-black text-[var(--platform-text-strong)] outline-none transition-colors hover:bg-white/55 focus-visible:bg-white/65"
onClick={() => {
closeDetails();
onRedeemCode();
}}
>
<ChevronRight className="h-3.5 w-3.5" aria-hidden="true" />
</button>
) : null}
</div>
) : null}
</div>