feat: 本次提交更新内容如下
用户信息修改完成
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
115
nkebao/src/pages/mine/userSet/index.module.scss
Normal file
115
nkebao/src/pages/mine/userSet/index.module.scss
Normal 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;
|
||||
}
|
||||
113
nkebao/src/pages/mine/userSet/index.tsx
Normal file
113
nkebao/src/pages/mine/userSet/index.tsx
Normal 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;
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user