feat: 本次提交更新内容如下
充值页面做完了
This commit is contained in:
@@ -3,54 +3,108 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.user-card {
|
.user-card {
|
||||||
margin-bottom: 16px;
|
border-radius: 16px;
|
||||||
border-radius: 12px;
|
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
|
||||||
overflow: hidden;
|
margin: 16px 0 12px 0;
|
||||||
|
padding: 0 0 0 0;
|
||||||
:global(.adm-card-body) {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-info {
|
.user-info-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 16px;
|
padding: 20px 24px 16px 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-avatar {
|
.user-avatar {
|
||||||
width: 60px;
|
width: 56px;
|
||||||
height: 60px;
|
height: 56px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
background: #f5f5f5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1890ff;
|
||||||
|
margin-right: 18px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 2px solid var(--primary-color);
|
}
|
||||||
|
.avatar-placeholder {
|
||||||
img {
|
width: 100%;
|
||||||
width: 100%;
|
height: 100%;
|
||||||
height: 100%;
|
display: flex;
|
||||||
object-fit: cover;
|
align-items: center;
|
||||||
}
|
justify-content: center;
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1890ff;
|
||||||
|
background: #e6f7ff;
|
||||||
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-details {
|
.user-main-info {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-main-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
.user-name {
|
.user-name {
|
||||||
font-size: 18px;
|
font-size: 20px;
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
color: #333;
|
color: #222;
|
||||||
|
margin-right: 2px;
|
||||||
}
|
}
|
||||||
|
.role-badge {
|
||||||
.user-level {
|
background: #fa8c16;
|
||||||
font-size: 14px;
|
color: #fff;
|
||||||
color: var(--primary-color);
|
font-size: 13px;
|
||||||
margin-bottom: 4px;
|
font-weight: 500;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 2px 10px;
|
||||||
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
.balance-label {
|
||||||
.user-points {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
color: #666;
|
||||||
|
font-size: 15px;
|
||||||
|
margin-right: 2px;
|
||||||
|
}
|
||||||
|
.balance-value {
|
||||||
|
color: #16b364;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
.recharge-btn {
|
||||||
|
margin-right: 8px;
|
||||||
|
padding: 0 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.icon-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: none;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #666;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
.last-login {
|
||||||
|
color: #888;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 6px;
|
||||||
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-card {
|
.menu-card {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ const Mine: React.FC = () => {
|
|||||||
wechat: 25,
|
wechat: 25,
|
||||||
traffic: 8,
|
traffic: 8,
|
||||||
content: 156,
|
content: 156,
|
||||||
|
balance: 0,
|
||||||
});
|
});
|
||||||
const [showLogoutDialog, setShowLogoutDialog] = useState(false);
|
const [showLogoutDialog, setShowLogoutDialog] = useState(false);
|
||||||
|
|
||||||
@@ -90,6 +91,7 @@ const Mine: React.FC = () => {
|
|||||||
wechat: res.wechatNum,
|
wechat: res.wechatNum,
|
||||||
traffic: 999,
|
traffic: 999,
|
||||||
content: 999,
|
content: 999,
|
||||||
|
balance: res.balance || 0,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("加载统计数据失败:", error);
|
console.error("加载统计数据失败:", error);
|
||||||
@@ -173,45 +175,51 @@ const Mine: React.FC = () => {
|
|||||||
footer={<MeauMobile activeKey="mine" />}
|
footer={<MeauMobile activeKey="mine" />}
|
||||||
>
|
>
|
||||||
<div className={style["mine-page"]}>
|
<div className={style["mine-page"]}>
|
||||||
{/* 用户信息卡片 */}
|
{/* 用户信息卡片(严格按图片风格) */}
|
||||||
<Card className={style["user-card"]}>
|
<Card className={style["user-card"]}>
|
||||||
<div className={style["user-info"]}>
|
<div className={style["user-info-row"]}>
|
||||||
<div className={style["user-avatar"]}>{renderUserAvatar()}</div>
|
{/* 头像 */}
|
||||||
<div className={style["user-details"]}>
|
<div className={style["user-avatar"]}>
|
||||||
<div
|
{currentUserInfo.avatar ? (
|
||||||
style={{
|
<img src={currentUserInfo.avatar} alt="头像" />
|
||||||
display: "flex",
|
) : (
|
||||||
alignItems: "center",
|
<div className={style["avatar-placeholder"]}>卡</div>
|
||||||
gap: "8px",
|
)}
|
||||||
}}
|
</div>
|
||||||
>
|
{/* 右侧内容 */}
|
||||||
<div className={style["user-name"]}>{currentUserInfo.name}</div>
|
<div className={style["user-main-info"]}>
|
||||||
<span
|
<div className={style["user-main-row"]}>
|
||||||
style={{
|
<span className={style["user-name"]}>
|
||||||
padding: "2px 8px",
|
{currentUserInfo.name}
|
||||||
backgroundColor: "#fa8c16",
|
</span>
|
||||||
color: "white",
|
<span className={style["role-badge"]}>
|
||||||
borderRadius: "12px",
|
|
||||||
fontSize: "12px",
|
|
||||||
fontWeight: "500",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{currentUserInfo.role}
|
{currentUserInfo.role}
|
||||||
</span>
|
</span>
|
||||||
|
<span className={style["balance-label"]}>余额:</span>
|
||||||
|
<span className={style["balance-value"]}>
|
||||||
|
¥{Number(stats.balance || 0).toFixed(2)}
|
||||||
|
</span>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
color="primary"
|
||||||
|
className={style["recharge-btn"]}
|
||||||
|
onClick={() => navigate("/recharge")}
|
||||||
|
>
|
||||||
|
充值
|
||||||
|
</Button>
|
||||||
|
<span className={style["icon-btn"]}>
|
||||||
|
<i className="iconfont icon-bell" />
|
||||||
|
</span>
|
||||||
|
<span className={style["icon-btn"]}>
|
||||||
|
<i
|
||||||
|
className="iconfont icon-setting"
|
||||||
|
onClick={() => navigate("/settings")}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className={style["last-login"]}>
|
||||||
style={{ fontSize: "14px", color: "#666", marginBottom: "4px" }}
|
最近登录:{currentUserInfo.lastLogin}
|
||||||
>
|
|
||||||
{currentUserInfo.email}
|
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "12px", color: "#666" }}>
|
|
||||||
最近登录: {currentUserInfo.lastLogin}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{ display: "flex", flexDirection: "column", gap: "8px" }}
|
|
||||||
>
|
|
||||||
<SettingOutlined style={{ fontSize: "20px", color: "#666" }} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
127
nkebao/src/pages/mine/recharge/index.module.scss
Normal file
127
nkebao/src/pages/mine/recharge/index.module.scss
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
.recharge-page {
|
||||||
|
padding: 16px 0 60px 0;
|
||||||
|
background: #f7f8fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.balance-card {
|
||||||
|
margin: 16px;
|
||||||
|
background: #f6ffed;
|
||||||
|
border: 1px solid #b7eb8f;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 18px 0 18px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.balance-content {
|
||||||
|
display: flex;
|
||||||
|
color: #16b364;
|
||||||
|
padding-left: 30px;
|
||||||
|
}
|
||||||
|
.wallet-icon {
|
||||||
|
color: #16b364;
|
||||||
|
font-size: 30px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.balance-info {
|
||||||
|
margin-left: 15px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.balance-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.balance-amount {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #16b364;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-card {
|
||||||
|
margin: 16px;
|
||||||
|
.quick-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc-card {
|
||||||
|
margin: 16px;
|
||||||
|
background: #fffbe6;
|
||||||
|
border: 1px solid #ffe58f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warn-card {
|
||||||
|
margin: 16px;
|
||||||
|
background: #fff2e8;
|
||||||
|
border: 1px solid #ffbb96;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-title {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.quick-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
justify-content: flex-start;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.quick-btn {
|
||||||
|
min-width: 80px;
|
||||||
|
margin: 4px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.quick-btn-active {
|
||||||
|
@extend .quick-btn;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.recharge-main-btn {
|
||||||
|
margin-top: 16px;
|
||||||
|
font-size: 18px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.desc-title {
|
||||||
|
font-weight: 500;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.desc-text {
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.warn-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
color: #faad14;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.warn-icon {
|
||||||
|
font-size: 30px;
|
||||||
|
color: #faad14;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.warn-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.warn-title {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.warn-text {
|
||||||
|
color: #faad14;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
101
nkebao/src/pages/mine/recharge/index.tsx
Normal file
101
nkebao/src/pages/mine/recharge/index.tsx
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { Card, Button, Toast, NavBar } from "antd-mobile";
|
||||||
|
import { useUserStore } from "@/store/module/user";
|
||||||
|
import style from "./index.module.scss";
|
||||||
|
import { WalletOutlined, WarningOutlined } from "@ant-design/icons";
|
||||||
|
import NavCommon from "@/components/NavCommon";
|
||||||
|
import Layout from "@/components/Layout/Layout";
|
||||||
|
|
||||||
|
const quickAmounts = [50, 100, 200, 500, 1000];
|
||||||
|
|
||||||
|
const Recharge: React.FC = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { user } = useUserStore();
|
||||||
|
// 假设余额从后端接口获取,实际可用props或store传递
|
||||||
|
const [balance, setBalance] = useState(0);
|
||||||
|
const [selected, setSelected] = useState<number | null>(null);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
// 充值操作
|
||||||
|
const handleRecharge = async () => {
|
||||||
|
if (!selected) {
|
||||||
|
Toast.show({ content: "请选择充值金额", position: "top" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoading(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setBalance((b) => b + selected);
|
||||||
|
Toast.show({ content: `充值成功,已到账¥${selected}` });
|
||||||
|
setLoading(false);
|
||||||
|
}, 1200);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout header={<NavCommon title="账户充值" />}>
|
||||||
|
<div className={style["recharge-page"]}>
|
||||||
|
<Card className={style["balance-card"]}>
|
||||||
|
<div className={style["balance-content"]}>
|
||||||
|
<WalletOutlined className={style["wallet-icon"]} />
|
||||||
|
<div className={style["balance-info"]}>
|
||||||
|
<div className={style["balance-label"]}>当前余额</div>
|
||||||
|
<div className={style["balance-amount"]}>
|
||||||
|
¥{balance.toFixed(2)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
<Card className={style["quick-card"]}>
|
||||||
|
<div className={style["quick-title"]}>快捷充值</div>
|
||||||
|
<div className={style["quick-list"]}>
|
||||||
|
{quickAmounts.map((amt) => (
|
||||||
|
<Button
|
||||||
|
key={amt}
|
||||||
|
color={selected === amt ? "primary" : "default"}
|
||||||
|
className={
|
||||||
|
selected === amt
|
||||||
|
? style["quick-btn-active"]
|
||||||
|
: style["quick-btn"]
|
||||||
|
}
|
||||||
|
onClick={() => setSelected(amt)}
|
||||||
|
>
|
||||||
|
¥{amt}
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
block
|
||||||
|
color="primary"
|
||||||
|
size="large"
|
||||||
|
className={style["recharge-main-btn"]}
|
||||||
|
loading={loading}
|
||||||
|
onClick={handleRecharge}
|
||||||
|
>
|
||||||
|
立即充值
|
||||||
|
</Button>
|
||||||
|
</Card>
|
||||||
|
<Card className={style["desc-card"]}>
|
||||||
|
<div className={style["desc-title"]}>服务消耗</div>
|
||||||
|
<div className={style["desc-text"]}>
|
||||||
|
使用以下服务将从余额中扣除相应费用。
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
{balance < 10 && (
|
||||||
|
<Card className={style["warn-card"]}>
|
||||||
|
<div className={style["warn-content"]}>
|
||||||
|
<WarningOutlined className={style["warn-icon"]} />
|
||||||
|
<div className={style["warn-info"]}>
|
||||||
|
<div className={style["warn-title"]}>余额不足提醒</div>
|
||||||
|
<div className={style["warn-text"]}>
|
||||||
|
当前余额较低,建议及时充值以免影响服务使用
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Recharge;
|
||||||
@@ -2,6 +2,7 @@ import Home from "@/pages/home/index";
|
|||||||
import Mine from "@/pages/mine/index";
|
import Mine from "@/pages/mine/index";
|
||||||
import WechatAccounts from "@/pages/wechat-accounts/list/index";
|
import WechatAccounts from "@/pages/wechat-accounts/list/index";
|
||||||
import WechatAccountDetail from "@/pages/wechat-accounts/detail/index";
|
import WechatAccountDetail from "@/pages/wechat-accounts/detail/index";
|
||||||
|
import Recharge from "@/pages/mine/recharge/index";
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
// 基础路由
|
// 基础路由
|
||||||
@@ -26,6 +27,11 @@ const routes = [
|
|||||||
element: <WechatAccountDetail />,
|
element: <WechatAccountDetail />,
|
||||||
auth: true,
|
auth: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/recharge",
|
||||||
|
element: <Recharge />,
|
||||||
|
auth: true,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default routes;
|
export default routes;
|
||||||
|
|||||||
Reference in New Issue
Block a user