diff --git a/README.md b/README.md
index 0f4baf0..de6b963 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,10 @@
## 当前状态
-**Phase 0 已完成,Phase 1 基础切片已完成。** 后端已复制并跑通空库迁移、构建、健康检查与全量测试;前端已完成 SVG 品牌资产、用户首页/登录/商品列表、管理员验证码登录、强制改密、浅色后台 Shell 与真实仪表盘。
+**Phase 0 已完成,Phase 1 基础切片已完成。** 后端已复制并跑通空库迁移、构建、健康检查与全量测试;前端已完成 SVG 品牌资产、用户首页/登录/商品列表、移动端 `/m` 首页/详情/个人中心、管理员验证码登录、强制改密、浅色后台 Shell 与真实仪表盘。
- 前端:`http://localhost:5289/`
+- 移动端:`http://localhost:5289/m`
- 后台:`http://localhost:5289/console-jy8k3m/login`
- 后端:`http://localhost:18089/`
- 健康检查:`http://localhost:18089/health/ready`
diff --git a/docs/Phase1-验收报告.md b/docs/Phase1-验收报告.md
index ef723de..49130dd 100644
--- a/docs/Phase1-验收报告.md
+++ b/docs/Phase1-验收报告.md
@@ -89,9 +89,22 @@
`AppRouter` 已改为 `React.lazy + Suspense`:
- 首页商品列表、用户登录、后台登录、后台改密、后台仪表盘、后台 Shell 分别按路由加载。
+- 移动端 Layout、首页、详情、个人中心独立分包。
- 后台代码不会在用户首页首屏直接执行。
- 已移除会提前触发后台模块加载的顶层 `import()`。
+### 1.8 移动端 `/m` 基础切片
+
+已引入 `antd-mobile` + `antd-mobile-icons`:
+
+- `MobileLayout`:品牌顶栏、底部 TabBar(首页 / 订单 / 消息 / 我的)、详情页自动隐藏 TabBar。
+- `MobileHomePage`:深绿品牌首屏、搜索、快捷筛选、PullToRefresh、商品卡列表、空/错误状态。
+- `MobileListingDetailPage`:商品图、价格/押金/哈夫币、账号说明、资产摘要、在线时间、固定底部操作栏。
+- `MobileProfilePage`:登录状态、实名状态、订单/消息入口、退出登录。
+- `/m/orders`、`/m/messages` 先用统一占位页,下一批迁移真实业务。
+- 移动端 CSS 变量已接入解忧商行品牌色,不使用 Vant/旧站视觉。
+
+
---
## 2. 验证结果
@@ -126,6 +139,10 @@ listings = ok,返回 1 件联调商品
```text
/console-jy8k3m/login HTTP 200
/favicon.svg HTTP 200
+/m HTTP 200
+/m/listings/1 HTTP 200
+/m/login HTTP 200
+/api/listings/1 code=ok,返回联调商品详情
```
---
@@ -149,9 +166,11 @@ listings = ok,返回 1 件联调商品
当前生产构建:
```text
-dist/assets/index-*.js 884.51 kB │ gzip 288.64 kB
-dist/assets/AdminLayout-*.js 36.74 kB │ gzip 12.98 kB
-dist/assets/AdminDashboardPage-*.js 179.67 kB │ gzip 58.44 kB
+dist/assets/index-*.js 886.81 kB │ gzip 289.33 kB
+dist/assets/AdminLayout-*.js 36.75 kB │ gzip 12.98 kB
+dist/assets/AdminDashboardPage-*.js 179.71 kB │ gzip 58.46 kB
+dist/assets/MobileHomePage-*.js 36.96 kB │ gzip 13.37 kB
+dist/assets/MobileListingDetailPage-*.js 27.31 kB │ gzip 10.70 kB
```
**问题:** 首屏主包仍偏大,超过 Phase 1 目标。
@@ -162,19 +181,19 @@ dist/assets/AdminDashboardPage-*.js 179.67 kB │ gzip 58.44 kB
## 5. 已知限制
-1. 移动端 `/m` 尚未开始迁移。
+1. 移动端订单与消息页仍是占位,下单、客服会话尚未接入。
2. 后台 43 个页面目前只有仪表盘是真实页面,其余为统一占位。
3. 分销后台尚未做品牌轻改。
4. 后台菜单权限码基于旧项目推断,后续需与后端权限表逐一核对。
5. SVG 中文尚未转曲。
6. 首屏包体仍偏大。
-7. 本批次尚未提交 Git。
+7. 本移动端批次尚未提交 Git。
---
## 6. 建议下一批次
-1. 移动端 `/m` 首页 + 商品列表 + 底部导航。
+1. 移动端订单列表、订单详情、消息与聊天。
2. 后台列表页原型:DataTable、FilterBar、详情 Drawer、批量操作。
3. 先迁移后台订单列表与商品审核列表。
4. 分销后台主题轻改。
diff --git a/docs/项目计划.md b/docs/项目计划.md
index 3147a2a..ce2697a 100644
--- a/docs/项目计划.md
+++ b/docs/项目计划.md
@@ -352,7 +352,7 @@ hfb_jysh/
### Phase 1:品牌与设计系统(1 周)
-> 状态:**基础切片已完成(2026-10-30)**,验收见 [`Phase1-验收报告.md`](./Phase1-验收报告.md)。已完成 SVG 品牌资产、管理员会话、后台登录/强制改密/Shell/仪表盘与路由懒加载;移动端与后台列表页原型继续。
+> 状态:**基础切片已完成(2026-10-30)**,验收见 [`Phase1-验收报告.md`](./Phase1-验收报告.md)。已完成 SVG 品牌资产、管理员会话、后台登录/强制改密/Shell/仪表盘、路由懒加载与移动端 `/m` 首页/详情/个人中心;后台列表页原型与移动订单/消息继续。
- 重绘 logo SVG:横版、方形印章、单色、反白。
- 落地 Design Token:颜色、字体、间距、圆角、阴影、动效。
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 14fb8a6..c53c175 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -11,6 +11,8 @@
"@ant-design/icons": "^6.0.0",
"@tanstack/react-query": "^5.90.5",
"antd": "^5.27.6",
+ "antd-mobile": "^5.43.0",
+ "antd-mobile-icons": "^0.3.0",
"axios": "^1.13.2",
"dayjs": "^1.11.19",
"react": "^19.1.1",
@@ -865,6 +867,31 @@
"node": ">=18"
}
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz",
+ "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz",
+ "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/core": "^1.8.0",
+ "@floating-ui/utils": "^0.2.12"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz",
+ "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
+ "license": "MIT"
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
@@ -1108,6 +1135,18 @@
"react-dom": ">=18.0.0"
}
},
+ "node_modules/@react-spring/rafz": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.6.1.tgz",
+ "integrity": "sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==",
+ "license": "MIT"
+ },
+ "node_modules/@react-spring/types": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@react-spring/types/-/types-9.6.1.tgz",
+ "integrity": "sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==",
+ "license": "MIT"
+ },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-rc.3",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
@@ -1618,6 +1657,24 @@
"@types/react": "^19.3.0"
}
},
+ "node_modules/@use-gesture/core": {
+ "version": "10.3.0",
+ "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.0.tgz",
+ "integrity": "sha512-rh+6MND31zfHcy9VU3dOZCqGY511lvGcfyJenN4cWZe0u1BH6brBpBddLVXhF2r4BMqWbvxfsbL7D287thJU2A==",
+ "license": "MIT"
+ },
+ "node_modules/@use-gesture/react": {
+ "version": "10.3.0",
+ "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.0.tgz",
+ "integrity": "sha512-3zc+Ve99z4usVP6l9knYVbVnZgfqhKah7sIG+PS2w+vpig2v2OLct05vs+ZXMzwxdNCMka8B+8WlOo0z6Pn6DA==",
+ "license": "MIT",
+ "dependencies": {
+ "@use-gesture/core": "10.3.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.8.0"
+ }
+ },
"node_modules/@vitejs/plugin-react": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz",
@@ -1651,6 +1708,26 @@
"node": ">= 6.0.0"
}
},
+ "node_modules/ahooks": {
+ "version": "3.11.0",
+ "resolved": "https://registry.npmjs.org/ahooks/-/ahooks-3.11.0.tgz",
+ "integrity": "sha512-mQML7DrxZo7xvxm145NTMowE9m75tflSayKjlwEMzwQSRFguweNCdCSIq88aQ4RRfVMugBrH8AtGresJwqMy5A==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.21.0",
+ "dayjs": "^1.9.1",
+ "js-cookie": "^3.0.5",
+ "lodash": "^4.17.21",
+ "react-fast-compare": "^3.2.2",
+ "resize-observer-polyfill": "^1.5.1",
+ "screenfull": "^5.0.0",
+ "tslib": "^2.4.1"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/antd": {
"version": "5.29.3",
"resolved": "https://registry.npmjs.org/antd/-/antd-5.29.3.tgz",
@@ -1716,6 +1793,160 @@
"react-dom": ">=16.9.0"
}
},
+ "node_modules/antd-mobile": {
+ "version": "5.43.0",
+ "resolved": "https://registry.npmjs.org/antd-mobile/-/antd-mobile-5.43.0.tgz",
+ "integrity": "sha512-Pe8P/hHmv1vDHzbGuT6C23SJPeiH7ryESi001eiNqEm9WzEgyKhV60T69Mt26fUvkF7k6Wd75cMcdDziGYeJbw==",
+ "license": "MIT",
+ "dependencies": {
+ "@floating-ui/dom": "^1.4.2",
+ "@rc-component/mini-decimal": "^1.1.0",
+ "@react-spring/web": "~9.6.1",
+ "@use-gesture/react": "10.3.0",
+ "ahooks": "^3.7.6",
+ "antd-mobile-icons": "^0.3.0",
+ "antd-mobile-v5-count": "^1.0.1",
+ "classnames": "^2.3.2",
+ "dayjs": "^1.11.7",
+ "deepmerge": "^4.3.1",
+ "nano-memoize": "^3.0.16",
+ "rc-field-form": "^1.34.2",
+ "rc-segmented": "~2.4.1",
+ "rc-util": "^5.44.4",
+ "react-fast-compare": "^3.2.2",
+ "react-is": "^18.2.0",
+ "runes2": "^1.1.2",
+ "staged-components": "^1.1.3",
+ "tslib": "^2.5.0",
+ "use-sync-external-store": "^1.2.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/antd-mobile-icons": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/antd-mobile-icons/-/antd-mobile-icons-0.3.0.tgz",
+ "integrity": "sha512-rqINQpJWZWrva9moCd1Ye695MZYWmqLPE+bY8d2xLRy7iSQwPsinCdZYjpUPp2zL/LnKYSyXxP2ut2A+DC+whQ==",
+ "license": "MIT"
+ },
+ "node_modules/antd-mobile-v5-count": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/antd-mobile-v5-count/-/antd-mobile-v5-count-1.0.1.tgz",
+ "integrity": "sha512-YGsiEDCPUDz3SzfXi6gLZn/HpeSMW+jgPc4qiYUr1fSopg3hkUie2TnooJdExgfiETHefH3Ggs58He0OVfegLA==",
+ "license": "MIT"
+ },
+ "node_modules/antd-mobile/node_modules/@react-spring/web": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@react-spring/web/-/web-9.6.1.tgz",
+ "integrity": "sha512-X2zR6q2Z+FjsWfGAmAXlQaoUHbPmfuCaXpuM6TcwXPpLE1ZD4A1eys/wpXboFQmDkjnrlTmKvpVna1MjWpZ5Hw==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-spring/animated": "~9.6.1",
+ "@react-spring/core": "~9.6.1",
+ "@react-spring/shared": "~9.6.1",
+ "@react-spring/types": "~9.6.1"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/antd-mobile/node_modules/@react-spring/web/node_modules/@react-spring/animated": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.6.1.tgz",
+ "integrity": "sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-spring/shared": "~9.6.1",
+ "@react-spring/types": "~9.6.1"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/antd-mobile/node_modules/@react-spring/web/node_modules/@react-spring/core": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@react-spring/core/-/core-9.6.1.tgz",
+ "integrity": "sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-spring/animated": "~9.6.1",
+ "@react-spring/rafz": "~9.6.1",
+ "@react-spring/shared": "~9.6.1",
+ "@react-spring/types": "~9.6.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-spring/donate"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/antd-mobile/node_modules/@react-spring/web/node_modules/@react-spring/shared": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@react-spring/shared/-/shared-9.6.1.tgz",
+ "integrity": "sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-spring/rafz": "~9.6.1",
+ "@react-spring/types": "~9.6.1"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/antd-mobile/node_modules/rc-field-form": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.44.0.tgz",
+ "integrity": "sha512-el7w87fyDUsca63Y/s8qJcq9kNkf/J5h+iTdqG5WsSHLH0e6Usl7QuYSmSVzJMgtp40mOVZIY/W/QP9zwrp1FA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.18.0",
+ "async-validator": "^4.1.0",
+ "rc-util": "^5.32.2"
+ },
+ "engines": {
+ "node": ">=8.x"
+ },
+ "peerDependencies": {
+ "react": ">=16.9.0",
+ "react-dom": ">=16.9.0"
+ }
+ },
+ "node_modules/antd-mobile/node_modules/rc-segmented": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.4.1.tgz",
+ "integrity": "sha512-KUi+JJFdKnumV9iXlm+BJ00O4NdVBp2TEexLCk6bK1x/RH83TvYKQMzIz/7m3UTRPD08RM/8VG/JNjWgWbd4cw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.11.1",
+ "classnames": "^2.2.1",
+ "rc-motion": "^2.4.4",
+ "rc-util": "^5.17.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.0.0",
+ "react-dom": ">=16.0.0"
+ }
+ },
+ "node_modules/antd-mobile/node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "license": "MIT"
+ },
+ "node_modules/antd-mobile/node_modules/staged-components": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/staged-components/-/staged-components-1.1.3.tgz",
+ "integrity": "sha512-9EIswzDqjwlEu+ymkV09TTlJfzSbKgEnNteUnZSTxkpMgr5Wx2CzzA9WcMFWBNCldqVPsHVnRGGrApduq2Se5A==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/antd/node_modules/@ant-design/colors": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.2.1.tgz",
@@ -1757,6 +1988,12 @@
"react-dom": ">=16.0.0"
}
},
+ "node_modules/async-validator": {
+ "version": "4.2.5",
+ "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
+ "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==",
+ "license": "MIT"
+ },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -1947,6 +2184,15 @@
}
}
},
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -2269,6 +2515,12 @@
"integrity": "sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==",
"license": "MIT"
},
+ "node_modules/js-cookie": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.8.tgz",
+ "integrity": "sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw==",
+ "license": "MIT"
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -2311,6 +2563,12 @@
"node": ">=6"
}
},
+ "node_modules/lodash": {
+ "version": "4.18.1",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
+ "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
+ "license": "MIT"
+ },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -2357,6 +2615,12 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
+ "node_modules/nano-memoize": {
+ "version": "3.0.16",
+ "resolved": "https://registry.npmjs.org/nano-memoize/-/nano-memoize-3.0.16.tgz",
+ "integrity": "sha512-JyK96AKVGAwVeMj3MoMhaSXaUNqgMbCRSQB3trUV8tYZfWEzqUBKdK1qJpfuNXgKeHOx1jv/IEYTM659ly7zUA==",
+ "license": "MIT"
+ },
"node_modules/nanoid": {
"version": "3.3.20",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz",
@@ -3077,6 +3341,12 @@
"react": "^19.3.1"
}
},
+ "node_modules/react-fast-compare": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
+ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==",
+ "license": "MIT"
+ },
"node_modules/react-is": {
"version": "19.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.1.tgz",
@@ -3183,12 +3453,30 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/runes2": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/runes2/-/runes2-1.1.10.tgz",
+ "integrity": "sha512-4Y1en7X+3i0pf9NDPMEerT1CkZlExpQJPnEPlrBXzXSIHO3etyZR6Wbpl+hHWVYRFnhPVCyPHaJks6GcCFgEiA==",
+ "license": "MIT"
+ },
"node_modules/scheduler": {
"version": "0.28.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz",
"integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==",
"license": "MIT"
},
+ "node_modules/screenfull": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/screenfull/-/screenfull-5.2.0.tgz",
+ "integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/scroll-into-view-if-needed": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
@@ -3268,6 +3556,12 @@
"integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==",
"license": "MIT"
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
@@ -3320,6 +3614,15 @@
"browserslist": ">= 4.21.0"
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.7.0.tgz",
+ "integrity": "sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/vite": {
"version": "7.3.7",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.7.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index af99512..7f57a9c 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -13,6 +13,8 @@
"@ant-design/icons": "^6.0.0",
"@tanstack/react-query": "^5.90.5",
"antd": "^5.27.6",
+ "antd-mobile": "^5.43.0",
+ "antd-mobile-icons": "^0.3.0",
"axios": "^1.13.2",
"dayjs": "^1.11.19",
"react": "^19.1.1",
diff --git a/frontend/src/app/AppRouter.tsx b/frontend/src/app/AppRouter.tsx
index 604d0e3..4a10760 100644
--- a/frontend/src/app/AppRouter.tsx
+++ b/frontend/src/app/AppRouter.tsx
@@ -11,6 +11,27 @@ const ListingListPage = lazy(() =>
const LoginPage = lazy(() =>
import('@/features/auth/LoginPage').then(module => ({ default: module.LoginPage }))
)
+const MobileLayout = lazy(() =>
+ import('@/layouts/MobileLayout').then(module => ({ default: module.MobileLayout }))
+)
+const MobileHomePage = lazy(() =>
+ import('@/features/mobile/MobileHomePage').then(module => ({ default: module.MobileHomePage }))
+)
+const MobileListingDetailPage = lazy(() =>
+ import('@/features/mobile/MobileListingDetailPage').then(module => ({
+ default: module.MobileListingDetailPage,
+ }))
+)
+const MobileProfilePage = lazy(() =>
+ import('@/features/mobile/MobileProfilePage').then(module => ({
+ default: module.MobileProfilePage,
+ }))
+)
+const MobilePlaceholderPage = lazy(() =>
+ import('@/features/mobile/MobilePlaceholderPage').then(module => ({
+ default: module.MobilePlaceholderPage,
+ }))
+)
const AdminLoginPage = lazy(() =>
import('@/features/admin/AdminLoginPage').then(module => ({ default: module.AdminLoginPage }))
)
@@ -60,6 +81,32 @@ export function AppRouter() {
实名审核 · 流程留痕 · 账单逐项列明
+押金、租金、额外消耗和退款规则都会在订单里逐项列出。结账备注不参与系统结算。
+{data.description || '号主暂未填写补充说明。'}
+押金、租金、额外消耗和退款规则会在下单页逐项列出;交接、归还、结账全程留痕。
+{description}
+ +{user ? user.phone : '登录后查看订单、钱包与实名状态'}
+