feat: 本次提交更新内容如下

用户信息修改完成
This commit is contained in:
笔记本里的永平
2025-07-23 19:10:43 +08:00
parent 0b215ff1eb
commit 6479bea3ce
5 changed files with 257 additions and 12 deletions

View File

@@ -19,7 +19,7 @@
width: 56px;
height: 56px;
border-radius: 50%;
background: #f5f5f5;
background: #666;
display: flex;
align-items: center;
justify-content: center;
@@ -45,6 +45,7 @@
.user-main-info {
flex: 1;
min-width: 0;
position: relative;
}
.user-main-row {
@@ -87,6 +88,15 @@
line-height: 28px;
border-radius: 8px;
}
.icon-setting{
font-size: 26px;
color: #666;
position: absolute;
right: 0px;
top: 0px;
}
.icon-btn {
display: flex;
align-items: center;
@@ -178,6 +188,7 @@
.user-avatar {
width: 50px;
height: 50px;
background: #666;
}
.user-name {

View File

@@ -181,7 +181,7 @@ const Mine: React.FC = () => {
{/* 头像 */}
<div className={style["user-avatar"]}>
{currentUserInfo.avatar ? (
<img src={currentUserInfo.avatar} alt="头像" />
<img src={currentUserInfo.avatar} />
) : (
<div className={style["avatar-placeholder"]}></div>
)}
@@ -195,6 +195,12 @@ const Mine: React.FC = () => {
<span className={style["role-badge"]}>
{currentUserInfo.role}
</span>
<span className={style["icon-btn"]}>
<i className="iconfont icon-bell" />
</span>
</div>
<div>
<span className={style["balance-label"]}></span>
<span className={style["balance-value"]}>
{Number(stats.balance || 0).toFixed(2)}
@@ -202,24 +208,18 @@ const Mine: React.FC = () => {
<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 className={style["last-login"]}>
{currentUserInfo.lastLogin}
</div>
<SettingOutlined
className={style["icon-setting"]}
onClick={() => navigate("/settings")}
/>
</div>
</div>
</Card>

View File

@@ -0,0 +1,115 @@
.user-set-page {
background: #f7f8fa;
}
.user-card {
margin: 18px 16px 0 16px;
border-radius: 14px;
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
}
.user-info {
display: flex;
align-items: flex-start;
padding: 24px 20px 20px 20px;
}
.avatar {
width: 64px;
height: 64px;
border-radius: 50%;
background: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
font-weight: 700;
color: #1890ff;
margin-right: 22px;
overflow: hidden;
}
.avatar-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
font-weight: 700;
color: #1890ff;
background: #e6f7ff;
border-radius: 50%;
}
.info-list {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 14px;
}
.info-item {
display: flex;
align-items: center;
font-size: 16px;
}
.label {
color: #888;
min-width: 70px;
font-size: 15px;
}
.value {
color: #222;
font-weight: 500;
font-size: 16px;
margin-left: 8px;
word-break: break-all;
}
.avatar-upload {
position: relative;
cursor: pointer;
width: 64px;
height: 64px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
overflow: hidden;
background: #f5f5f5;
transition: box-shadow 0.2s;
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
}
.avatar-upload img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
}
.avatar-edit {
position: absolute;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.45);
color: #fff;
font-size: 13px;
text-align: center;
padding: 3px 0 2px 0;
border-radius: 0 0 32px 32px;
opacity: 0;
transition: opacity 0.2s;
pointer-events: none;
}
.avatar-upload:hover .avatar-edit {
opacity: 1;
pointer-events: auto;
}
.edit-input {
flex: 1;
min-width: 0;
font-size: 16px;
border-radius: 8px;
border: 1px solid #e5e6eb;
padding: 4px 10px;
background: #fafbfc;
}
.save-btn {
padding: 12px;
background: #fff;
}

View File

@@ -0,0 +1,113 @@
import React, { useRef, useState } from "react";
import { useUserStore } from "@/store/module/user";
import { Card, Button, Input, Toast } from "antd-mobile";
import style from "./index.module.scss";
import { useNavigate } from "react-router-dom";
import Layout from "@/components/Layout/Layout";
import NavCommon from "@/components/NavCommon";
const UserSetting: React.FC = () => {
const { user, setUser } = useUserStore();
const navigate = useNavigate();
const [nickname, setNickname] = useState(user?.username || "");
const [avatar, setAvatar] = useState(user?.avatar || "");
const [uploading, setUploading] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
// 头像上传
const handleAvatarChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (ev) => {
setAvatar(ev.target?.result as string);
};
reader.readAsDataURL(file);
};
// 保存
const handleSave = async () => {
if (!nickname.trim()) {
Toast.show({ content: "昵称不能为空", position: "top" });
return;
}
if (!user) return;
setUser({ ...user, id: user.id, username: nickname, avatar });
Toast.show({ content: "保存成功", position: "top" });
navigate(-1);
};
return (
<Layout
header={<NavCommon title="用户信息修改" />}
footer={
<div className={style["save-btn"]}>
<Button
block
color="primary"
onClick={handleSave}
loading={uploading}
>
</Button>
</div>
}
>
<div className={style["user-set-page"]}>
<Card className={style["user-card"]}>
<div className={style["user-info"]}>
<div className={style["avatar"]}>
<div
className={style["avatar-upload"]}
onClick={() => fileInputRef.current?.click()}
>
{avatar ? (
<img src={avatar} alt="头像" />
) : (
<div className={style["avatar-placeholder"]}></div>
)}
<div className={style["avatar-edit"]}></div>
<input
ref={fileInputRef}
type="file"
accept="image/*"
style={{ display: "none" }}
onChange={handleAvatarChange}
disabled={uploading}
/>
</div>
</div>
<div className={style["info-list"]}>
<div className={style["info-item"]}>
<span className={style["label"]}></span>
<Input
className={style["edit-input"]}
value={nickname}
onChange={setNickname}
maxLength={12}
placeholder="请输入昵称"
/>
</div>
<div className={style["info-item"]}>
<span className={style["label"]}></span>
<span className={style["value"]}>{user?.phone || "-"}</span>
</div>
<div className={style["info-item"]}>
<span className={style["label"]}></span>
<span className={style["value"]}>{user?.account || "-"}</span>
</div>
<div className={style["info-item"]}>
<span className={style["label"]}></span>
<span className={style["value"]}>
{user?.isAdmin === 1 ? "管理员" : "普通用户"}
</span>
</div>
</div>
</div>
</Card>
</div>
</Layout>
);
};
export default UserSetting;

View File

@@ -3,6 +3,7 @@ import Mine from "@/pages/mine/index";
import WechatAccounts from "@/pages/wechat-accounts/list/index";
import WechatAccountDetail from "@/pages/wechat-accounts/detail/index";
import Recharge from "@/pages/mine/recharge/index";
import UserSetting from "@/pages/mine/userSet/index";
const routes = [
// 基础路由
@@ -32,6 +33,11 @@ const routes = [
element: <Recharge />,
auth: true,
},
{
path: "/settings",
element: <UserSetting />,
auth: true,
},
];
export default routes;