From 6ff9070eca1c6a984968987217c0fff9987ce0a9 Mon Sep 17 00:00:00 2001
From: czz <862977248@qq.com>
Date: Fri, 8 May 2026 11:22:59 +0800
Subject: [PATCH] feat: add mine page and secondary pages
---
.../2026-05-08-mine-page-implementation.md | 84 ++++
src/app.config.ts | 14 +-
src/components/secondary-page/index.scss | 128 ++++++
src/components/secondary-page/index.tsx | 56 +++
src/pages/devices/index.config.ts | 3 +
src/pages/devices/index.scss | 3 +
src/pages/devices/index.tsx | 29 ++
src/pages/feedback/index.config.ts | 3 +
src/pages/feedback/index.scss | 3 +
src/pages/feedback/index.tsx | 28 ++
src/pages/follow-us/index.config.ts | 3 +
src/pages/follow-us/index.scss | 3 +
src/pages/follow-us/index.tsx | 25 +
src/pages/index/index.tsx | 6 +
src/pages/mine/index.config.ts | 4 +
src/pages/mine/index.scss | 429 ++++++++++++++++++
src/pages/mine/index.tsx | 180 ++++++++
src/pages/profile/index.config.ts | 3 +
src/pages/profile/index.scss | 3 +
src/pages/profile/index.tsx | 26 ++
src/pages/repair/index.config.ts | 3 +
src/pages/repair/index.scss | 3 +
src/pages/repair/index.tsx | 28 ++
src/pages/settings/index.config.ts | 3 +
src/pages/settings/index.scss | 3 +
src/pages/settings/index.tsx | 31 ++
src/pages/support/index.config.ts | 3 +
src/pages/support/index.scss | 3 +
src/pages/support/index.tsx | 24 +
src/pages/videos/index.config.ts | 3 +
src/pages/videos/index.scss | 3 +
src/pages/videos/index.tsx | 24 +
32 files changed, 1163 insertions(+), 1 deletion(-)
create mode 100644 docs/superpowers/plans/2026-05-08-mine-page-implementation.md
create mode 100644 src/components/secondary-page/index.scss
create mode 100644 src/components/secondary-page/index.tsx
create mode 100644 src/pages/devices/index.config.ts
create mode 100644 src/pages/devices/index.scss
create mode 100644 src/pages/devices/index.tsx
create mode 100644 src/pages/feedback/index.config.ts
create mode 100644 src/pages/feedback/index.scss
create mode 100644 src/pages/feedback/index.tsx
create mode 100644 src/pages/follow-us/index.config.ts
create mode 100644 src/pages/follow-us/index.scss
create mode 100644 src/pages/follow-us/index.tsx
create mode 100644 src/pages/mine/index.config.ts
create mode 100644 src/pages/mine/index.scss
create mode 100644 src/pages/mine/index.tsx
create mode 100644 src/pages/profile/index.config.ts
create mode 100644 src/pages/profile/index.scss
create mode 100644 src/pages/profile/index.tsx
create mode 100644 src/pages/repair/index.config.ts
create mode 100644 src/pages/repair/index.scss
create mode 100644 src/pages/repair/index.tsx
create mode 100644 src/pages/settings/index.config.ts
create mode 100644 src/pages/settings/index.scss
create mode 100644 src/pages/settings/index.tsx
create mode 100644 src/pages/support/index.config.ts
create mode 100644 src/pages/support/index.scss
create mode 100644 src/pages/support/index.tsx
create mode 100644 src/pages/videos/index.config.ts
create mode 100644 src/pages/videos/index.scss
create mode 100644 src/pages/videos/index.tsx
diff --git a/docs/superpowers/plans/2026-05-08-mine-page-implementation.md b/docs/superpowers/plans/2026-05-08-mine-page-implementation.md
new file mode 100644
index 0000000..1856301
--- /dev/null
+++ b/docs/superpowers/plans/2026-05-08-mine-page-implementation.md
@@ -0,0 +1,84 @@
+# Mine Page Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** 为小程序新增“我的”主页面和其二级页面骨架,完成页面注册、页面跳转和深色视觉落地。
+
+**Architecture:** 保持当前项目的轻量结构,直接在 `src/pages/` 下新增页面目录,不引入状态管理或新 UI 框架。主页面使用本地 mock 数据渲染,二级页面复用统一的深色卡片布局和轻量占位文案,验证以 `npm run build:weapp` 为主。
+
+**Tech Stack:** Taro 4、React 18、TypeScript、SCSS
+
+---
+
+### Task 1: 注册页面与整理导航入口
+
+**Files:**
+- Modify: `src/app.config.ts`
+- Modify: `src/pages/index/index.tsx`
+
+- [ ] 在 `src/app.config.ts` 中注册 `mine` 主页面及 `profile`、`settings`、`support`、`devices`、`repair`、`feedback`、`videos`、`follow-us` 二级页面
+- [ ] 将首页底部导航中的“我的”入口改为跳转到 `pages/mine/index`
+- [ ] 保留首页其余入口当前占位逻辑,不扩展其他 Tab 页面
+
+### Task 2: 实现“我的”主页面
+
+**Files:**
+- Create: `src/pages/mine/index.config.ts`
+- Create: `src/pages/mine/index.tsx`
+- Create: `src/pages/mine/index.scss`
+
+- [ ] 新建“我的”主页面配置,设置页面标题
+- [ ] 在 `index.tsx` 中定义本地 mock 用户数据、功能列表数据和页面跳转逻辑
+- [ ] 实现顶部用户信息卡、右侧快捷入口、功能列表和版本检查提示
+- [ ] 保持代码对新手友好,复杂映射处仅补充必要注释
+
+### Task 3: 实现二级页面骨架
+
+**Files:**
+- Create: `src/pages/profile/index.config.ts`
+- Create: `src/pages/profile/index.tsx`
+- Create: `src/pages/profile/index.scss`
+- Create: `src/pages/settings/index.config.ts`
+- Create: `src/pages/settings/index.tsx`
+- Create: `src/pages/settings/index.scss`
+- Create: `src/pages/support/index.config.ts`
+- Create: `src/pages/support/index.tsx`
+- Create: `src/pages/support/index.scss`
+- Create: `src/pages/devices/index.config.ts`
+- Create: `src/pages/devices/index.tsx`
+- Create: `src/pages/devices/index.scss`
+- Create: `src/pages/repair/index.config.ts`
+- Create: `src/pages/repair/index.tsx`
+- Create: `src/pages/repair/index.scss`
+- Create: `src/pages/feedback/index.config.ts`
+- Create: `src/pages/feedback/index.tsx`
+- Create: `src/pages/feedback/index.scss`
+- Create: `src/pages/videos/index.config.ts`
+- Create: `src/pages/videos/index.tsx`
+- Create: `src/pages/videos/index.scss`
+- Create: `src/pages/follow-us/index.config.ts`
+- Create: `src/pages/follow-us/index.tsx`
+- Create: `src/pages/follow-us/index.scss`
+
+- [ ] 为每个二级页面补齐标题、卡片布局和占位内容
+- [ ] 保持二级页面视觉与主页面一致,但布局更简洁
+- [ ] 确保所有从“我的”页发起的跳转都能进入对应页面
+
+### Task 4: 样式收口与验证
+
+**Files:**
+- Modify: `src/app.scss`
+- Modify: `src/pages/index/index.tsx`
+- Modify: `src/pages/mine/index.scss`
+- Modify: `src/pages/profile/index.scss`
+- Modify: `src/pages/settings/index.scss`
+- Modify: `src/pages/support/index.scss`
+- Modify: `src/pages/devices/index.scss`
+- Modify: `src/pages/repair/index.scss`
+- Modify: `src/pages/feedback/index.scss`
+- Modify: `src/pages/videos/index.scss`
+- Modify: `src/pages/follow-us/index.scss`
+
+- [ ] 如有必要,补充少量全局基础样式,避免和现有页面冲突
+- [ ] 运行 `npm run build:weapp`
+- [ ] 检查构建输出,确认页面注册、TS 代码和 SCSS 都能通过编译
diff --git a/src/app.config.ts b/src/app.config.ts
index 8fb4fc0..735d4a8 100644
--- a/src/app.config.ts
+++ b/src/app.config.ts
@@ -1,5 +1,17 @@
export default defineAppConfig({
- pages: ["pages/index/index", "pages/message/index"],
+ pages: [
+ "pages/index/index",
+ "pages/message/index",
+ "pages/mine/index",
+ "pages/profile/index",
+ "pages/settings/index",
+ "pages/support/index",
+ "pages/devices/index",
+ "pages/repair/index",
+ "pages/feedback/index",
+ "pages/videos/index",
+ "pages/follow-us/index"
+ ],
window: {
navigationBarTitleText: "新手小程序",
navigationBarBackgroundColor: "#1AAD19",
diff --git a/src/components/secondary-page/index.scss b/src/components/secondary-page/index.scss
new file mode 100644
index 0000000..fd5b297
--- /dev/null
+++ b/src/components/secondary-page/index.scss
@@ -0,0 +1,128 @@
+.secondary-page {
+ position: relative;
+ min-height: 100vh;
+ padding: 32rpx 24rpx 48rpx;
+ box-sizing: border-box;
+ background: linear-gradient(180deg, #1e2432 0%, #171d29 100%);
+ overflow: hidden;
+}
+
+.secondary-page__halo {
+ position: absolute;
+ border-radius: 50%;
+ pointer-events: none;
+}
+
+.secondary-page__halo--large {
+ top: -80rpx;
+ right: -44rpx;
+ width: 320rpx;
+ height: 320rpx;
+ background:
+ radial-gradient(circle, rgba(54, 228, 170, 0.08) 0 24%, transparent 25% 44%, rgba(109, 121, 154, 0.16) 45% 62%, transparent 63%),
+ radial-gradient(circle at center, rgba(255, 255, 255, 0.06), transparent 72%);
+}
+
+.secondary-page__halo--small {
+ top: 180rpx;
+ right: 90rpx;
+ width: 160rpx;
+ height: 120rpx;
+ background: radial-gradient(circle at center, rgba(255, 255, 255, 0.05), transparent 68%);
+}
+
+.secondary-page__hero {
+ position: relative;
+ z-index: 1;
+ margin-bottom: 28rpx;
+ padding: 32rpx 30rpx;
+ border-radius: 28rpx;
+ background: rgba(39, 46, 64, 0.95);
+ box-shadow: inset 0 0 0 2rpx rgba(255, 255, 255, 0.03);
+}
+
+.secondary-page__eyebrow {
+ display: block;
+ margin-bottom: 12rpx;
+ color: #40deb4;
+ font-size: 22rpx;
+ letter-spacing: 4rpx;
+}
+
+.secondary-page__title {
+ display: block;
+ color: #f6f8fb;
+ font-size: 42rpx;
+ font-weight: 600;
+}
+
+.secondary-page__description {
+ display: block;
+ margin-top: 14rpx;
+ color: #9aa5bb;
+ font-size: 24rpx;
+ line-height: 1.7;
+}
+
+.secondary-page__content {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 20rpx;
+}
+
+.secondary-page__card {
+ padding: 28rpx;
+ border-radius: 24rpx;
+ background: rgba(39, 46, 64, 0.94);
+ box-shadow: inset 0 0 0 2rpx rgba(255, 255, 255, 0.03);
+}
+
+.secondary-page__card-title {
+ display: block;
+ margin-bottom: 20rpx;
+ color: #eef3fb;
+ font-size: 28rpx;
+ font-weight: 600;
+}
+
+.secondary-page__list {
+ display: flex;
+ flex-direction: column;
+ gap: 2rpx;
+}
+
+.secondary-page__list-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 20rpx 0;
+ border-bottom: 1rpx solid rgba(255, 255, 255, 0.06);
+}
+
+.secondary-page__list-item:last-child {
+ padding-bottom: 0;
+ border-bottom: 0;
+}
+
+.secondary-page__list-label {
+ color: #edf1f7;
+ font-size: 26rpx;
+}
+
+.secondary-page__list-value {
+ color: #7c879d;
+ font-size: 22rpx;
+}
+
+.secondary-page__footer-tip {
+ position: relative;
+ z-index: 1;
+ display: block;
+ margin-top: 22rpx;
+ color: #7d88a1;
+ font-size: 22rpx;
+ line-height: 1.7;
+ text-align: center;
+}
diff --git a/src/components/secondary-page/index.tsx b/src/components/secondary-page/index.tsx
new file mode 100644
index 0000000..4ee6118
--- /dev/null
+++ b/src/components/secondary-page/index.tsx
@@ -0,0 +1,56 @@
+import { Text, View } from "@tarojs/components";
+import "./index.scss";
+
+export type SecondaryPageItem = {
+ label: string;
+ value?: string;
+};
+
+export type SecondaryPageSection = {
+ title: string;
+ items: SecondaryPageItem[];
+};
+
+type SecondaryPageProps = {
+ eyebrow: string;
+ title: string;
+ description: string;
+ sections: SecondaryPageSection[];
+ footerTip?: string;
+};
+
+export default function SecondaryPage(props: SecondaryPageProps) {
+ const { eyebrow, title, description, sections, footerTip } = props;
+
+ return (
+
+
+
+
+
+ {eyebrow}
+ {title}
+ {description}
+
+
+
+ {sections.map((section) => (
+
+ {section.title}
+
+
+ {section.items.map((item) => (
+
+ {item.label}
+ {item.value || "待接入"}
+
+ ))}
+
+
+ ))}
+
+
+ {footerTip ? {footerTip} : null}
+
+ );
+}
diff --git a/src/pages/devices/index.config.ts b/src/pages/devices/index.config.ts
new file mode 100644
index 0000000..0e36edb
--- /dev/null
+++ b/src/pages/devices/index.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+ navigationBarTitleText: "我的设备"
+});
diff --git a/src/pages/devices/index.scss b/src/pages/devices/index.scss
new file mode 100644
index 0000000..2971b8b
--- /dev/null
+++ b/src/pages/devices/index.scss
@@ -0,0 +1,3 @@
+.devices-page {
+ display: block;
+}
diff --git a/src/pages/devices/index.tsx b/src/pages/devices/index.tsx
new file mode 100644
index 0000000..4126261
--- /dev/null
+++ b/src/pages/devices/index.tsx
@@ -0,0 +1,29 @@
+import SecondaryPage, { type SecondaryPageSection } from "../../components/secondary-page";
+import "./index.scss";
+
+const sections: SecondaryPageSection[] = [
+ {
+ title: "设备概览",
+ items: [
+ { label: "已绑定设备", value: "0 台" },
+ { label: "设备共享管理", value: "待接入" },
+ { label: "添加设备", value: "可复用首页绑定能力" }
+ ]
+ },
+ {
+ title: "当前状态",
+ items: [{ label: "设备列表", value: "暂无已绑定设备" }]
+ }
+];
+
+export default function DevicesPage() {
+ return (
+
+ );
+}
diff --git a/src/pages/feedback/index.config.ts b/src/pages/feedback/index.config.ts
new file mode 100644
index 0000000..b4f3e1f
--- /dev/null
+++ b/src/pages/feedback/index.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+ navigationBarTitleText: "问题反馈"
+});
diff --git a/src/pages/feedback/index.scss b/src/pages/feedback/index.scss
new file mode 100644
index 0000000..065f769
--- /dev/null
+++ b/src/pages/feedback/index.scss
@@ -0,0 +1,3 @@
+.feedback-page {
+ display: block;
+}
diff --git a/src/pages/feedback/index.tsx b/src/pages/feedback/index.tsx
new file mode 100644
index 0000000..cead7e3
--- /dev/null
+++ b/src/pages/feedback/index.tsx
@@ -0,0 +1,28 @@
+import SecondaryPage, { type SecondaryPageSection } from "../../components/secondary-page";
+import "./index.scss";
+
+const sections: SecondaryPageSection[] = [
+ {
+ title: "反馈入口",
+ items: [
+ { label: "提交问题" },
+ { label: "提交建议" },
+ { label: "上传截图", value: "待接入上传能力" }
+ ]
+ },
+ {
+ title: "记录查询",
+ items: [{ label: "反馈记录", value: "后续展示处理进度" }]
+ }
+];
+
+export default function FeedbackPage() {
+ return (
+
+ );
+}
diff --git a/src/pages/follow-us/index.config.ts b/src/pages/follow-us/index.config.ts
new file mode 100644
index 0000000..e8bd5eb
--- /dev/null
+++ b/src/pages/follow-us/index.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+ navigationBarTitleText: "关注我们"
+});
diff --git a/src/pages/follow-us/index.scss b/src/pages/follow-us/index.scss
new file mode 100644
index 0000000..d95b565
--- /dev/null
+++ b/src/pages/follow-us/index.scss
@@ -0,0 +1,3 @@
+.follow-us-page {
+ display: block;
+}
diff --git a/src/pages/follow-us/index.tsx b/src/pages/follow-us/index.tsx
new file mode 100644
index 0000000..fab3c62
--- /dev/null
+++ b/src/pages/follow-us/index.tsx
@@ -0,0 +1,25 @@
+import SecondaryPage, { type SecondaryPageSection } from "../../components/secondary-page";
+import "./index.scss";
+
+const sections: SecondaryPageSection[] = [
+ {
+ title: "官方入口",
+ items: [
+ { label: "官方公众号", value: "待补充二维码" },
+ { label: "官方网站", value: "待补充地址" },
+ { label: "联系方式", value: "待补充电话或邮箱" },
+ { label: "社区入口", value: "待补充链接" }
+ ]
+ }
+];
+
+export default function FollowUsPage() {
+ return (
+
+ );
+}
diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx
index b45b8d3..6c2d139 100644
--- a/src/pages/index/index.tsx
+++ b/src/pages/index/index.tsx
@@ -28,6 +28,7 @@ const navItems: TabbarItem[] = [
{ key: "message", label: "消息", active: false, badge: true },
{ key: "mine", label: "我的", active: false }
];
+
const mockBluetoothDevices: DeviceCandidate[] = [
{ id: "mock-thermo-01", name: "体征监测设备 A1", source: "mock" },
{ id: "mock-thermo-02", name: "体征监测设备 B2", source: "mock" }
@@ -124,6 +125,11 @@ export default function Index() {
return;
}
+ if (item.key === "mine") {
+ Taro.navigateTo({ url: "/pages/mine/index" });
+ return;
+ }
+
showToast(`${item.label}功能待接入`);
};
diff --git a/src/pages/mine/index.config.ts b/src/pages/mine/index.config.ts
new file mode 100644
index 0000000..4f9b3ca
--- /dev/null
+++ b/src/pages/mine/index.config.ts
@@ -0,0 +1,4 @@
+export default definePageConfig({
+ navigationStyle: "custom",
+ navigationBarTitleText: "我的"
+});
diff --git a/src/pages/mine/index.scss b/src/pages/mine/index.scss
new file mode 100644
index 0000000..f53b738
--- /dev/null
+++ b/src/pages/mine/index.scss
@@ -0,0 +1,429 @@
+.mine-page {
+ position: relative;
+ min-height: 100vh;
+ padding: calc(var(--top-safe-height, 0px) + 34rpx) 24rpx 170rpx;
+ box-sizing: border-box;
+ background: linear-gradient(180deg, #1f2534 0%, #171d29 100%);
+ overflow: hidden;
+}
+
+.mine-page__halo {
+ position: absolute;
+ border-radius: 50%;
+ pointer-events: none;
+}
+
+.mine-page__halo--large {
+ top: -110rpx;
+ right: -34rpx;
+ width: 360rpx;
+ height: 360rpx;
+ background:
+ radial-gradient(circle, rgba(54, 228, 170, 0.06) 0 24%, transparent 25% 42%, rgba(110, 121, 151, 0.14) 43% 62%, transparent 63%),
+ radial-gradient(circle at center, rgba(255, 255, 255, 0.05), transparent 72%);
+}
+
+.mine-page__halo--small {
+ top: 90rpx;
+ right: 88rpx;
+ width: 150rpx;
+ height: 110rpx;
+ background: radial-gradient(circle at center, rgba(255, 255, 255, 0.04), transparent 70%);
+}
+
+.mine-page__header-card {
+ position: relative;
+ z-index: 1;
+ display: flex;
+ justify-content: space-between;
+ padding: 34rpx 28rpx 30rpx;
+ margin-bottom: 22rpx;
+ border-radius: 0 0 28rpx 28rpx;
+ background: rgba(39, 46, 64, 0.96);
+ box-shadow: inset 0 0 0 2rpx rgba(255, 255, 255, 0.03);
+}
+
+.mine-page__header-main {
+ display: flex;
+ align-items: center;
+ flex: 1;
+ min-width: 0;
+}
+
+.mine-page__avatar {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 104rpx;
+ height: 104rpx;
+ margin-right: 24rpx;
+ border-radius: 50%;
+ background: linear-gradient(180deg, rgba(170, 177, 192, 0.55) 0%, rgba(131, 141, 159, 0.75) 100%);
+}
+
+.mine-page__avatar-placeholder {
+ position: relative;
+ width: 56rpx;
+ height: 56rpx;
+}
+
+.mine-page__avatar-head,
+.mine-page__avatar-body {
+ position: absolute;
+ left: 50%;
+ background: rgba(238, 240, 244, 0.72);
+ transform: translateX(-50%);
+}
+
+.mine-page__avatar-head {
+ top: 0;
+ width: 24rpx;
+ height: 24rpx;
+ border-radius: 50%;
+}
+
+.mine-page__avatar-body {
+ bottom: 0;
+ width: 48rpx;
+ height: 26rpx;
+ border-radius: 26rpx 26rpx 20rpx 20rpx;
+}
+
+.mine-page__identity {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ min-width: 0;
+}
+
+.mine-page__name {
+ color: #f4f7fb;
+ font-size: 34rpx;
+ font-weight: 600;
+}
+
+.mine-page__phone {
+ margin-top: 10rpx;
+ color: #c2cad9;
+ font-size: 24rpx;
+}
+
+.mine-page__vip-row {
+ display: flex;
+ align-items: center;
+ margin-top: 12rpx;
+ gap: 10rpx;
+}
+
+.mine-page__vip-badge {
+ color: #f4a55c;
+ font-size: 22rpx;
+ font-style: italic;
+}
+
+.mine-page__vip-text,
+.mine-page__vip-count {
+ color: #11d1ba;
+ font-size: 20rpx;
+}
+
+.mine-page__header-actions {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ padding-left: 18rpx;
+ padding-right: calc(var(--menu-safe-width, 0px) + 6rpx);
+}
+
+.mine-page__icon-actions {
+ display: flex;
+ align-items: center;
+ gap: 16rpx;
+}
+
+.mine-page__circle-action {
+ position: relative;
+ width: 34rpx;
+ height: 34rpx;
+ opacity: 0.9;
+}
+
+.mine-page__circle-action::before,
+.mine-page__circle-action::after {
+ position: absolute;
+ content: "";
+}
+
+.mine-page__circle-action--support::before {
+ inset: 7rpx 4rpx 10rpx;
+ border: 2rpx solid rgba(255, 255, 255, 0.84);
+ border-bottom: 0;
+ border-radius: 20rpx 20rpx 0 0;
+}
+
+.mine-page__circle-action--support::after {
+ left: 12rpx;
+ right: 12rpx;
+ bottom: 6rpx;
+ height: 10rpx;
+ border-left: 2rpx solid rgba(255, 255, 255, 0.84);
+ border-right: 2rpx solid rgba(255, 255, 255, 0.84);
+ border-radius: 0 0 10rpx 10rpx;
+}
+
+.mine-page__circle-action--settings::before {
+ inset: 8rpx;
+ border: 2rpx solid rgba(255, 255, 255, 0.84);
+ border-radius: 50%;
+}
+
+.mine-page__circle-action--settings::after {
+ inset: 3rpx;
+ border: 2rpx dashed rgba(255, 255, 255, 0.56);
+ border-radius: 50%;
+}
+
+.mine-page__profile-link {
+ margin-top: 56rpx;
+ color: #1ac9c0;
+ font-size: 24rpx;
+}
+
+.mine-page__menu-card {
+ position: relative;
+ z-index: 1;
+ border-radius: 24rpx;
+ background: rgba(39, 46, 64, 0.96);
+ box-shadow: inset 0 0 0 2rpx rgba(255, 255, 255, 0.03);
+ overflow: hidden;
+}
+
+.mine-page__menu-item {
+ display: flex;
+ align-items: center;
+ min-height: 96rpx;
+ padding: 0 24rpx;
+ border-top: 1rpx solid rgba(255, 255, 255, 0.05);
+}
+
+.mine-page__menu-item--first {
+ border-top: 0;
+}
+
+.mine-page__menu-icon {
+ position: relative;
+ width: 28rpx;
+ height: 28rpx;
+ margin-right: 18rpx;
+}
+
+.mine-page__menu-icon::before,
+.mine-page__menu-icon::after {
+ position: absolute;
+ content: "";
+ border-color: #19d3be;
+}
+
+.mine-page__menu-icon--device::before {
+ inset: 4rpx;
+ border: 2rpx solid #19d3be;
+ border-radius: 6rpx;
+}
+
+.mine-page__menu-icon--device::after {
+ left: 6rpx;
+ right: 6rpx;
+ top: 12rpx;
+ height: 2rpx;
+ background: #19d3be;
+}
+
+.mine-page__menu-icon--repair::before {
+ left: 4rpx;
+ top: 12rpx;
+ width: 20rpx;
+ height: 2rpx;
+ background: #19d3be;
+ transform: rotate(45deg);
+}
+
+.mine-page__menu-icon--repair::after {
+ left: 10rpx;
+ top: 6rpx;
+ width: 10rpx;
+ height: 14rpx;
+ border: 2rpx solid #19d3be;
+ border-left: 0;
+ border-bottom: 0;
+ transform: rotate(45deg);
+}
+
+.mine-page__menu-icon--feedback::before {
+ inset: 4rpx;
+ border: 2rpx solid #19d3be;
+ border-radius: 50%;
+}
+
+.mine-page__menu-icon--feedback::after {
+ left: 12rpx;
+ top: 8rpx;
+ width: 2rpx;
+ height: 12rpx;
+ background: #19d3be;
+ box-shadow: 0 10rpx 0 #19d3be;
+}
+
+.mine-page__menu-icon--video::before {
+ inset: 5rpx 3rpx;
+ border: 2rpx solid #19d3be;
+ border-radius: 6rpx;
+}
+
+.mine-page__menu-icon--video::after {
+ top: 9rpx;
+ right: 7rpx;
+ width: 0;
+ height: 0;
+ border-top: 5rpx solid transparent;
+ border-bottom: 5rpx solid transparent;
+ border-left: 8rpx solid #19d3be;
+}
+
+.mine-page__menu-icon--follow::before {
+ left: 4rpx;
+ top: 8rpx;
+ width: 10rpx;
+ height: 16rpx;
+ border: 2rpx solid #19d3be;
+ border-right: 0;
+ border-radius: 12rpx 0 0 12rpx;
+}
+
+.mine-page__menu-icon--follow::after {
+ right: 4rpx;
+ top: 8rpx;
+ width: 10rpx;
+ height: 16rpx;
+ border: 2rpx solid #19d3be;
+ border-left: 0;
+ border-radius: 0 12rpx 12rpx 0;
+}
+
+.mine-page__menu-icon--version::before {
+ inset: 4rpx;
+ border: 2rpx solid #19d3be;
+ border-radius: 50%;
+}
+
+.mine-page__menu-icon--version::after {
+ left: 12rpx;
+ top: 8rpx;
+ width: 2rpx;
+ height: 8rpx;
+ background: #19d3be;
+ box-shadow: 0 12rpx 0 #19d3be;
+}
+
+.mine-page__menu-label {
+ flex: 1;
+ color: #edf2f7;
+ font-size: 30rpx;
+}
+
+.mine-page__menu-trailing {
+ display: flex;
+ align-items: center;
+ gap: 12rpx;
+}
+
+.mine-page__menu-value {
+ color: #707b92;
+ font-size: 24rpx;
+}
+
+.mine-page__menu-arrow {
+ color: #7d869d;
+ font-size: 26rpx;
+}
+
+.mine-page__tabbar {
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 5;
+ display: flex;
+ justify-content: space-around;
+ padding: 16rpx 24rpx calc(20rpx + env(safe-area-inset-bottom));
+ background: rgba(30, 35, 48, 0.98);
+ box-shadow: 0 -8rpx 24rpx rgba(4, 8, 20, 0.34);
+}
+
+.mine-page__tabbar-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ min-width: 88rpx;
+}
+
+.mine-page__tabbar-icon {
+ position: relative;
+ width: 34rpx;
+ height: 34rpx;
+ margin-bottom: 8rpx;
+ border-radius: 10rpx;
+ border: 2rpx solid #8f97a9;
+ opacity: 0.86;
+}
+
+.mine-page__tabbar-icon::before,
+.mine-page__tabbar-icon::after {
+ position: absolute;
+ content: "";
+}
+
+.mine-page__tabbar-icon::before {
+ left: 8rpx;
+ right: 8rpx;
+ top: 10rpx;
+ height: 2rpx;
+ background: #8f97a9;
+}
+
+.mine-page__tabbar-icon::after {
+ left: 8rpx;
+ right: 8rpx;
+ bottom: 10rpx;
+ height: 2rpx;
+ background: #8f97a9;
+}
+
+.mine-page__tabbar-icon--active {
+ border-color: #36e4aa;
+ background: rgba(54, 228, 170, 0.12);
+}
+
+.mine-page__tabbar-icon--active::before,
+.mine-page__tabbar-icon--active::after {
+ background: #36e4aa;
+}
+
+.mine-page__tabbar-badge {
+ position: absolute;
+ top: -4rpx;
+ right: -4rpx;
+ width: 10rpx;
+ height: 10rpx;
+ border-radius: 50%;
+ background: #ff4d4f;
+ box-shadow: 0 0 0 4rpx rgba(30, 35, 48, 0.98);
+}
+
+.mine-page__tabbar-label {
+ color: #b0b6c4;
+ font-size: 20rpx;
+}
+
+.mine-page__tabbar-label--active {
+ color: #36e4aa;
+}
diff --git a/src/pages/mine/index.tsx b/src/pages/mine/index.tsx
new file mode 100644
index 0000000..3faf952
--- /dev/null
+++ b/src/pages/mine/index.tsx
@@ -0,0 +1,180 @@
+import { Text, View } from "@tarojs/components";
+import Taro from "@tarojs/taro";
+import type { CSSProperties } from "react";
+import { useEffect, useState } from "react";
+import "./index.scss";
+
+type UserProfile = {
+ userName: string;
+ phone: string;
+ vip: boolean;
+ avatar: string;
+ deviceCount: number;
+};
+
+type FeatureItem = {
+ key: string;
+ label: string;
+ value?: string;
+ icon: string;
+ url?: string;
+};
+
+const userProfile: UserProfile = {
+ userName: "张天爱",
+ phone: "135****2598",
+ vip: true,
+ avatar: "",
+ deviceCount: 0
+};
+
+const featureItems: FeatureItem[] = [
+ { key: "devices", label: "我的设备", value: "已绑定 0 台", icon: "device", url: "/pages/devices/index" },
+ { key: "repair", label: "设备报修", icon: "repair", url: "/pages/repair/index" },
+ { key: "feedback", label: "问题反馈", icon: "feedback", url: "/pages/feedback/index" },
+ { key: "videos", label: "教学视频", icon: "video", url: "/pages/videos/index" },
+ { key: "follow-us", label: "关注我们", icon: "follow", url: "/pages/follow-us/index" },
+ { key: "version", label: "当前版本", value: "V1.0.2504.12", icon: "version" }
+];
+
+const tabItems = [
+ { key: "home", label: "首页" },
+ { key: "report", label: "报告" },
+ { key: "assistant", label: "小e" },
+ { key: "message", label: "消息", badge: true },
+ { key: "mine", label: "我的", active: true }
+];
+
+export default function MinePage() {
+ const [topSafeHeight, setTopSafeHeight] = useState(0);
+ const [menuSafeWidth, setMenuSafeWidth] = 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;
+ const safeRight = menuButtonRect ? windowInfo.windowWidth - menuButtonRect.left : 0;
+
+ setTopSafeHeight(safeTop);
+ setMenuSafeWidth(safeRight);
+ }, []);
+
+ const showToast = (title: string) => {
+ Taro.showToast({
+ title,
+ icon: "none"
+ });
+ };
+
+ const openPage = (url: string) => {
+ Taro.navigateTo({ url });
+ };
+
+ const handleFeatureClick = (item: FeatureItem) => {
+ if (item.url) {
+ openPage(item.url);
+ return;
+ }
+
+ showToast("当前已是最新版本");
+ };
+
+ const handleTabClick = (key: string, label: string) => {
+ if (key === "mine") {
+ return;
+ }
+
+ if (key === "home") {
+ const pages = Taro.getCurrentPages();
+
+ if (pages.length > 1) {
+ Taro.navigateBack();
+ } else {
+ Taro.redirectTo({ url: "/pages/index/index" });
+ }
+
+ return;
+ }
+
+ showToast(`${label}功能待接入`);
+ };
+
+ const pageStyle = {
+ "--top-safe-height": `${topSafeHeight}px`,
+ "--menu-safe-width": `${menuSafeWidth}px`
+ } as CSSProperties;
+
+ return (
+
+
+
+
+
+
+
+ {userProfile.avatar ? (
+
+ ) : (
+
+
+
+
+ )}
+
+
+
+ {userProfile.userName}
+ 账号: {userProfile.phone}
+
+ VIP
+ {userProfile.vip ? "已开通VIP会员" : "暂未开通VIP会员"}
+ 0
+
+
+
+
+
+
+ openPage("/pages/support/index")} />
+ openPage("/pages/settings/index")} />
+
+
+ openPage("/pages/profile/index")}>
+ 个人信息
+
+
+
+
+
+ {featureItems.map((item, index) => (
+ handleFeatureClick(item)}
+ >
+
+
+ {item.label}
+
+
+ {item.value ? {item.value} : null}
+ >
+
+
+ ))}
+
+
+
+ {tabItems.map((item) => (
+ handleTabClick(item.key, item.label)}>
+
+ {item.badge ? : null}
+
+ {item.label}
+
+ ))}
+
+
+ );
+}
diff --git a/src/pages/profile/index.config.ts b/src/pages/profile/index.config.ts
new file mode 100644
index 0000000..186f3e0
--- /dev/null
+++ b/src/pages/profile/index.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+ navigationBarTitleText: "个人信息"
+});
diff --git a/src/pages/profile/index.scss b/src/pages/profile/index.scss
new file mode 100644
index 0000000..719270f
--- /dev/null
+++ b/src/pages/profile/index.scss
@@ -0,0 +1,3 @@
+.profile-page {
+ display: block;
+}
diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx
new file mode 100644
index 0000000..cdc847e
--- /dev/null
+++ b/src/pages/profile/index.tsx
@@ -0,0 +1,26 @@
+import SecondaryPage, { type SecondaryPageSection } from "../../components/secondary-page";
+import "./index.scss";
+
+const sections: SecondaryPageSection[] = [
+ {
+ title: "资料编辑",
+ items: [
+ { label: "头像", value: "支持后续替换" },
+ { label: "昵称", value: "张天爱" },
+ { label: "手机号", value: "135****2598" },
+ { label: "修改密码", value: "待接入" }
+ ]
+ }
+];
+
+export default function ProfilePage() {
+ return (
+
+ );
+}
diff --git a/src/pages/repair/index.config.ts b/src/pages/repair/index.config.ts
new file mode 100644
index 0000000..26a3152
--- /dev/null
+++ b/src/pages/repair/index.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+ navigationBarTitleText: "设备报修"
+});
diff --git a/src/pages/repair/index.scss b/src/pages/repair/index.scss
new file mode 100644
index 0000000..0cef517
--- /dev/null
+++ b/src/pages/repair/index.scss
@@ -0,0 +1,3 @@
+.repair-page {
+ display: block;
+}
diff --git a/src/pages/repair/index.tsx b/src/pages/repair/index.tsx
new file mode 100644
index 0000000..1e7dd2e
--- /dev/null
+++ b/src/pages/repair/index.tsx
@@ -0,0 +1,28 @@
+import SecondaryPage, { type SecondaryPageSection } from "../../components/secondary-page";
+import "./index.scss";
+
+const sections: SecondaryPageSection[] = [
+ {
+ title: "报修申请",
+ items: [
+ { label: "提交报修申请" },
+ { label: "上传故障图片", value: "待接入上传能力" },
+ { label: "填写设备问题", value: "待接入表单" }
+ ]
+ },
+ {
+ title: "售后进度",
+ items: [{ label: "维修进度查询", value: "后续接接口" }]
+ }
+];
+
+export default function RepairPage() {
+ return (
+
+ );
+}
diff --git a/src/pages/settings/index.config.ts b/src/pages/settings/index.config.ts
new file mode 100644
index 0000000..a55f8e7
--- /dev/null
+++ b/src/pages/settings/index.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+ navigationBarTitleText: "设置"
+});
diff --git a/src/pages/settings/index.scss b/src/pages/settings/index.scss
new file mode 100644
index 0000000..23d29ef
--- /dev/null
+++ b/src/pages/settings/index.scss
@@ -0,0 +1,3 @@
+.settings-page {
+ display: block;
+}
diff --git a/src/pages/settings/index.tsx b/src/pages/settings/index.tsx
new file mode 100644
index 0000000..52646c1
--- /dev/null
+++ b/src/pages/settings/index.tsx
@@ -0,0 +1,31 @@
+import SecondaryPage, { type SecondaryPageSection } from "../../components/secondary-page";
+import "./index.scss";
+
+const sections: SecondaryPageSection[] = [
+ {
+ title: "通用设置",
+ items: [
+ { label: "通知设置" },
+ { label: "权限管理" },
+ { label: "清理缓存" }
+ ]
+ },
+ {
+ title: "账号相关",
+ items: [
+ { label: "关于我们" },
+ { label: "退出登录", value: "待二次确认" }
+ ]
+ }
+];
+
+export default function SettingsPage() {
+ return (
+
+ );
+}
diff --git a/src/pages/support/index.config.ts b/src/pages/support/index.config.ts
new file mode 100644
index 0000000..98bfb12
--- /dev/null
+++ b/src/pages/support/index.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+ navigationBarTitleText: "帮助与客服"
+});
diff --git a/src/pages/support/index.scss b/src/pages/support/index.scss
new file mode 100644
index 0000000..2c59e96
--- /dev/null
+++ b/src/pages/support/index.scss
@@ -0,0 +1,3 @@
+.support-page {
+ display: block;
+}
diff --git a/src/pages/support/index.tsx b/src/pages/support/index.tsx
new file mode 100644
index 0000000..1958ec3
--- /dev/null
+++ b/src/pages/support/index.tsx
@@ -0,0 +1,24 @@
+import SecondaryPage, { type SecondaryPageSection } from "../../components/secondary-page";
+import "./index.scss";
+
+const sections: SecondaryPageSection[] = [
+ {
+ title: "客服入口",
+ items: [
+ { label: "在线客服", value: "工作日 9:00 - 18:00" },
+ { label: "联系售后", value: "支持提交工单" },
+ { label: "帮助中心", value: "常见问题待补充" }
+ ]
+ }
+];
+
+export default function SupportPage() {
+ return (
+
+ );
+}
diff --git a/src/pages/videos/index.config.ts b/src/pages/videos/index.config.ts
new file mode 100644
index 0000000..a0ee045
--- /dev/null
+++ b/src/pages/videos/index.config.ts
@@ -0,0 +1,3 @@
+export default definePageConfig({
+ navigationBarTitleText: "教学视频"
+});
diff --git a/src/pages/videos/index.scss b/src/pages/videos/index.scss
new file mode 100644
index 0000000..0f5de77
--- /dev/null
+++ b/src/pages/videos/index.scss
@@ -0,0 +1,3 @@
+.videos-page {
+ display: block;
+}
diff --git a/src/pages/videos/index.tsx b/src/pages/videos/index.tsx
new file mode 100644
index 0000000..1efd3a3
--- /dev/null
+++ b/src/pages/videos/index.tsx
@@ -0,0 +1,24 @@
+import SecondaryPage, { type SecondaryPageSection } from "../../components/secondary-page";
+import "./index.scss";
+
+const sections: SecondaryPageSection[] = [
+ {
+ title: "视频分类",
+ items: [
+ { label: "设备使用教程", value: "3 个占位视频" },
+ { label: "安装教程", value: "2 个占位视频" },
+ { label: "健康指导视频", value: "持续补充" }
+ ]
+ }
+];
+
+export default function VideosPage() {
+ return (
+
+ );
+}