refactor(settings): 设置页面重构 & 支付状态优化
- SettingsPage: 功能增强 - PaymentStatus: 关闭按钮样式优化 - InvoicePage: 支持嵌入模式
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 发票管理页面
|
||||
*/
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
@@ -31,38 +31,49 @@ import {
|
||||
StatLabel,
|
||||
StatNumber,
|
||||
StatHelpText,
|
||||
} from '@chakra-ui/react';
|
||||
import { FileText, Plus, RefreshCw, Clock, CheckCircle, AlertCircle } from 'lucide-react';
|
||||
import Card from '@components/Card/Card';
|
||||
import CardHeader from '@components/Card/CardHeader';
|
||||
import { InvoiceCard, InvoiceApplyModal } from '@components/Invoice';
|
||||
} from "@chakra-ui/react";
|
||||
import {
|
||||
FileText,
|
||||
Plus,
|
||||
RefreshCw,
|
||||
Clock,
|
||||
CheckCircle,
|
||||
AlertCircle,
|
||||
} from "lucide-react";
|
||||
import Card from "@components/Card/Card";
|
||||
import CardHeader from "@components/Card/CardHeader";
|
||||
import { InvoiceCard, InvoiceApplyModal } from "@components/Invoice";
|
||||
import {
|
||||
getInvoiceList,
|
||||
getInvoiceStats,
|
||||
cancelInvoice,
|
||||
downloadInvoice,
|
||||
} from '@/services/invoiceService';
|
||||
import type { InvoiceInfo, InvoiceStatus, InvoiceStats } from '@/types/invoice';
|
||||
} from "@/services/invoiceService";
|
||||
import type { InvoiceInfo, InvoiceStatus, InvoiceStats } from "@/types/invoice";
|
||||
|
||||
type TabType = 'all' | 'pending' | 'processing' | 'completed';
|
||||
type TabType = "all" | "pending" | "processing" | "completed";
|
||||
|
||||
const tabConfig: { key: TabType; label: string; status?: InvoiceStatus }[] = [
|
||||
{ key: 'all', label: '全部' },
|
||||
{ key: 'pending', label: '待处理', status: 'pending' },
|
||||
{ key: 'processing', label: '处理中', status: 'processing' },
|
||||
{ key: 'completed', label: '已完成', status: 'completed' },
|
||||
{ key: "all", label: "全部" },
|
||||
{ key: "pending", label: "待处理", status: "pending" },
|
||||
{ key: "processing", label: "处理中", status: "processing" },
|
||||
{ key: "completed", label: "已完成", status: "completed" },
|
||||
];
|
||||
|
||||
export default function InvoicePage() {
|
||||
interface InvoicePageProps {
|
||||
embedded?: boolean;
|
||||
}
|
||||
|
||||
export default function InvoicePage({ embedded = false }: InvoicePageProps) {
|
||||
const [invoices, setInvoices] = useState<InvoiceInfo[]>([]);
|
||||
const [stats, setStats] = useState<InvoiceStats | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [activeTab, setActiveTab] = useState<TabType>('all');
|
||||
const [activeTab, setActiveTab] = useState<TabType>("all");
|
||||
const [cancelingId, setCancelingId] = useState<string | null>(null);
|
||||
|
||||
const toast = useToast();
|
||||
const textColor = useColorModeValue('gray.700', 'white');
|
||||
const bgCard = useColorModeValue('white', 'gray.800');
|
||||
const textColor = useColorModeValue("gray.700", "white");
|
||||
const bgCard = useColorModeValue("white", "gray.800");
|
||||
const cancelDialogRef = React.useRef<HTMLButtonElement>(null);
|
||||
|
||||
const {
|
||||
@@ -87,11 +98,11 @@ export default function InvoicePage() {
|
||||
setInvoices(res.data.list || []);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载发票列表失败:', error);
|
||||
console.error("加载发票列表失败:", error);
|
||||
toast({
|
||||
title: '加载失败',
|
||||
description: '无法获取发票列表',
|
||||
status: 'error',
|
||||
title: "加载失败",
|
||||
description: "无法获取发票列表",
|
||||
status: "error",
|
||||
duration: 3000,
|
||||
});
|
||||
} finally {
|
||||
@@ -107,7 +118,7 @@ export default function InvoicePage() {
|
||||
setStats(res.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载发票统计失败:', error);
|
||||
console.error("加载发票统计失败:", error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -124,25 +135,25 @@ export default function InvoicePage() {
|
||||
const res = await cancelInvoice(cancelingId);
|
||||
if (res.code === 200) {
|
||||
toast({
|
||||
title: '取消成功',
|
||||
status: 'success',
|
||||
title: "取消成功",
|
||||
status: "success",
|
||||
duration: 2000,
|
||||
});
|
||||
loadInvoices();
|
||||
loadStats();
|
||||
} else {
|
||||
toast({
|
||||
title: '取消失败',
|
||||
title: "取消失败",
|
||||
description: res.message,
|
||||
status: 'error',
|
||||
status: "error",
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: '取消失败',
|
||||
description: '网络错误',
|
||||
status: 'error',
|
||||
title: "取消失败",
|
||||
description: "网络错误",
|
||||
status: "error",
|
||||
duration: 3000,
|
||||
});
|
||||
} finally {
|
||||
@@ -156,7 +167,7 @@ export default function InvoicePage() {
|
||||
try {
|
||||
const blob = await downloadInvoice(invoice.id);
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `发票_${invoice.invoiceNo || invoice.id}.pdf`;
|
||||
document.body.appendChild(a);
|
||||
@@ -165,9 +176,9 @@ export default function InvoicePage() {
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: '下载失败',
|
||||
description: '无法下载发票文件',
|
||||
status: 'error',
|
||||
title: "下载失败",
|
||||
description: "无法下载发票文件",
|
||||
status: "error",
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
@@ -186,11 +197,17 @@ export default function InvoicePage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex direction="column" pt={{ base: '120px', md: '75px' }}>
|
||||
<Flex direction="column" pt={embedded ? 0 : { base: "120px", md: "75px" }}>
|
||||
{/* 统计卡片 */}
|
||||
{stats && (
|
||||
<SimpleGrid columns={{ base: 2, md: 4 }} spacing={4} mb={6}>
|
||||
<Card p={4}>
|
||||
<Card
|
||||
p={4}
|
||||
bg="transparent"
|
||||
border="1px solid"
|
||||
borderColor="rgba(212, 175, 55, 0.3)"
|
||||
backdropFilter="blur(10px)"
|
||||
>
|
||||
<Stat>
|
||||
<StatLabel color="gray.500">全部申请</StatLabel>
|
||||
<StatNumber color={textColor}>{stats.total}</StatNumber>
|
||||
@@ -200,7 +217,13 @@ export default function InvoicePage() {
|
||||
</StatHelpText>
|
||||
</Stat>
|
||||
</Card>
|
||||
<Card p={4}>
|
||||
<Card
|
||||
p={4}
|
||||
bg="transparent"
|
||||
border="1px solid"
|
||||
borderColor="rgba(212, 175, 55, 0.3)"
|
||||
backdropFilter="blur(10px)"
|
||||
>
|
||||
<Stat>
|
||||
<StatLabel color="gray.500">待处理</StatLabel>
|
||||
<StatNumber color="yellow.500">{stats.pending}</StatNumber>
|
||||
@@ -210,7 +233,13 @@ export default function InvoicePage() {
|
||||
</StatHelpText>
|
||||
</Stat>
|
||||
</Card>
|
||||
<Card p={4}>
|
||||
<Card
|
||||
p={4}
|
||||
bg="transparent"
|
||||
border="1px solid"
|
||||
borderColor="rgba(212, 175, 55, 0.3)"
|
||||
backdropFilter="blur(10px)"
|
||||
>
|
||||
<Stat>
|
||||
<StatLabel color="gray.500">处理中</StatLabel>
|
||||
<StatNumber color="blue.500">{stats.processing}</StatNumber>
|
||||
@@ -220,7 +249,13 @@ export default function InvoicePage() {
|
||||
</StatHelpText>
|
||||
</Stat>
|
||||
</Card>
|
||||
<Card p={4}>
|
||||
<Card
|
||||
p={4}
|
||||
bg="transparent"
|
||||
border="1px solid"
|
||||
borderColor="rgba(212, 175, 55, 0.3)"
|
||||
backdropFilter="blur(10px)"
|
||||
>
|
||||
<Stat>
|
||||
<StatLabel color="gray.500">已完成</StatLabel>
|
||||
<StatNumber color="green.500">{stats.completed}</StatNumber>
|
||||
@@ -234,7 +269,12 @@ export default function InvoicePage() {
|
||||
)}
|
||||
|
||||
{/* 主内容区 */}
|
||||
<Card>
|
||||
<Card
|
||||
bg="transparent"
|
||||
border="1px solid"
|
||||
borderColor="rgba(212, 175, 55, 0.3)"
|
||||
backdropFilter="blur(10px)"
|
||||
>
|
||||
<CardHeader>
|
||||
<Flex justify="space-between" align="center" w="100%" mb={4}>
|
||||
<HStack>
|
||||
@@ -340,7 +380,9 @@ export default function InvoicePage() {
|
||||
取消开票申请
|
||||
</AlertDialogHeader>
|
||||
|
||||
<AlertDialogBody>确定要取消这个开票申请吗?取消后可重新申请。</AlertDialogBody>
|
||||
<AlertDialogBody>
|
||||
确定要取消这个开票申请吗?取消后可重新申请。
|
||||
</AlertDialogBody>
|
||||
|
||||
<AlertDialogFooter>
|
||||
<Button ref={cancelDialogRef} onClick={onCancelClose}>
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
Icon,
|
||||
Button,
|
||||
} from '@chakra-ui/react';
|
||||
import { CheckCircle, XCircle, AlertCircle } from 'lucide-react';
|
||||
import { CheckCircle, XCircle, AlertCircle, X } from 'lucide-react';
|
||||
import type { PaymentStatus as PaymentStatusType } from '../hooks/useWechatPay';
|
||||
|
||||
interface PaymentStatusProps {
|
||||
@@ -94,7 +94,24 @@ export const PaymentStatus: React.FC<PaymentStatusProps> = ({
|
||||
maxW="400px"
|
||||
w="full"
|
||||
textAlign="center"
|
||||
position="relative"
|
||||
>
|
||||
{/* 右上角关闭按钮 */}
|
||||
{onBack && (
|
||||
<Box
|
||||
position="absolute"
|
||||
top={3}
|
||||
right={3}
|
||||
cursor="pointer"
|
||||
p={1}
|
||||
borderRadius="full"
|
||||
_hover={{ bg: 'whiteAlpha.200' }}
|
||||
onClick={onBack}
|
||||
>
|
||||
<Icon as={X} boxSize={5} color="gray.400" />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* 图标或加载动画 */}
|
||||
{config.showSpinner ? (
|
||||
<Spinner size="xl" color="gold.400" thickness="4px" />
|
||||
@@ -135,27 +152,16 @@ export const PaymentStatus: React.FC<PaymentStatusProps> = ({
|
||||
)}
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<VStack spacing={3} w="full" pt={4}>
|
||||
{(status === 'failed' || status === 'cancelled') && onRetry && (
|
||||
<Button
|
||||
w="full"
|
||||
colorScheme="yellow"
|
||||
onClick={onRetry}
|
||||
>
|
||||
重新支付
|
||||
</Button>
|
||||
)}
|
||||
{onBack && (
|
||||
<Button
|
||||
w="full"
|
||||
variant="ghost"
|
||||
color="gray.400"
|
||||
onClick={onBack}
|
||||
>
|
||||
返回
|
||||
</Button>
|
||||
)}
|
||||
</VStack>
|
||||
{(status === 'failed' || status === 'cancelled') && onRetry && (
|
||||
<Button
|
||||
w="full"
|
||||
colorScheme="yellow"
|
||||
onClick={onRetry}
|
||||
mt={4}
|
||||
>
|
||||
重新支付
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* 支付中提示 */}
|
||||
{status === 'paying' && (
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user