FEAT => 本次更新项目为:

设置页面构建完成
This commit is contained in:
超级老白兔
2025-07-30 16:58:29 +08:00
parent e3ccf61fd2
commit 2577fd81eb
2 changed files with 321 additions and 98 deletions

View File

@@ -1,30 +1,39 @@
.save-buttons { .save-buttons {
padding: 12px; padding: 12px;
background: #fff;
} }
.setting-page { .setting-page {
padding: 12px; padding: 12px;
.user-card { .user-card {
margin-bottom: 12px; margin-bottom: 16px;
border-radius: 12px; border-radius: 16px;
overflow: hidden; overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
background: linear-gradient(
135deg,
var(--primary-color) 0%,
var(--primary-color-dark) 100%
);
position: relative;
.user-info { .user-info {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 16px; padding: 20px;
gap: 16px; gap: 16px;
position: relative;
z-index: 1;
.avatar { .avatar {
width: 60px; width: 70px;
height: 60px; height: 70px;
border-radius: 30px; border-radius: 35px;
overflow: hidden; overflow: hidden;
flex-shrink: 0; flex-shrink: 0;
background: #f0f0f0; background: rgba(255, 255, 255, 0.2);
border: 2px solid #e0e0e0; border: 3px solid rgba(255, 255, 255, 0.3);
position: relative;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
img { img {
width: 100%; width: 100%;
@@ -35,13 +44,18 @@
.avatar-placeholder { .avatar-placeholder {
width: 100%; width: 100%;
height: 100%; height: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: linear-gradient(
135deg,
var(--primary-color) 0%,
var(--primary-color-dark) 100%
);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: white; color: white;
font-size: 24px; font-size: 28px;
font-weight: bold; font-weight: bold;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
} }
} }
@@ -50,19 +64,20 @@
min-width: 0; min-width: 0;
.username { .username {
font-size: 18px; font-size: 20px;
font-weight: 600; font-weight: 700;
color: #333; color: white;
margin-bottom: 4px; margin-bottom: 6px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
} }
.account { .account {
font-size: 14px; font-size: 14px;
color: #666; color: rgba(255, 255, 255, 0.8);
margin-bottom: 4px; margin-bottom: 6px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@@ -70,99 +85,205 @@
.role { .role {
font-size: 12px; font-size: 12px;
color: #999; color: rgba(255, 255, 255, 0.9);
background: #f0f0f0; background: rgba(255, 255, 255, 0.2);
padding: 2px 8px; padding: 4px 12px;
border-radius: 10px; border-radius: 12px;
display: inline-block; display: inline-block;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
} }
} }
.user-actions {
flex-shrink: 0;
}
} }
} }
.setting-group { .setting-group {
margin-bottom: 12px; margin-bottom: 16px;
border-radius: 12px; border-radius: 16px;
overflow: hidden; overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
background: white;
border: 1px solid rgba(0, 0, 0, 0.05);
.group-title { .group-title {
padding: 12px 16px 8px; padding: 16px 20px 12px;
font-size: 14px; font-size: 15px;
font-weight: 600; font-weight: 700;
color: #666; color: #333;
background: #fafafa; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-bottom: 1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
display: flex;
align-items: center;
gap: 8px;
.group-icon {
font-size: 16px;
}
} }
:global(.adm-list) { .setting-list {
--border-inner: solid 1px #f0f0f0; :global(.adm-list) {
--border-top: none; --border-inner: solid 1px #f0f0f0;
--border-bottom: none; --border-top: none;
--adm-font-size-main: 16px; --border-bottom: none;
--adm-color-text: #333; --adm-font-size-main: 16px;
--adm-color-text-secondary: #666; --adm-color-text: #333;
--adm-color-text-secondary: #666;
.adm-list-item { .adm-list-item {
padding: 16px; padding: 16px 20px;
min-height: 56px; min-height: 64px;
transition: all 0.2s ease;
position: relative;
.adm-list-item-content { &:hover {
padding: 0; background: #f8f9fa;
} transform: translateX(4px);
.adm-list-item-content-prefix {
margin-right: 12px;
font-size: 20px;
color: var(--primary-color);
}
.adm-list-item-content-main {
flex: 1;
min-width: 0;
.adm-list-item-content-main-title {
font-size: 16px;
font-weight: 500;
color: #333;
margin-bottom: 4px;
} }
.adm-list-item-content-main-description { &:active {
font-size: 14px; background: #e9ecef;
color: #666; transform: scale(0.98);
line-height: 1.4;
} }
}
.adm-list-item-content-extra { .adm-list-item-content {
margin-left: 8px; padding: 0;
} }
&:last-child { .adm-list-item-content-prefix {
border-bottom: none; margin-right: 16px;
} }
&:active { .adm-list-item-content-main {
background-color: #f5f5f5; flex: 1;
min-width: 0;
.adm-list-item-content-main-title {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 4px;
}
.adm-list-item-content-main-description {
font-size: 14px;
color: #666;
line-height: 1.4;
}
}
.adm-list-item-content-extra {
margin-left: 8px;
}
&:last-child {
border-bottom: none;
}
} }
} }
} }
} }
.setting-icon {
width: 40px;
height: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
background: rgba(24, 144, 255, 0.1);
color: var(--primary-color);
transition: all 0.2s ease;
&:hover {
transform: scale(1.1);
background: rgba(24, 144, 255, 0.2);
}
}
.setting-title {
display: flex;
align-items: center;
gap: 8px;
}
.setting-badge {
background: #ff4d4f;
color: white;
font-size: 10px;
padding: 2px 6px;
border-radius: 8px;
font-weight: 500;
}
.setting-item {
transition: all 0.2s ease;
}
.version-info { .version-info {
text-align: center; .version-card {
padding: 24px 16px; background: white;
color: #999; border-radius: 16px;
font-size: 12px; padding: 24px;
line-height: 1.6; margin-bottom: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
display: flex;
align-items: center;
gap: 16px;
span { .app-logo {
display: block; flex-shrink: 0;
margin-bottom: 4px; width: 60px;
height: 60px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
&:last-child { .version-details {
margin-bottom: 0; flex: 1;
text-align: left;
.app-name {
font-size: 18px;
font-weight: 700;
color: #333;
margin-bottom: 4px;
}
.version-text {
font-size: 14px;
color: #666;
margin-bottom: 2px;
}
.build-info {
font-size: 12px;
color: #999;
}
}
}
.copyright {
color: #999;
font-size: 12px;
line-height: 1.6;
text-align: center;
span {
display: block;
margin-bottom: 4px;
&:last-child {
margin-bottom: 0;
color: #ccc;
}
} }
} }
} }

View File

@@ -7,6 +7,10 @@ import {
InfoCircleOutlined, InfoCircleOutlined,
LogoutOutlined, LogoutOutlined,
SettingOutlined, SettingOutlined,
BellOutlined,
LockOutlined,
HeartOutlined,
StarOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import Layout from "@/components/Layout/Layout"; import Layout from "@/components/Layout/Layout";
import { useUserStore } from "@/store/module/user"; import { useUserStore } from "@/store/module/user";
@@ -22,6 +26,8 @@ interface SettingItem {
value?: boolean; value?: boolean;
path?: string; path?: string;
onClick?: () => void; onClick?: () => void;
badge?: string;
color?: string;
} }
const Setting: React.FC = () => { const Setting: React.FC = () => {
@@ -29,6 +35,12 @@ const Setting: React.FC = () => {
const { user, logout } = useUserStore(); const { user, logout } = useUserStore();
const { settings, updateSetting } = useSettingsStore(); const { settings, updateSetting } = useSettingsStore();
const [showLogoutDialog, setShowLogoutDialog] = useState(false); const [showLogoutDialog, setShowLogoutDialog] = useState(false);
const [avatarError, setAvatarError] = useState(false);
// 处理头像加载错误
const handleAvatarError = () => {
setAvatarError(true);
};
// 处理开关变化 // 处理开关变化
const handleSwitchChange = (key: keyof typeof settings, value: boolean) => { const handleSwitchChange = (key: keyof typeof settings, value: boolean) => {
@@ -78,6 +90,7 @@ const Setting: React.FC = () => {
icon: <UserOutlined />, icon: <UserOutlined />,
type: "navigate", type: "navigate",
path: "/userSet", path: "/userSet",
color: "var(--primary-color)",
}, },
{ {
id: "security", id: "security",
@@ -86,12 +99,22 @@ const Setting: React.FC = () => {
icon: <SafetyOutlined />, icon: <SafetyOutlined />,
type: "navigate", type: "navigate",
path: "/security", path: "/security",
color: "var(--primary-color)",
}, },
], ],
}, },
{ {
title: "其他", title: "应用设置",
items: [ items: [
{
id: "privacy",
title: "隐私保护",
description: "数据隐私、权限管理",
icon: <LockOutlined />,
type: "navigate",
path: "/privacy",
color: "var(--primary-color)",
},
{ {
id: "clearCache", id: "clearCache",
title: "清除缓存", title: "清除缓存",
@@ -99,14 +122,32 @@ const Setting: React.FC = () => {
icon: <SettingOutlined />, icon: <SettingOutlined />,
type: "button", type: "button",
onClick: handleClearCache, onClick: handleClearCache,
color: "var(--primary-color)",
badge: "2.3MB",
},
],
},
{
title: "其他",
items: [
{
id: "feedback",
title: "意见反馈",
description: "问题反馈、功能建议",
icon: <HeartOutlined />,
type: "navigate",
path: "/feedback",
color: "var(--primary-color)",
}, },
{ {
id: "privacy", id: "rate",
title: "用户隐私协议", title: "给我们评分",
description: "查看用户隐私协议和数据处理说明", description: "在应用商店给我们评分",
icon: <InfoCircleOutlined />, icon: <StarOutlined />,
type: "navigate", type: "button",
path: "/privacy", onClick: () =>
Toast.show({ content: "感谢您的支持!", position: "top" }),
color: "var(--primary-color)",
}, },
{ {
id: "about", id: "about",
@@ -115,6 +156,7 @@ const Setting: React.FC = () => {
icon: <InfoCircleOutlined />, icon: <InfoCircleOutlined />,
type: "navigate", type: "navigate",
path: "/about", path: "/about",
color: "var(--primary-color)",
}, },
{ {
id: "logout", id: "logout",
@@ -123,6 +165,7 @@ const Setting: React.FC = () => {
icon: <LogoutOutlined />, icon: <LogoutOutlined />,
type: "button", type: "button",
onClick: () => setShowLogoutDialog(true), onClick: () => setShowLogoutDialog(true),
color: "#ff4d4f",
}, },
], ],
}, },
@@ -143,16 +186,42 @@ const Setting: React.FC = () => {
return ( return (
<List.Item <List.Item
key={item.id} key={item.id}
prefix={item.icon} prefix={
title={item.title} <div
className={style["setting-icon"]}
style={{
color: item.color || "var(--primary-color)",
background: `${item.color || "var(--primary-color)"}15`,
}}
>
{item.icon}
</div>
}
title={
<div className={style["setting-title"]}>
{item.title}
{item.badge && (
<span className={style["setting-badge"]}>{item.badge}</span>
)}
</div>
}
description={item.description} description={item.description}
extra={ extra={
item.type === "switch" ? ( item.type === "switch" ? (
<Switch checked={item.value} onChange={() => item.onClick?.()} /> <Switch
checked={item.value}
onChange={() => item.onClick?.()}
style={
{
"--checked-color": item.color || "var(--primary-color)",
} as React.CSSProperties
}
/>
) : null ) : null
} }
onClick={handleClick} onClick={handleClick}
arrow={item.type === "navigate"} arrow={item.type === "navigate"}
className={style["setting-item"]}
/> />
); );
}; };
@@ -172,8 +241,8 @@ const Setting: React.FC = () => {
<Card className={style["user-card"]}> <Card className={style["user-card"]}>
<div className={style["user-info"]}> <div className={style["user-info"]}>
<div className={style["avatar"]}> <div className={style["avatar"]}>
{user?.avatar ? ( {user?.avatar && !avatarError ? (
<img src={user.avatar} alt="头像" /> <img src={user.avatar} alt="头像" onError={handleAvatarError} />
) : ( ) : (
<div className={style["avatar-placeholder"]}> <div className={style["avatar-placeholder"]}>
{user?.username?.charAt(0) || "用"} {user?.username?.charAt(0) || "用"}
@@ -191,21 +260,54 @@ const Setting: React.FC = () => {
{user?.isAdmin === 1 ? "管理员" : "普通用户"} {user?.isAdmin === 1 ? "管理员" : "普通用户"}
</div> </div>
</div> </div>
<div className={style["user-actions"]}>
<Button
size="small"
fill="outline"
onClick={() => navigate("/userSet")}
style={{
color: "#fff",
borderColor: "#fff",
fontSize: "12px",
padding: "4px 8px",
height: "auto",
}}
>
</Button>
</div>
</div> </div>
</Card> </Card>
{/* 设置列表 */} {/* 设置列表 */}
{settingGroups.map((group, groupIndex) => ( {settingGroups.map((group, groupIndex) => (
<Card key={groupIndex} className={style["setting-group"]}> <Card key={groupIndex} className={style["setting-group"]}>
<div className={style["group-title"]}>{group.title}</div> <div className={style["group-title"]}>
<List>{group.items.map(renderSettingItem)}</List> <span className={style["group-icon"]}></span>
{group.title}
</div>
<List className={style["setting-list"]}>
{group.items.map(renderSettingItem)}
</List>
</Card> </Card>
))} ))}
{/* 版本信息 */} {/* 版本信息 */}
<div className={style["version-info"]}> <div className={style["version-info"]}>
<span> 1.0.0</span> <div className={style["version-card"]}>
<span>© 2024 </span> <div className={style["app-logo"]}>
<img src="/public/logo.png" alt="" />
</div>
<div className={style["version-details"]}>
<div className={style["app-name"]}></div>
<div className={style["version-text"]}> 3.0.0</div>
<div className={style["build-info"]}>Build 2025-7-30</div>
</div>
</div>
<div className={style["copyright"]}>
<span>© 2024 </span>
<span></span>
</div>
</div> </div>
</div> </div>