From 10dd9869d49bce4a8c7bd3a545413e2261af4e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B6=85=E7=BA=A7=E8=80=81=E7=99=BD=E5=85=94?= Date: Tue, 29 Jul 2025 18:42:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=BB=91=E5=AE=9A=E5=BC=95=E5=AF=BC=E9=A1=B5=E9=9D=A2=E5=8F=8A?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91=EF=BC=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=B7=AF=E7=94=B1=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- nkebao/src/pages/guide/index.module.scss | 341 +++++++++++++++++++++++ nkebao/src/pages/guide/index.tsx | 176 ++++++++++++ nkebao/src/pages/login/login.tsx | 16 ++ nkebao/src/router/config.ts | 4 +- nkebao/src/router/module/auth.tsx | 6 + 5 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 nkebao/src/pages/guide/index.module.scss create mode 100644 nkebao/src/pages/guide/index.tsx diff --git a/nkebao/src/pages/guide/index.module.scss b/nkebao/src/pages/guide/index.module.scss new file mode 100644 index 00000000..5c8f8ff4 --- /dev/null +++ b/nkebao/src/pages/guide/index.module.scss @@ -0,0 +1,341 @@ +.guideContainer { + min-height: 100vh; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + padding: 20px; + display: flex; + flex-direction: column; + position: relative; + overflow: hidden; + + &::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: url('data:image/svg+xml,'); + opacity: 0.3; + pointer-events: none; + } +} + +.loadingContainer { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); +} + +.loadingText { + color: white; + font-size: 16px; + margin-top: 16px; + font-weight: 500; +} + +.header { + text-align: center; + margin-bottom: 40px; + position: relative; + z-index: 1; +} + +.iconContainer { + width: 80px; + height: 80px; + background: rgba(255, 255, 255, 0.2); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto 20px; + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.3); +} + +.warningIcon { + font-size: 40px; + color: #ffd700; +} + +.title { + color: white; + font-size: 28px; + font-weight: 700; + margin-bottom: 12px; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); +} + +.subtitle { + color: rgba(255, 255, 255, 0.9); + font-size: 16px; + line-height: 1.5; + max-width: 300px; + margin: 0 auto; +} + +.content { + flex: 1; + position: relative; + z-index: 1; +} + +.deviceStatus { + margin-bottom: 30px; +} + +.statusCard { + background: rgba(255, 255, 255, 0.95); + border-radius: 16px; + padding: 20px; + display: flex; + align-items: center; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.2); +} + +.statusIcon { + width: 50px; + height: 50px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + margin-right: 16px; + color: white; + font-size: 24px; +} + +.statusInfo { + flex: 1; +} + +.statusTitle { + font-size: 16px; + font-weight: 600; + color: #333; + margin-bottom: 4px; +} + +.statusValue { + font-size: 14px; + color: #666; +} + +.deviceCount { + color: #667eea; + font-weight: 700; + font-size: 18px; +} + +.guideSteps { + margin-bottom: 30px; +} + +.stepsTitle { + color: white; + font-size: 20px; + font-weight: 600; + margin-bottom: 20px; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); +} + +.stepList { + display: flex; + flex-direction: column; + gap: 16px; +} + +.stepItem { + background: rgba(255, 255, 255, 0.95); + border-radius: 12px; + padding: 16px; + display: flex; + align-items: flex-start; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.2); + transition: transform 0.2s ease; + + &:hover { + transform: translateY(-2px); + } +} + +.stepNumber { + width: 32px; + height: 32px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 700; + font-size: 14px; + margin-right: 16px; + flex-shrink: 0; +} + +.stepContent { + flex: 1; +} + +.stepTitle { + font-size: 16px; + font-weight: 600; + color: #333; + margin-bottom: 4px; +} + +.stepDesc { + font-size: 14px; + color: #666; + line-height: 1.4; +} + +.tips { + background: rgba(255, 255, 255, 0.95); + border-radius: 12px; + padding: 20px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.2); +} + +.tipsTitle { + display: flex; + align-items: center; + font-size: 16px; + font-weight: 600; + color: #333; + margin-bottom: 12px; +} + +.tipsIcon { + color: #ff6b6b; + margin-right: 8px; + font-size: 18px; +} + +.tipsContent { + p { + font-size: 14px; + color: #666; + line-height: 1.6; + margin-bottom: 8px; + + &:last-child { + margin-bottom: 0; + } + } +} + +.footer { + margin-top: 30px; + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + gap: 12px; +} + +.primaryButton { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border: none; + border-radius: 12px; + height: 48px; + font-size: 16px; + font-weight: 600; + color: white; + box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4); + transition: all 0.3s ease; + + &:active { + transform: translateY(1px); + box-shadow: 0 2px 10px rgba(102, 126, 234, 0.4); + } +} + +.buttonIcon { + margin-left: 8px; + font-size: 14px; +} + +.secondaryButton { + border: 2px solid rgba(255, 255, 255, 0.8); + border-radius: 12px; + height: 48px; + font-size: 16px; + font-weight: 600; + color: white; + background: transparent; + backdrop-filter: blur(10px); + + &:active { + background: rgba(255, 255, 255, 0.1); + } +} + +// 响应式设计 +@media (max-width: 480px) { + .guideContainer { + padding: 16px; + } + + .title { + font-size: 24px; + } + + .subtitle { + font-size: 14px; + } + + .statusCard { + padding: 16px; + } + + .stepItem { + padding: 14px; + } + + .tips { + padding: 16px; + } +} + +// 动画效果 +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.header, +.deviceStatus, +.guideSteps, +.tips { + animation: fadeInUp 0.6s ease-out; +} + +.guideSteps { + animation-delay: 0.1s; +} + +.tips { + animation-delay: 0.2s; +} + +.footer { + animation: fadeInUp 0.6s ease-out 0.3s both; +} diff --git a/nkebao/src/pages/guide/index.tsx b/nkebao/src/pages/guide/index.tsx new file mode 100644 index 00000000..bc28b47d --- /dev/null +++ b/nkebao/src/pages/guide/index.tsx @@ -0,0 +1,176 @@ +import React, { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { Button, Toast } from "antd-mobile"; +import { + MobileOutlined, + ExclamationCircleOutlined, + ArrowRightOutlined, +} from "@ant-design/icons"; +import Layout from "@/components/Layout/Layout"; +import { useUserStore } from "@/store/module/user"; +import { getDashboard } from "@/pages/mobile/home/api"; +import styles from "./index.module.scss"; + +const Guide: React.FC = () => { + const navigate = useNavigate(); + const { user } = useUserStore(); + const [loading, setLoading] = useState(true); + const [deviceCount, setDeviceCount] = useState(0); + const [hasDevices, setHasDevices] = useState(false); + + useEffect(() => { + checkDeviceStatus(); + }, []); + + // 检查设备绑定状态 + const checkDeviceStatus = async () => { + try { + setLoading(true); + const dashboardData = await getDashboard(); + const deviceNum = dashboardData?.deviceNum || 0; + + setDeviceCount(deviceNum); + setHasDevices(deviceNum > 0); + + // 如果已有设备,直接跳转到首页 + if (deviceNum > 0) { + navigate("/"); + return; + } + } catch (error) { + console.error("检查设备状态失败:", error); + Toast.show({ + content: "检查设备状态失败,请重试", + position: "top", + }); + } finally { + setLoading(false); + } + }; + + // 跳转到设备管理页面 + const handleGoToDevices = () => { + navigate("/devices"); + }; + + // 跳转到首页(跳过引导) + const handleSkipGuide = () => { + navigate("/"); + }; + + if (loading) { + return ( + +
+
检查设备状态中...
+
+
+ ); + } + + return ( + +
+ {/* 头部区域 */} +
+
+ +
+

欢迎使用存客宝

+

+ 为了更好的使用体验,请先绑定您的设备 +

+
+ + {/* 内容区域 */} +
+
+
+
+ +
+
+
设备绑定状态
+
+ 已绑定设备: + {deviceCount} 台 +
+
+
+
+ +
+

绑定设备步骤

+
+
+
1
+
+
准备设备
+
+ 确保您的手机设备已安装存客宝应用 +
+
+
+
+
2
+
+
扫描二维码
+
+ 在设备管理页面扫描二维码绑定设备 +
+
+
+
+
3
+
+
开始使用
+
+ 绑定成功后即可使用所有功能 +
+
+
+
+
+ +
+
+ + 温馨提示 +
+
+

• 绑定设备后可以享受更完整的功能体验

+

• 每个账号最多可绑定10台设备

+

• 如需帮助请联系客服

+
+
+
+ + {/* 底部按钮区域 */} +
+ + + +
+
+
+ ); +}; + +export default Guide; diff --git a/nkebao/src/pages/login/login.tsx b/nkebao/src/pages/login/login.tsx index f53ccc6d..76def565 100644 --- a/nkebao/src/pages/login/login.tsx +++ b/nkebao/src/pages/login/login.tsx @@ -8,6 +8,7 @@ import { } from "antd-mobile-icons"; import { useUserStore } from "@/store/module/user"; import { loginWithPassword, loginWithCode, sendVerificationCode } from "./api"; +import { getDashboard } from "@/pages/mobile/home/api"; import style from "./login.module.scss"; const Login: React.FC = () => { @@ -100,6 +101,21 @@ const Login: React.FC = () => { Toast.show({ content: "登录成功", position: "top" }); + // 检查设备绑定状态 + try { + const dashboardData = await getDashboard(); + const deviceNum = dashboardData?.deviceNum || 0; + + // 如果没有绑定设备,跳转到引导页面 + if (deviceNum === 0) { + navigate("/guide"); + return; + } + } catch (error) { + console.error("检查设备状态失败:", error); + // 如果检查失败,默认跳转到首页 + } + // 跳转到首页或重定向URL const returnUrl = searchParams.get("returnUrl"); if (returnUrl) { diff --git a/nkebao/src/router/config.ts b/nkebao/src/router/config.ts index 136e3cb5..b7c68c54 100644 --- a/nkebao/src/router/config.ts +++ b/nkebao/src/router/config.ts @@ -14,7 +14,7 @@ export const routeGroups = { // 基础路由 basic: { name: "基础功能", - routes: ["/", "/login", "/scene", "/work", "/mine"], + routes: ["/", "/login", "/guide", "/scene", "/work", "/mine"], }, // 设备管理 @@ -109,6 +109,7 @@ export const routePermissions = { user: [ "/", "/login", + "/guide", "/scene", "/work", "/mine", @@ -136,6 +137,7 @@ export const routePermissions = { export const routeTitles: Record = { "/": "首页", "/login": "登录", + "/guide": "设备绑定引导", "/scene": "场景获客", "/work": "工作台", "/mine": "我的", diff --git a/nkebao/src/router/module/auth.tsx b/nkebao/src/router/module/auth.tsx index b89c7d5d..8d74fd49 100644 --- a/nkebao/src/router/module/auth.tsx +++ b/nkebao/src/router/module/auth.tsx @@ -1,4 +1,5 @@ import Login from "@/pages/login/login"; +import Guide from "@/pages/guide"; const authRoutes = [ { @@ -6,6 +7,11 @@ const authRoutes = [ element: , auth: false, // 不需要权限 }, + { + path: "/guide", + element: , + auth: true, // 需要登录权限 + }, ]; export default authRoutes;