From ef70bfc71c3cef19eceb78b0996e60681c0a7176 Mon Sep 17 00:00:00 2001
From: czz <862977248@qq.com>
Date: Sat, 9 May 2026 15:50:51 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E5=81=9A=E4=B8=AA=E4=BA=BA?=
=?UTF-8?q?=E4=BF=A1=E6=81=AF=E9=A1=B5=E4=BA=A4=E4=BA=92?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
package-lock.json | 14 +-
package.json | 1 +
src/app.tsx | 3 +-
src/pages/profile/index.config.ts | 1 +
src/pages/profile/index.scss | 213 +++++++++++++++++++++++++++++-
src/pages/profile/index.tsx | 191 ++++++++++++++++++++++++---
tsconfig.json | 2 +-
7 files changed, 401 insertions(+), 24 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index c6d7d35..c1400e2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,7 @@
"@tarojs/webpack5-runner": "^4.0.0",
"@types/react": "^18.2.66",
"babel-preset-taro": "^4.0.0",
+ "miniprogram-api-typings": "^5.2.0",
"typescript": "^5.4.5"
}
},
@@ -10249,6 +10250,13 @@
"miniprogram-exparser": "latest"
}
},
+ "node_modules/j-component/node_modules/miniprogram-api-typings": {
+ "version": "3.12.3",
+ "resolved": "https://registry.npmmirror.com/miniprogram-api-typings/-/miniprogram-api-typings-3.12.3.tgz",
+ "integrity": "sha512-o7bOfrU28MEMCBWo83nXv0ROQSBFxJcfCl4f2wTYqah64ipC5RGqLJfvWJTWhlQt2ECVwspSzM8LgvnfMo7TEQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/jackspeak": {
"version": "2.3.6",
"resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-2.3.6.tgz",
@@ -11395,9 +11403,9 @@
}
},
"node_modules/miniprogram-api-typings": {
- "version": "3.12.3",
- "resolved": "https://registry.npmmirror.com/miniprogram-api-typings/-/miniprogram-api-typings-3.12.3.tgz",
- "integrity": "sha512-o7bOfrU28MEMCBWo83nXv0ROQSBFxJcfCl4f2wTYqah64ipC5RGqLJfvWJTWhlQt2ECVwspSzM8LgvnfMo7TEQ==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmmirror.com/miniprogram-api-typings/-/miniprogram-api-typings-5.2.0.tgz",
+ "integrity": "sha512-dkel1zG/eAfApabCtZnr9Y69+5z89GtWVPb6aCTvTJ0gu9mk+A0wCwdxlKWReFfXhcvhuonFrfYDwfSnSEkxsA==",
"dev": true,
"license": "MIT"
},
diff --git a/package.json b/package.json
index 1565931..aba516b 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"@tarojs/webpack5-runner": "^4.0.0",
"@types/react": "^18.2.66",
"babel-preset-taro": "^4.0.0",
+ "miniprogram-api-typings": "^5.2.0",
"typescript": "^5.4.5"
}
}
diff --git a/src/app.tsx b/src/app.tsx
index 9209af4..209a279 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -1,6 +1,7 @@
import "./app.scss";
+import type { ReactNode } from "react";
-function App(props) {
+function App(props: { children?: ReactNode }) {
const { children } = props;
return children ?? null;
}
diff --git a/src/pages/profile/index.config.ts b/src/pages/profile/index.config.ts
index 186f3e0..0ef25ba 100644
--- a/src/pages/profile/index.config.ts
+++ b/src/pages/profile/index.config.ts
@@ -1,3 +1,4 @@
export default definePageConfig({
+ navigationStyle: "custom",
navigationBarTitleText: "个人信息"
});
diff --git a/src/pages/profile/index.scss b/src/pages/profile/index.scss
index 719270f..d22046a 100644
--- a/src/pages/profile/index.scss
+++ b/src/pages/profile/index.scss
@@ -1,3 +1,214 @@
.profile-page {
- display: block;
+ min-height: 100vh;
+ box-sizing: border-box;
+ padding: calc(var(--profile-top-safe-height, 0px) + 22rpx) 0 72rpx;
+ background:
+ linear-gradient(180deg, rgba(39, 44, 60, 0.98) 0 150rpx, transparent 150rpx),
+ linear-gradient(180deg, #181d2a 0%, #171c29 100%);
+ color: var(--color-text-primary);
+}
+
+.profile-page__nav {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0 26rpx;
+}
+
+.profile-page__back {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ width: 112rpx;
+ height: 72rpx;
+}
+
+.profile-page__back-icon {
+ width: 24rpx;
+ height: 24rpx;
+ border-left: 4rpx solid var(--color-text-white);
+ border-bottom: 4rpx solid var(--color-text-white);
+ transform: rotate(45deg);
+}
+
+.profile-page__title {
+ color: var(--color-text-white);
+ font-size: 52rpx;
+ font-weight: 600;
+ letter-spacing: 2rpx;
+}
+
+.profile-page__save {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 126rpx;
+ height: 60rpx;
+ padding: 0 24rpx;
+ border-radius: 24rpx;
+ background: linear-gradient(135deg, var(--color-brand-start), var(--color-brand-end));
+ box-shadow: 0 12rpx 24rpx var(--color-brand-shadow-soft);
+}
+
+.profile-page__save-text {
+ color: var(--color-text-white);
+ font-size: 28rpx;
+}
+
+.profile-page__content {
+ padding: 70rpx 30rpx 0;
+}
+
+.profile-page__avatar-block {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.profile-page__avatar {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 154rpx;
+ height: 154rpx;
+ border-radius: 50%;
+ background:
+ radial-gradient(circle at 50% 34%, #f8fafc 0 20rpx, transparent 20rpx),
+ linear-gradient(180deg, #b8c1cf 0%, #7f8ba0 100%);
+ box-shadow: 0 16rpx 40rpx rgba(7, 10, 20, 0.26);
+ overflow: hidden;
+}
+
+.profile-page__avatar-image {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ background: linear-gradient(180deg, #dbe2ed 0%, #aeb8c7 100%);
+}
+
+.profile-page__avatar-placeholder {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ background:
+ radial-gradient(circle at 50% 34%, #f6f8fb 0 24rpx, transparent 25rpx),
+ linear-gradient(180deg, #d9dfea 0 58%, #b7c1d1 58% 100%);
+}
+
+.profile-page__avatar-head {
+ position: absolute;
+ top: 36rpx;
+ left: 50%;
+ width: 42rpx;
+ height: 42rpx;
+ margin-left: -21rpx;
+ border-radius: 50%;
+ background: #2d3650;
+}
+
+.profile-page__avatar-body {
+ position: absolute;
+ left: 50%;
+ bottom: 24rpx;
+ width: 90rpx;
+ height: 54rpx;
+ margin-left: -45rpx;
+ border-radius: 50rpx 50rpx 28rpx 28rpx;
+ background: #2d3650;
+}
+
+.profile-page__avatar-tip {
+ margin-top: 42rpx;
+ color: #08e0da;
+ font-size: 30rpx;
+}
+
+.profile-page__nickname-block {
+ margin: 110rpx 30rpx 0;
+ padding: 0 12rpx 18rpx;
+ border-top: 2rpx solid rgba(255, 255, 255, 0.28);
+ border-bottom: 2rpx solid rgba(255, 255, 255, 0.28);
+}
+
+.profile-page__nickname-input {
+ width: 100%;
+ height: 108rpx;
+ color: rgba(255, 255, 255, 0.64);
+ font-size: 34rpx;
+ line-height: 108rpx;
+ text-align: center;
+}
+
+.profile-page__nickname-placeholder {
+ color: rgba(255, 255, 255, 0.28);
+}
+
+.profile-page__info-card {
+ margin-top: 92rpx;
+ padding: 18rpx 36rpx;
+ border-radius: 30rpx;
+ background: rgba(41, 46, 61, 0.96);
+ box-shadow:
+ inset 0 0 0 2rpx rgba(255, 255, 255, 0.03),
+ 0 16rpx 34rpx rgba(5, 9, 18, 0.18);
+}
+
+.profile-page__info-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ min-height: 154rpx;
+ gap: 20rpx;
+ border-bottom: 2rpx solid rgba(255, 255, 255, 0.04);
+}
+
+.profile-page__info-row--last {
+ border-bottom: 0;
+}
+
+.profile-page__info-main {
+ display: flex;
+ align-items: baseline;
+ gap: 16rpx;
+ min-width: 0;
+}
+
+.profile-page__info-label {
+ color: var(--color-text-white);
+ font-size: 34rpx;
+}
+
+.profile-page__info-value {
+ color: rgba(255, 255, 255, 0.42);
+ font-size: 28rpx;
+}
+
+.profile-page__info-value--muted {
+ color: rgba(255, 255, 255, 0.26);
+}
+
+.profile-page__info-action {
+ display: flex;
+ align-items: center;
+ gap: 18rpx;
+ flex-shrink: 0;
+}
+
+.profile-page__info-action-text {
+ color: #08e0da;
+ font-size: 28rpx;
+}
+
+.profile-page__info-action-text--muted {
+ color: rgba(255, 255, 255, 0.42);
+}
+
+.profile-page__info-action-text--bound {
+ color: #08e0da;
+}
+
+.profile-page__info-arrow {
+ color: rgba(255, 255, 255, 0.72);
+ font-size: 28rpx;
}
diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx
index cdc847e..bc54c0e 100644
--- a/src/pages/profile/index.tsx
+++ b/src/pages/profile/index.tsx
@@ -1,26 +1,181 @@
-import SecondaryPage, { type SecondaryPageSection } from "../../components/secondary-page";
+import { Input, Text, View } from "@tarojs/components";
+import Taro from "@tarojs/taro";
+import type { CSSProperties } from "react";
+import { useEffect, useState } from "react";
import "./index.scss";
-const sections: SecondaryPageSection[] = [
- {
- title: "资料编辑",
- items: [
- { label: "头像", value: "支持后续替换" },
- { label: "昵称", value: "张天爱" },
- { label: "手机号", value: "135****2598" },
- { label: "修改密码", value: "待接入" }
- ]
+type ProfileState = {
+ avatar: string;
+ nickname: string;
+ phone: string;
+ email: string;
+ wechatBound: boolean;
+};
+
+type InfoAction = "replacePhone" | "replaceEmail" | "bindWechat";
+
+const defaultProfile: ProfileState = {
+ avatar: "",
+ nickname: "玛利亚",
+ phone: "139****0753",
+ email: "",
+ wechatBound: false
+};
+
+function getActionToast(action: InfoAction) {
+ switch (action) {
+ case "replacePhone":
+ return "手机号更换功能待接入";
+ case "replaceEmail":
+ return "邮箱更换功能待接入";
+ case "bindWechat":
+ return "微信绑定功能待接入";
+ default:
+ return "功能待接入";
}
-];
+}
export default function ProfilePage() {
+ const [profile, setProfile] = useState(defaultProfile);
+ const [draftNickname, setDraftNickname] = useState(defaultProfile.nickname);
+ const [topSafeHeight, setTopSafeHeight] = useState(0);
+
+ useEffect(() => {
+ const windowInfo = typeof Taro.getWindowInfo === "function" ? Taro.getWindowInfo() : Taro.getSystemInfoSync();
+ const menuButtonRect =
+ typeof Taro.getMenuButtonBoundingClientRect === "function" ? Taro.getMenuButtonBoundingClientRect() : null;
+ const safeTop = menuButtonRect?.bottom || windowInfo.statusBarHeight || 0;
+
+ setTopSafeHeight(safeTop);
+ }, []);
+
+ const pageStyle = {
+ "--profile-top-safe-height": `${topSafeHeight}px`
+ } as CSSProperties;
+
+ const showToast = (title: string, icon: "none" | "success" = "none") => {
+ Taro.showToast({
+ title,
+ icon
+ });
+ };
+
+ const handleBack = () => {
+ const pages = Taro.getCurrentPages();
+
+ if (pages.length > 1) {
+ Taro.navigateBack({ delta: 1 });
+ return;
+ }
+
+ Taro.redirectTo({ url: "/pages/mine/index" });
+ };
+
+ const handleSave = () => {
+ const nickname = draftNickname.trim() || defaultProfile.nickname;
+
+ setProfile((current) => ({
+ ...current,
+ nickname
+ }));
+ setDraftNickname(nickname);
+ showToast("保存成功", "success");
+ };
+
+ const handleAvatarClick = () => {
+ showToast("头像更换功能待接入");
+ };
+
+ const handleInfoAction = (action: InfoAction) => {
+ showToast(getActionToast(action));
+ };
+
return (
-
+
+
+
+
+
+
+ 个人信息
+
+
+ 保存
+
+
+
+
+
+
+ {profile.avatar ? (
+
+ ) : (
+
+
+
+
+ )}
+
+
+ 点击更换头像
+
+
+
+ setDraftNickname(event.detail.value)}
+ />
+
+
+
+ handleInfoAction("replacePhone")}>
+
+ 手机号
+ ({profile.phone})
+
+
+
+ 更换
+ >
+
+
+
+ handleInfoAction("replaceEmail")}>
+
+ 邮箱
+
+ {profile.email || "暂未填写"}
+
+
+
+
+ 更换
+ >
+
+
+
+ handleInfoAction("bindWechat")}>
+
+ 微信
+
+
+
+
+ {profile.wechatBound ? "已绑定" : "去绑定"}
+
+ >
+
+
+
+
+
);
}
diff --git a/tsconfig.json b/tsconfig.json
index effe83c..7e77ef4 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -18,7 +18,7 @@
},
"types": [
"@tarojs/taro",
- "wechat-miniprogram"
+ "miniprogram-api-typings"
]
},
"include": [