瀏覽代碼

1. 轮播图切换
2. 修改密码
3. 登录页修改
4. 验证码修改

ith5 3 月之前
父節點
當前提交
a3618624d0

+ 28 - 0
src/api/auth/index.ts

@@ -15,6 +15,34 @@ export const sendCodeApi = (params) => {
   });
 };
 
+/**
+ * 发送修改密码验证码
+ * @param params {mobile: string}
+ * @returns
+ */
+export const sendChangePasswordCodeApi = (params) => {
+  let os = getSystemInfo();
+  return request({
+    url: `${authBaseApi}/send-change-password-code`,
+    method: "POST",
+    data: { os, ...params },
+  });
+};
+
+/**
+ * 修改密码
+ * @param params
+ * @returns
+ */
+export const changePasswordApi = (params) => {
+  let os = getSystemInfo();
+  return request({
+    url: `${authBaseApi}/change-password`,
+    method: "POST",
+    data: { os, ...params },
+  });
+};
+
 /**
  * 短信登录
  */

+ 1 - 0
src/app.tsx

@@ -12,6 +12,7 @@ function App(props: { children: React.ReactNode }) {
     "--nutui-tabs-tabpane-padding": "0",
     "--nutui-button-primary-disabled": "#b3b9e9",
     "--nutui-color-primary-disabled": "#b3b9e9",
+    "--nutui-input-border-bottom-width": "2px",
   };
   // 可以使用所有的 React Hooks
   useEffect(() => {});

二進制
src/asset/img/banner/1.jpg


二進制
src/asset/img/banner/2.jpg


二進制
src/asset/img/banner/3.jpg


二進制
src/asset/img/banner/4.jpg


二進制
src/asset/img/banner/5.jpg


+ 52 - 4
src/components/game-intro/index.tsx

@@ -1,6 +1,12 @@
 import { Button, Image } from "@nutui/nutui-react-taro";
 import { View, ScrollView } from "@tarojs/components";
 import { downLogApi } from "../../api/log";
+import banner1 from "../../asset/img/banner/1.jpg";
+import banner2 from "../../asset/img/banner/2.jpg";
+import banner3 from "../../asset/img/banner/3.jpg";
+import banner4 from "../../asset/img/banner/4.jpg";
+import banner5 from "../../asset/img/banner/5.jpg";
+
 const GameIntro = (props) => {
   const { vipUserInfo } = props;
   console.log(vipUserInfo);
@@ -80,7 +86,7 @@ const GameIntro = (props) => {
         </View>
         <View className="flex justify-between text-center">
           <View className="px-[20px] w-[24%] border-r-[1px] border-r-solid border-r-[#e0e0e0]">
-            <View className="text-[14px] font-[800] text-[#333]">5.0</View>
+            <View className="text-[14px] font-[800] text-[#333]">4.7</View>
             <View className="text-[12px] text-[#949494]">游戏评分</View>
           </View>
           <View className="px-[20px] w-[24%] border-r-[1px] border-r-solid border-r-[#e0e0e0]">
@@ -92,7 +98,7 @@ const GameIntro = (props) => {
             <View className="text-[12px] text-[#949494]">大小</View>
           </View>
           <View className="px-[20px] w-[24%]">
-            <View className="text-[14px] font-[800] text-[#333]">16+</View>
+            <View className="text-[14px] font-[800] text-[#333]">17+</View>
             <View className="text-[12px] text-[#949494]">年龄分级</View>
           </View>
         </View>
@@ -107,7 +113,49 @@ const GameIntro = (props) => {
                 }}
               >
                 <img
-                  src="http://192.168.10.5:8181/uploads20250917/b1.jpg"
+                  src={banner1}
+                  width="250px"
+                  height="427px"
+                  style={{ objectFit: "cover", borderRadius: "10px" }}
+                />
+              </View>
+              <View
+                style={{
+                  width: "250px",
+                  height: "427px",
+                  marginRight: "10px",
+                }}
+              >
+                <img
+                  src={banner2}
+                  width="250px"
+                  height="427px"
+                  style={{ objectFit: "cover", borderRadius: "10px" }}
+                />
+              </View>
+              <View
+                style={{
+                  width: "250px",
+                  height: "427px",
+                  marginRight: "10px",
+                }}
+              >
+                <img
+                  src={banner3}
+                  width="250px"
+                  height="427px"
+                  style={{ objectFit: "cover", borderRadius: "10px" }}
+                />
+              </View>
+              <View
+                style={{
+                  width: "250px",
+                  height: "427px",
+                  marginRight: "10px",
+                }}
+              >
+                <img
+                  src={banner4}
                   width="250px"
                   height="427px"
                   style={{ objectFit: "cover", borderRadius: "10px" }}
@@ -121,7 +169,7 @@ const GameIntro = (props) => {
                 }}
               >
                 <img
-                  src="http://192.168.10.5:8181/uploads20250917/b2.jpg"
+                  src={banner5}
                   width="250px"
                   height="427px"
                   style={{ objectFit: "cover", borderRadius: "10px" }}

+ 1 - 1
src/config/index.ts

@@ -1,7 +1,7 @@
 // 环境配置
 const config = {
   development: {
-    TARO_ACT_HOST: "http://192.168.10.5:3000",
+    TARO_ACT_HOST: "http://192.168.10.5:3001",
     API_BASE_URL: "/api",
   },
   production: {

+ 1 - 0
src/http/request.ts

@@ -105,6 +105,7 @@ const request = async (params, callback?: any) => {
               console.log("用户点击确定");
             }
           },
+          confirmColor: "#4d7ced",
         });
         return;
       }

+ 105 - 0
src/pages/login/index copy.tsx

@@ -0,0 +1,105 @@
+import { Text, View } from "@tarojs/components";
+import "./index.scss";
+import { Button, Form, Input } from "@nutui/nutui-react-taro";
+import { verifyPhone } from "../../utils";
+import { sendCodeApi, smsLoginApi } from "../../api/auth";
+import { setStorageSync, redirectTo } from "@tarojs/taro";
+import { useState } from "react";
+
+const LoginIndex = () => {
+  const [form] = Form.useForm();
+  const [showCode, setShowCode] = useState(false);
+  const mobile = Form.useWatch("mobile", form);
+  const code = Form.useWatch("code", form);
+  /**
+   * 发送验证码
+   */
+  const sendCode = async () => {
+    console.log(mobile);
+    setShowCode(true);
+    await sendCodeApi({ mobile }).then((res) => {
+      console.log(res);
+    });
+  };
+  /**
+   * 短信登录
+   */
+  const smsLogin = async () => {
+    await smsLoginApi({ mobile, code }).then((res: any) => {
+      const { data } = res;
+      const {
+        token,
+        username,
+        mobile,
+        is_vip,
+        vip_code,
+        circle_info,
+        vip_info,
+      } = data;
+      setStorageSync("Authorization", token);
+      setStorageSync("User", { username, mobile, is_vip, vip_code });
+      setStorageSync("vipInfo", vip_info);
+      setStorageSync("circleInfo", circle_info);
+      redirectTo({ url: "/pages/index/index" });
+    });
+  };
+
+  return (
+    <View className="login-page">
+      <View className="login-contain">
+        <View className="text-[16px] font-bold text-center">手机号登录</View>
+        <Form form={form}>
+          {!showCode && (
+            <Form.Item name="mobile">
+              <Input placeholder="手机号码" className="input-box" />
+            </Form.Item>
+          )}
+
+          {/* <View className="flex flex-wrap justify-between items-center bg-[#ffffff] relative w-full"> */}
+          {showCode && (
+            <Form.Item name="code">
+              <Input placeholder="请输入短信验证码" className="input-box" />
+            </Form.Item>
+          )}
+
+          {/* <Button
+              type="primary"
+              disabled={!verifyPhone(mobile)}
+              size="small"
+              className="flex-shrink-1 absolute right-0"
+              onClick={() => sendCode()}
+            >
+              <Text className="text-[12px] text-[#ffffff]">获取验证码</Text>
+            </Button> */}
+          {/* </View> */}
+        </Form>
+        <View className="mt-[22px]">
+          {showCode ? (
+            <Button
+              size="large"
+              block
+              type="primary"
+              disabled={!verifyPhone(mobile) || !code}
+              onClick={() => smsLogin()}
+            >
+              登录
+            </Button>
+          ) : (
+            <Button
+              size="large"
+              block
+              type="primary"
+              disabled={!verifyPhone(mobile)}
+              className="flex-shrink-1 absolute right-0"
+              onClick={() => sendCode()}
+            >
+              下一步
+            </Button>
+          )}
+        </View>
+      </View>
+    </View>
+  );
+};
+
+export default LoginIndex;

+ 167 - 77
src/pages/login/index.tsx

@@ -1,31 +1,55 @@
-import { Text, View } from "@tarojs/components";
-import "./index.scss";
-import { Button, Form, Input } from "@nutui/nutui-react-taro";
-import { verifyPhone } from "../../utils";
-import { sendCodeApi, smsLoginApi } from "../../api/auth";
-import { setStorageSync, redirectTo } from "@tarojs/taro";
+import "./index1.scss";
 import { useState } from "react";
-
+import {
+  showModal,
+  showToast,
+  navigateTo,
+  setStorageSync,
+  redirectTo,
+} from "@tarojs/taro";
+import { sendCodeApi, smsLoginApi } from "../../api/auth";
 const LoginIndex = () => {
-  const [form] = Form.useForm();
-  const [showCode, setShowCode] = useState(false);
-  const mobile = Form.useWatch("mobile", form);
-  const code = Form.useWatch("code", form);
-  /**
-   * 发送验证码
-   */
-  const sendCode = async () => {
-    console.log(mobile);
-    setShowCode(true);
-    await sendCodeApi({ mobile }).then((res) => {
-      console.log(res);
-    });
+  const [countdown, setCountdown] = useState(0);
+  const [formData, setFormData] = useState({
+    phone: "",
+    code: "",
+  });
+  const handleInputChange = (e: any) => {
+    setFormData({ ...formData, [e.target.name]: e.target.value });
   };
-  /**
-   * 短信登录
-   */
-  const smsLogin = async () => {
-    await smsLoginApi({ mobile, code }).then((res: any) => {
+  // 处理登录
+  const handleSubmit = async (e: React.FormEvent) => {
+    e.preventDefault();
+
+    // 表单验证
+    if (!formData.phone || !formData.code) {
+      showModal({
+        content: "请填写完整信息",
+      });
+      return;
+    }
+
+    const phoneRegex = /^1[3-9]\d{9}$/;
+    if (!phoneRegex.test(formData.phone)) {
+      showModal({
+        content: "请输入正确的手机号",
+      });
+      return;
+    }
+
+    if (formData.code.length !== 4) {
+      showModal({
+        content: "验证码长度应为4位",
+      });
+      return;
+    }
+
+    try {
+      const res: any = await smsLoginApi({
+        mobile: formData.phone,
+        code: formData.code,
+      });
+
       const { data } = res;
       const {
         token,
@@ -41,64 +65,130 @@ const LoginIndex = () => {
       setStorageSync("vipInfo", vip_info);
       setStorageSync("circleInfo", circle_info);
       redirectTo({ url: "/pages/index/index" });
-    });
+
+      showToast({
+        title: "登录成功",
+        icon: "none",
+        duration: 2000,
+      });
+
+      navigateTo({ url: "/pages/index/index" });
+    } catch (error) {
+      showToast({
+        title: "登录失败,请重试",
+        icon: "none",
+        duration: 2000,
+      });
+    }
+  };
+
+  // 发送验证码
+  const handleSendCode = async () => {
+    try {
+      if (!formData.phone) {
+        showModal({
+          content: "请先输入手机号",
+          showCancel: false,
+          confirmColor: "#4d7ced",
+        });
+        return;
+      }
+
+      const phoneRegex = /^1[3-9]\d{9}$/;
+      if (!phoneRegex.test(formData.phone)) {
+        showModal({
+          content: "请输入正确的手机号",
+          showCancel: false,
+          confirmColor: "#4d7ced",
+        });
+        return;
+      }
+
+      await sendCodeApi({ mobile: formData.phone });
+      showToast({
+        title: "验证码已发送",
+        icon: "none",
+        duration: 2000,
+      });
+      setCountdown(60);
+      const timer = setInterval(() => {
+        setCountdown((prev) => {
+          if (prev <= 1) {
+            clearInterval(timer);
+            return 0;
+          }
+          return prev - 1;
+        });
+      }, 1000);
+    } catch (error: any) {
+      showToast({
+        title: error.msg || "发送失败,请重试",
+        icon: "none",
+        duration: 2000,
+      });
+    }
   };
 
   return (
-    <View className="login-page">
-      <View className="login-contain">
-        <View className="text-[16px] font-bold text-center">手机号登录</View>
-        <Form form={form}>
-          {!showCode && (
-            <Form.Item name="mobile">
-              <Input placeholder="手机号码" className="input-box" />
-            </Form.Item>
-          )}
+    <div className="login-page">
+      <div className="login-container">
+        <div className="login-header">
+          <h1>Hello!</h1>
+          <p>很高兴见到您,欢迎来到玩家中心</p>
+        </div>
+
+        <div className="login-card">
+          <h2>短信登录</h2>
+          <form onSubmit={handleSubmit} className="login-form">
+            <div className="form-item">
+              <div className="label">账号</div>
+              <div className="input-container">
+                <i className="phone-icon"></i>
+                <input
+                  type="tel"
+                  name="phone"
+                  className="custom-input"
+                  placeholder="请输入手机号"
+                  value={formData.phone}
+                  onChange={handleInputChange}
+                  maxLength={11}
+                />
+              </div>
+            </div>
 
-          {/* <View className="flex flex-wrap justify-between items-center bg-[#ffffff] relative w-full"> */}
-          {showCode && (
-            <Form.Item name="code">
-              <Input placeholder="请输入短信验证码" className="input-box" />
-            </Form.Item>
-          )}
+            <div className="form-item">
+              <div className="label">验证码</div>
+              <div className="code-container">
+                <div className="input-container">
+                  <i className="shield-icon"></i>
+                  <input
+                    type="text"
+                    name="code"
+                    className="custom-input"
+                    placeholder="输入验证码"
+                    value={formData.code}
+                    onChange={handleInputChange}
+                    maxLength={6}
+                  />
+                </div>
+                <button
+                  type="button"
+                  className="code-btn"
+                  disabled={countdown > 0}
+                  onClick={handleSendCode}
+                >
+                  {countdown > 0 ? `${countdown}s` : "获取验证码"}
+                </button>
+              </div>
+            </div>
 
-          {/* <Button
-              type="primary"
-              disabled={!verifyPhone(mobile)}
-              size="small"
-              className="flex-shrink-1 absolute right-0"
-              onClick={() => sendCode()}
-            >
-              <Text className="text-[12px] text-[#ffffff]">获取验证码</Text>
-            </Button> */}
-          {/* </View> */}
-        </Form>
-        <View className="mt-[22px]">
-          {showCode ? (
-            <Button
-              size="large"
-              block
-              type="primary"
-              disabled={!verifyPhone(mobile) || !code}
-              onClick={() => smsLogin()}
-            >
+            <button type="submit" className="submit-btn">
               登录
-            </Button>
-          ) : (
-            <Button
-              size="large"
-              block
-              type="primary"
-              disabled={!verifyPhone(mobile)}
-              className="flex-shrink-1 absolute right-0"
-              onClick={() => sendCode()}
-            >
-              下一步
-            </Button>
-          )}
-        </View>
-      </View>
-    </View>
+            </button>
+          </form>
+        </div>
+      </div>
+    </div>
   );
 };
 

+ 194 - 0
src/pages/login/index1.scss

@@ -0,0 +1,194 @@
+/* 统一高度设置 */
+:root {
+  --input-height: 46px; /* 统一控制高度 */
+}
+.login-page {
+  min-height: calc(100vh);
+  background: linear-gradient(180deg, #726ead 0%, #bbc4e3 100%);
+  padding: 40px 15px;
+  display: flex;
+  flex-direction: column;
+
+  .login-header {
+    color: #fff;
+    margin-bottom: 20px;
+
+    h1 {
+      font-size: 32px;
+      font-weight: 600;
+      margin: 0 0 8px;
+      text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+    }
+
+    p {
+      font-size: 14px;
+      margin: 0;
+      opacity: 0.9;
+    }
+  }
+  .login-container {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -60%);
+    width: calc(100vw - 30px);
+  }
+
+  .login-card {
+    background: #fff;
+    border-radius: 16px;
+    padding: 20px;
+
+    h2 {
+      font-size: 20px;
+      font-weight: 500;
+      color: #333;
+      margin: 0 0 24px;
+    }
+
+    .login-form {
+      .form-item {
+        margin-bottom: 20px;
+
+        .label {
+          font-size: 14px;
+          color: #666;
+          margin-bottom: 8px;
+          font-weight: 800;
+        }
+
+        .input-container {
+          position: relative;
+          display: flex;
+          align-items: center;
+
+          .phone-icon,
+          .shield-icon {
+            position: absolute;
+            left: 12px;
+            width: 20px;
+            height: 20px;
+            background-size: contain;
+            background-repeat: no-repeat;
+          }
+
+          .phone-icon {
+            width: 25px;
+            height: 25px;
+            background-image: url('data:image/svg+xml;utf8,<svg t="1755848332958" class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="512" height="512"><path d="M682.666667 170.666667H341.333333c-47.786667 0-85.333333 37.546667-85.333333 85.333333v512c0 47.786667 37.546667 85.333333 85.333333 85.333333h341.333334c47.786667 0 85.333333-37.546667 85.333333-85.333333V256c0-47.786667-37.546667-85.333333-85.333333-85.333333z m51.2 597.333333c0 29.013333-22.186667 51.2-51.2 51.2H341.333333c-29.013333 0-51.2-22.186667-51.2-51.2v-85.333333h443.733334v85.333333zM290.133333 648.533333h443.733334v-341.333333H290.133333v341.333333z m443.733334-375.466666H290.133333V256c0-29.013333 22.186667-51.2 51.2-51.2h341.333334c29.013333 0 51.2 22.186667 51.2 51.2v17.066667z m-221.866667 512c18.773333 0 34.133333-15.36 34.133333-34.133334 0-18.773333-15.36-34.133333-34.133333-34.133333-18.773333 0-34.133333 15.36-34.133333 34.133333 0 18.773333 15.36 34.133333 34.133333 34.133334z" fill="%23bfbfbf"></path></svg>');
+          }
+
+          .shield-icon {
+            background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23999'%3E%3Cpath d='M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z'/%3E%3C/svg%3E");
+          }
+
+          .custom-input {
+            flex: 1;
+            width: 100%;
+            height: 48px;
+            padding: 0 12px 0 40px;
+            border: 1px solid #ddd;
+            border-radius: 12px;
+            font-size: 15px;
+            box-sizing: border-box;
+            transition: border-color 0.3s;
+
+            &::placeholder {
+              color: #999;
+            }
+
+            &:focus {
+              background: #f7f7f8;
+            }
+          }
+        }
+
+        .code-container {
+          display: flex;
+          gap: 12px;
+
+          .input-container {
+            flex: 1;
+          }
+
+          .code-btn {
+            background: rgba(124, 58, 237, 0.1);
+            color: #7c3aed;
+            white-space: nowrap;
+            padding: 0 15px;
+            flex-shrink: 0;
+            height: var(--input-height);
+            border: none;
+            border-radius: 12px;
+            font-size: 15px;
+            font-weight: 500;
+            transition: all 0.3s;
+            cursor: pointer;
+            display: inline-flex;
+            align-items: center;
+            justify-content: center;
+            box-sizing: border-box;
+
+            &:disabled {
+              opacity: 0.5;
+              cursor: not-allowed;
+            }
+          }
+        }
+      }
+
+      .submit-btn {
+        background: linear-gradient(to right, #7c3aed, #3b82f6);
+        color: white;
+        width: 100%;
+        padding: 0;
+        margin-top: 10px;
+        height: 48px;
+        border: none;
+        border-radius: 12px;
+        font-size: 15px;
+        font-weight: 500;
+        transition: all 0.3s;
+        cursor: pointer;
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        box-sizing: border-box;
+
+        &:active {
+          opacity: 0.9;
+        }
+      }
+
+      .agreement-section {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 12px;
+        color: #666;
+
+        .checkbox-wrapper {
+          display: flex;
+          align-items: center;
+          cursor: pointer;
+
+          input[type="checkbox"] {
+            width: 14px;
+            height: 14px;
+            margin-right: 4px;
+            cursor: pointer;
+          }
+
+          span {
+            margin-right: 2px;
+          }
+        }
+
+        .agreement-link {
+          color: #666;
+          text-decoration: none;
+        }
+      }
+    }
+  }
+}

+ 44 - 9
src/pages/self/setting/index.tsx

@@ -9,9 +9,12 @@ import {
 import { View } from "@tarojs/components";
 import { ArrowLeft, ArrowRight } from "@nutui/icons-react-taro";
 import { getStorageSync, navigateBack, showToast } from "@tarojs/taro";
-import { sendCodeApi } from "../../../api/auth";
+import {
+  changePasswordApi,
+  sendChangePasswordCodeApi,
+} from "../../../api/auth";
 import "./index.scss";
-import { useState } from "react";
+import { useEffect, useState } from "react";
 
 export default function Setting() {
   const [showBottom, setShowBottom] = useState(false);
@@ -48,7 +51,9 @@ export default function Setting() {
     }
     try {
       // 调用发送验证码接口
-      await sendCodeApi(formData.phone);
+      await sendChangePasswordCodeApi({
+        phone: formData.phone,
+      });
 
       // 这里可以调用发送验证码的API
       showToast({
@@ -65,7 +70,33 @@ export default function Setting() {
       });
     }
   };
-  const userInfo = getStorageSync("vipInfo");
+
+  const handleSubmit = async (data: any) => {
+    await changePasswordApi({
+      user_name: data.user_name,
+      user_pwd: data.user_pwd,
+      phone: data.phone,
+      code: data.code.detail.value,
+    });
+    showToast({
+      title: "修改密码成功",
+      duration: 2000,
+      icon: "none",
+    });
+    setShowBottom(false);
+  };
+
+  useEffect(() => {
+    let info = getStorageSync("vipInfo");
+    setFormData({
+      user_name: info.user_name,
+      phone: info.phone,
+      code: "",
+      user_pwd: "",
+    });
+    form.setFieldValue("user_name", info.user_name);
+    form.setFieldValue("phone", info.phone);
+  }, []);
 
   return (
     <View>
@@ -103,19 +134,18 @@ export default function Setting() {
         }}
       >
         <View>
-          <Form form={form}>
+          <Form form={form} onFinish={(data) => handleSubmit(data)}>
             <Form.Item label="账号" name="user_name">
               <Input
                 placeholder="请输入账号"
                 readOnly={true}
                 value={formData.user_name}
-                defaultValue={userInfo.username}
                 onChange={(value) =>
                   setFormData({ ...formData, user_name: value })
                 }
               />
             </Form.Item>
-            <Form.Item label="新密码">
+            <Form.Item label="新密码" name="user_pwd">
               <Input
                 placeholder="请输入新密码"
                 value={formData.user_pwd}
@@ -145,7 +175,7 @@ export default function Setting() {
                   className="w-[100px] h-[40px] text-[14px] text-[#333]"
                   disabled={countdown > 0}
                   onClick={handleGetCode}
-                  size="mini"
+                  size="small"
                   type="primary"
                 >
                   {countdown > 0 ? `${countdown}s` : "获取验证码"}
@@ -153,7 +183,12 @@ export default function Setting() {
               </View>
             </Form.Item>
             <Form.Item>
-              <Button block type="primary" onClick={() => form.submit()}>
+              <Button
+                block
+                type="primary"
+                size="large"
+                onClick={() => form.submit}
+              >
                 提交
               </Button>
             </Form.Item>