浏览代码

小程序调试

skyline 1 月之前
父节点
当前提交
5915c1d3e4

+ 1 - 1
haha-miniapp/src/main/java/com/haha/miniapp/controller/PaymentController.java

@@ -27,7 +27,7 @@ import java.util.stream.Collectors;
  */
 @Slf4j
 @RestController
-@RequestMapping("/api/payment")
+@RequestMapping("/payment")
 public class PaymentController {
 
     @Autowired

+ 1 - 16
haha-mp/src/api/user.ts

@@ -23,22 +23,7 @@ export interface UserInfo {
 }
 
 /**
- * 账号密码登录(临时方案)
- */
-export const loginByPassword = (params: { phone: string; password: string }): Promise<LoginResult> => {
-  return post<LoginResult>('/login/password', params);
-};
-
-/**
- * 微信手机号一键登录
- * @param params { code, encryptedData, iv }
- */
-export const loginByWechatPhone = (params: { code: string; encryptedData?: string; iv?: string }): Promise<LoginResult> => {
-  return post<LoginResult>('/login/wechat-phone', params);
-};
-
-/**
- * 微信小程序手机号快速登录(新版)
+ * 微信小程序手机号快速登录
  * 使用button open-type="getPhoneNumber"获取手机号
  * @param params { code, phoneCode }
  * code: 微信登录凭证(用于获取openid)

+ 16 - 0
haha-mp/src/pages.json

@@ -96,6 +96,22 @@
 				"navigationBarBackgroundColor": "#FFD700",
 				"navigationBarTextStyle": "black"
 			}
+		},
+		{
+			"path": "pages/agreement/serviceAgreement",
+			"style": {
+				"navigationBarTitleText": "用户服务协议",
+				"navigationBarBackgroundColor": "#FFD700",
+				"navigationBarTextStyle": "black"
+			}
+		},
+		{
+			"path": "pages/agreement/privacyPolicy",
+			"style": {
+				"navigationBarTitleText": "隐私政策",
+				"navigationBarBackgroundColor": "#FFD700",
+				"navigationBarTextStyle": "black"
+			}
 		}
 	],
 	"globalStyle": {

+ 364 - 0
haha-mp/src/pages/agreement/privacyPolicy.vue

@@ -0,0 +1,364 @@
+<template>
+  <view class="container">
+    <scroll-view class="content-scroll" scroll-y>
+      <view class="content-wrapper">
+        <!-- 标题 -->
+        <view class="header">
+          <text class="title">隐私政策</text>
+          <text class="update-time">更新日期:2026年4月11日</text>
+          <text class="update-time">生效日期:2026年4月11日</text>
+        </view>
+
+        <!-- 提示 -->
+        <view class="notice-card">
+          <view class="notice-icon">🔒</view>
+          <text class="notice-text">
+            AI智能零售柜(以下简称"我们")深知个人信息对您的重要性,我们将按照法律法规要求,采取相应的安全保护措施,尽力保护您的个人信息安全可控。
+          </text>
+        </view>
+
+        <!-- 隐私政策内容 -->
+        <view class="section">
+          <text class="section-title">引言</text>
+          <text class="section-content">
+            本隐私政策将帮助您了解:
+          </text>
+          <text class="section-content sub-item">• 我们如何收集和使用您的个人信息</text>
+          <text class="section-content sub-item">• 我们如何存储和保护您的个人信息</text>
+          <text class="section-content sub-item">• 您如何管理自己的个人信息</text>
+          <text class="section-content sub-item">• 您的权利和我们的责任</text>
+          <text class="section-content">
+            请您在使用我们的服务前,仔细阅读并充分理解本政策。您点击"同意"或实际使用我们的服务,即表示您已理解并同意本政策的全部内容。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">一、我们如何收集和使用您的个人信息</text>
+          <text class="section-content">
+            1.1 账号注册与登录
+          </text>
+          <text class="section-content sub-item">
+            当您使用微信授权登录时,我们会从微信获取以下信息:
+          </text>
+          <text class="section-content sub-item">• 微信openid:用于唯一标识您的账号</text>
+          <text class="section-content sub-item">• 手机号码:用于账号注册、身份验证和服务通知</text>
+          <text class="section-content">
+            1.2 订单服务
+          </text>
+          <text class="section-content sub-item">
+            当您使用智能零售柜购物时,我们会收集:
+          </text>
+          <text class="section-content sub-item">• 订单信息:包括商品名称、数量、价格、购买时间等</text>
+          <text class="section-content sub-item">• 支付信息:包括支付金额、支付时间、支付状态等</text>
+          <text class="section-content sub-item">• 设备信息:包括设备编号、开门时间、关门时间等</text>
+          <text class="section-content">
+            1.3 客户服务
+          </text>
+          <text class="section-content sub-item">
+            当您申请退款或联系客服时,我们可能需要:
+          </text>
+          <text class="section-content sub-item">• 退款原因:用于改进服务和商品质量</text>
+          <text class="section-content sub-item">• 联系方式:用于处理您的投诉和建议</text>
+          <text class="section-content">
+            1.4 设备识别
+          </text>
+          <text class="section-content sub-item">
+            为了保证服务安全和防止作弊,我们会收集:
+          </text>
+          <text class="section-content sub-item">• 设备信息:包括设备型号、操作系统版本等</text>
+          <text class="section-content sub-item">• 网络信息:包括IP地址、网络类型等</text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">二、我们如何使用Cookie和类似技术</text>
+          <text class="section-content">
+            2.1 为确保服务正常运行、优化用户体验,我们会在您的设备上存储小型数据文件(如Cookie)。
+          </text>
+          <text class="section-content">
+            2.2 我们使用Cookie主要用于以下目的:
+          </text>
+          <text class="section-content sub-item">• 记住您的登录状态,避免重复登录</text>
+          <text class="section-content sub-item">• 保存您的偏好设置</text>
+          <text class="section-content sub-item">• 分析服务使用情况,优化产品功能</text>
+          <text class="section-content">
+            2.3 您可以通过浏览器设置管理或删除Cookie,但这可能会影响您使用某些功能。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">三、我们如何共享、转让、公开披露您的个人信息</text>
+          <text class="section-content">
+            3.1 共享
+          </text>
+          <text class="section-content sub-item">
+            我们不会与任何公司、组织和个人共享您的个人信息,但以下情况除外:
+          </text>
+          <text class="section-content sub-item">• 获得您的明确同意后</text>
+          <text class="section-content sub-item">• 与我们的关联公司共享(仅为本政策声明的目的)</text>
+          <text class="section-content sub-item">• 与授权合作伙伴共享(如微信支付,仅用于完成支付服务)</text>
+          <text class="section-content">
+            3.2 转让
+          </text>
+          <text class="section-content sub-item">
+            我们不会将您的个人信息转让给任何公司、组织和个人,但以下情况除外:
+          </text>
+          <text class="section-content sub-item">• 获得您的明确同意后</text>
+          <text class="section-content sub-item">• 在涉及合并、收购或破产清算时,如涉及个人信息转让,我们会要求新的持有方继续受本政策约束</text>
+          <text class="section-content">
+            3.3 公开披露
+          </text>
+          <text class="section-content sub-item">
+            我们仅会在以下情况下公开披露您的个人信息:
+          </text>
+          <text class="section-content sub-item">• 获得您的明确同意后</text>
+          <text class="section-content sub-item">• 基于法律法规、法律程序、诉讼或政府主管部门的强制性要求</text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">四、我们如何存储和保护您的个人信息</text>
+          <text class="section-content">
+            4.1 信息存储
+          </text>
+          <text class="section-content sub-item">
+            • 我们会按照法律法规规定,将境内收集的个人信息存储于中国境内
+          </text>
+          <text class="section-content sub-item">
+            • 我们只会在达成本政策所述目的所需的期限内保留您的个人信息,除非法律有强制的留存要求
+          </text>
+          <text class="section-content sub-item">
+            • 当我们的产品或服务发生停止运营的情形时,我们将以推送通知、公告等形式通知您,并在合理的期限内删除或匿名化处理您的个人信息
+          </text>
+          <text class="section-content">
+            4.2 信息安全
+          </text>
+          <text class="section-content sub-item">
+            我们已采取符合业界标准的安全防护措施保护您的个人信息:
+          </text>
+          <text class="section-content sub-item">• 数据传输加密:使用HTTPS、TLS等加密技术</text>
+          <text class="section-content sub-item">• 数据存储加密:敏感信息(如手机号)采用加密存储</text>
+          <text class="section-content sub-item">• 访问控制:严格限制数据访问权限,实行最小权限原则</text>
+          <text class="section-content sub-item">• 安全审计:定期进行安全评估和漏洞扫描</text>
+          <text class="section-content">
+            4.3 安全事件处置
+          </text>
+          <text class="section-content sub-item">
+            在不幸发生个人信息安全事件后,我们将按照法律法规的要求,及时向您告知:
+          </text>
+          <text class="section-content sub-item">• 安全事件的基本情况和可能的影响</text>
+          <text class="section-content sub-item">• 我们已采取或将要采取的处置措施</text>
+          <text class="section-content sub-item">• 您可自主防范和降低风险的建议</text>
+          <text class="section-content sub-item">• 对您的补救措施</text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">五、您的权利</text>
+          <text class="section-content">
+            5.1 访问和更新您的个人信息
+          </text>
+          <text class="section-content sub-item">
+            您有权通过以下方式访问和更新您的个人信息:
+          </text>
+          <text class="section-content sub-item">• 在"我的"页面查看和修改个人信息</text>
+          <text class="section-content sub-item">• 在"我的订单"页面查看订单记录</text>
+          <text class="section-content sub-item">• 在"我的优惠券"页面查看优惠券信息</text>
+          <text class="section-content">
+            5.2 删除您的个人信息
+          </text>
+          <text class="section-content sub-item">
+            在以下情形中,您可以向我们提出删除个人信息的请求:
+          </text>
+          <text class="section-content sub-item">• 我们处理个人信息的行为违反法律法规</text>
+          <text class="section-content sub-item">• 我们收集、使用您的个人信息,却未征得您的同意</text>
+          <text class="section-content sub-item">• 我们处理个人信息的行为违反了与您的约定</text>
+          <text class="section-content sub-item">• 您不再使用我们的服务</text>
+          <text class="section-content">
+            5.3 改变授权范围
+          </text>
+          <text class="section-content sub-item">
+            您可以通过以下方式改变您授权我们继续收集个人信息的范围:
+          </text>
+          <text class="section-content sub-item">• 在微信设置中关闭对本小程序的授权</text>
+          <text class="section-content sub-item">• 注销账号(详见5.4)</text>
+          <text class="section-content">
+            5.4 注销账号
+          </text>
+          <text class="section-content sub-item">
+            您有权随时注销已注册的账号,您可以通过联系客服申请注销。账号注销后:
+          </text>
+          <text class="section-content sub-item">• 我们将停止为您提供产品或服务</text>
+          <text class="section-content sub-item">• 我们将根据适用法律的要求删除或匿名化处理您的个人信息</text>
+          <text class="section-content sub-item">• 法律法规另有规定的除外</text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">六、未成年人保护</text>
+          <text class="section-content">
+            6.1 我们非常重视对未成年人个人信息的保护。
+          </text>
+          <text class="section-content">
+            6.2 若您是未满18周岁的未成年人,在使用我们的服务前,应在您的父母或其他监护人监护、指导下共同阅读并同意本隐私政策。
+          </text>
+          <text class="section-content">
+            6.3 对于经父母或其他监护人同意使用我们服务的未成年人,我们只会在法律法规允许、父母或其他监护人明确同意或保护未成年人所必要的范围内收集、使用、存储、共享或披露其个人信息。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">七、第三方服务</text>
+          <text class="section-content">
+            7.1 我们的服务可能会包含第三方提供的服务或链接,例如:
+          </text>
+          <text class="section-content sub-item">• 微信支付:用于完成订单支付</text>
+          <text class="section-content sub-item">• 微信登录:用于账号注册和身份验证</text>
+          <text class="section-content">
+            7.2 这些第三方服务有其独立的隐私政策,我们建议您在使用前仔细阅读。
+          </text>
+          <text class="section-content">
+            7.3 我们不对第三方的隐私政策或内容承担责任,但会努力评估其数据收集的合法性和安全性。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">八、本政策如何更新</text>
+          <text class="section-content">
+            8.1 我们可能会适时修订本隐私政策,修订后的内容将在小程序中公示。
+          </text>
+          <text class="section-content">
+            8.2 对于重大变更,我们还会通过推送通知、弹窗等显著方式告知您。
+          </text>
+          <text class="section-content">
+            8.3 重大变更包括但不限于:
+          </text>
+          <text class="section-content sub-item">• 我们的服务模式发生重大变化</text>
+          <text class="section-content sub-item">• 个人信息共享、转让或公开披露的主要对象发生变化</text>
+          <text class="section-content sub-item">• 您参与个人信息处理的权利及其行使方式发生重大变化</text>
+          <text class="section-content">
+            8.4 本政策所指的重大变更包括但不限于上述情形。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">九、如何联系我们</text>
+          <text class="section-content">
+            如您对本隐私政策有任何疑问、意见或建议,或需要行使您的权利,请通过以下方式联系我们:
+          </text>
+          <text class="section-content">客服电话:400-XXX-XXXX</text>
+          <text class="section-content">服务邮箱:privacy@ai-retail.com</text>
+          <text class="section-content">服务时间:周一至周日 9:00-21:00</text>
+          <text class="section-content">
+            一般情况下,我们将在15个工作日内回复您的请求。
+          </text>
+        </view>
+
+        <!-- 底部间距 -->
+        <view class="bottom-spacer"></view>
+      </view>
+    </scroll-view>
+  </view>
+</template>
+
+<script setup lang="ts">
+import { onLoad } from '@dcloudio/uni-app';
+
+onLoad(() => {
+  uni.setNavigationBarTitle({
+    title: '隐私政策'
+  });
+});
+</script>
+
+<style lang="scss" scoped>
+.container {
+  min-height: 100vh;
+  background: linear-gradient(180deg, #FFF9E6 0%, #FFFFFF 30%);
+}
+
+.content-scroll {
+  height: 100vh;
+}
+
+.content-wrapper {
+  padding: 40rpx 32rpx;
+}
+
+.header {
+  text-align: center;
+  margin-bottom: 40rpx;
+  padding-bottom: 32rpx;
+  border-bottom: 2rpx solid rgba(255, 193, 7, 0.2);
+  
+  .title {
+    display: block;
+    font-size: 44rpx;
+    font-weight: 700;
+    color: #1A1A1A;
+    margin-bottom: 20rpx;
+    letter-spacing: 2rpx;
+  }
+  
+  .update-time {
+    display: block;
+    font-size: 24rpx;
+    color: #999999;
+    margin-top: 8rpx;
+  }
+}
+
+.notice-card {
+  display: flex;
+  align-items: flex-start;
+  gap: 16rpx;
+  padding: 24rpx;
+  background: linear-gradient(135deg, #E3F2FD 0%, #BBDEFB 100%);
+  border-radius: 16rpx;
+  border-left: 6rpx solid #2196F3;
+  margin-bottom: 48rpx;
+  
+  .notice-icon {
+    font-size: 36rpx;
+    flex-shrink: 0;
+    margin-top: 4rpx;
+  }
+  
+  .notice-text {
+    flex: 1;
+    font-size: 26rpx;
+    color: #1565C0;
+    line-height: 1.8;
+  }
+}
+
+.section {
+  margin-bottom: 48rpx;
+  
+  .section-title {
+    display: block;
+    font-size: 32rpx;
+    font-weight: 700;
+    color: #1A1A1A;
+    margin-bottom: 24rpx;
+    padding-left: 16rpx;
+    border-left: 6rpx solid #FFC107;
+    line-height: 1.4;
+  }
+  
+  .section-content {
+    display: block;
+    font-size: 28rpx;
+    color: #555555;
+    line-height: 1.8;
+    margin-bottom: 16rpx;
+    text-align: justify;
+    
+    &.sub-item {
+      padding-left: 32rpx;
+      color: #666666;
+      font-size: 26rpx;
+    }
+  }
+}
+
+.bottom-spacer {
+  height: 100rpx;
+}
+</style>

+ 303 - 0
haha-mp/src/pages/agreement/serviceAgreement.vue

@@ -0,0 +1,303 @@
+<template>
+  <view class="container">
+    <scroll-view class="content-scroll" scroll-y>
+      <view class="content-wrapper">
+        <!-- 标题 -->
+        <view class="header">
+          <text class="title">用户服务协议</text>
+          <text class="update-time">更新日期:2026年4月11日</text>
+          <text class="update-time">生效日期:2026年4月11日</text>
+        </view>
+
+        <!-- 提示 -->
+        <view class="notice-card">
+          <view class="notice-icon">⚠️</view>
+          <text class="notice-text">
+            请您在注册使用本服务前,仔细阅读并充分理解本协议的全部内容。
+            您点击"同意"或实际使用本服务,即表示您已阅读并同意接受本协议的全部内容。
+          </text>
+        </view>
+
+        <!-- 协议内容 -->
+        <view class="section">
+          <text class="section-title">一、服务的接受</text>
+          <text class="section-content">
+            1.1 本协议是您与AI智能零售柜服务提供者(以下简称"我们")之间关于使用本服务所订立的协议。
+          </text>
+          <text class="section-content">
+            1.2 本服务包括智能零售柜商品选购、在线支付、订单管理、售后服务等功能。
+          </text>
+          <text class="section-content">
+            1.3 我们有权根据业务发展需要,随时调整服务内容,调整后的服务将在小程序中公示。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">二、账号注册与使用</text>
+          <text class="section-content">
+            2.1 您需要通过微信授权登录本服务,我们将从微信获取您的手机号用于账号注册和身份验证。
+          </text>
+          <text class="section-content">
+            2.2 您应保证注册信息的真实性、准确性和完整性,并及时更新相关信息。
+          </text>
+          <text class="section-content">
+            2.3 您的账号仅供您本人使用,不得以任何形式转让、借用或分享给他人。
+          </text>
+          <text class="section-content">
+            2.4 您应对账号下的所有行为承担法律责任,包括但不限于商品选购、订单支付等。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">三、服务使用规则</text>
+          <text class="section-content">
+            3.1 您在使用本服务时,应遵守国家法律法规及本协议的各项规定。
+          </text>
+          <text class="section-content">
+            3.2 您通过智能零售柜选购商品时,应遵循"即拿即走"的使用流程,不得损坏设备或商品。
+          </text>
+          <text class="section-content">
+            3.3 您应确保微信支付分处于正常开通状态,以便完成自动扣款。
+          </text>
+          <text class="section-content">
+            3.4 您不得利用本服务从事任何违法违规活动,包括但不限于:
+          </text>
+          <text class="section-content sub-item">(1)窃取、破坏他人财物;</text>
+          <text class="section-content sub-item">(2)恶意损坏智能零售柜设备;</text>
+          <text class="section-content sub-item">(3)利用技术手段规避支付流程;</text>
+          <text class="section-content sub-item">(4)其他违反法律法规的行为。</text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">四、商品与价格</text>
+          <text class="section-content">
+            4.1 智能零售柜内商品的价格以柜内标示为准,我们有权根据市场情况调整商品价格。
+          </text>
+          <text class="section-content">
+            4.2 商品价格可能因促销活动、优惠券使用等因素有所变动,具体以订单结算页面显示为准。
+          </text>
+          <text class="section-content">
+            4.3 如因系统故障导致商品价格出现明显错误,我们有权取消相关订单并退还已支付款项。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">五、支付与结算</text>
+          <text class="section-content">
+            5.1 您选购商品后,系统将自动通过微信支付从您的账户中扣取相应款项。
+          </text>
+          <text class="section-content">
+            5.2 您应确保微信账户余额充足或绑定的支付方式可用,以便顺利完成支付。
+          </text>
+          <text class="section-content">
+            5.3 如因您账户余额不足导致支付失败,我们有权暂停您的服务使用权限。
+          </text>
+          <text class="section-content">
+            5.4 支付完成后,您可以在"我的订单"中查看订单详情和支付记录。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">六、退款与售后</text>
+          <text class="section-content">
+            6.1 如您对所购商品有异议,可在订单完成后24小时内申请退款。
+          </text>
+          <text class="section-content">
+            6.2 退款申请需说明具体原因,我们将在收到申请后48小时内处理。
+          </text>
+          <text class="section-content">
+            6.3 退款成功后,款项将原路返回至您的支付账户。
+          </text>
+          <text class="section-content">
+            6.4 以下情况不支持退款:
+          </text>
+          <text class="section-content sub-item">(1)超过退款申请时限;</text>
+          <text class="section-content sub-item">(2)商品已开封且影响二次销售;</text>
+          <text class="section-content sub-item">(3)非质量问题的主观退款。</text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">七、用户信用管理</text>
+          <text class="section-content">
+            7.1 我们为用户建立信用评分体系,初始信用分为100分。
+          </text>
+          <text class="section-content">
+            7.2 以下行为将导致信用分降低:
+          </text>
+          <text class="section-content sub-item">(1)支付失败或拒绝支付;</text>
+          <text class="section-content sub-item">(2)恶意损坏设备或商品;</text>
+          <text class="section-content sub-item">(3)频繁申请不合理退款;</text>
+          <text class="section-content sub-item">(4)其他违反本协议的行为。</text>
+          <text class="section-content">
+            7.3 当信用分低于60分时,我们有权暂停或终止向您提供服务。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">八、知识产权</text>
+          <text class="section-content">
+            8.1 本服务所涉及的所有内容,包括但不限于软件、技术、程序、网页、文字、图片、音频、视频、图表等,均受知识产权法律法规保护。
+          </text>
+          <text class="section-content">
+            8.2 未经我们书面许可,您不得以任何形式复制、传播、展示、修改本服务的内容。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">九、免责声明</text>
+          <text class="section-content">
+            9.1 因不可抗力(如自然灾害、战争、政府行为等)导致服务中断或数据丢失,我们不承担责任。
+          </text>
+          <text class="section-content">
+            9.2 因网络故障、设备故障、系统升级等原因导致的服务中断,我们将尽快修复,但不承担由此产生的间接损失。
+          </text>
+          <text class="section-content">
+            9.3 您使用本服务所做出的任何决定及据此采取的行动由您自行负责。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">十、协议变更</text>
+          <text class="section-content">
+            10.1 我们有权根据业务发展需要修改本协议条款。
+          </text>
+          <text class="section-content">
+            10.2 协议修改后,我们将在小程序中公示,公示期不少于7日。
+          </text>
+          <text class="section-content">
+            10.3 公示期届满后,修改后的协议即生效。如您不同意修改后的协议,有权停止使用本服务。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">十一、法律适用与争议解决</text>
+          <text class="section-content">
+            11.1 本协议的订立、执行、解释及争议解决均适用中华人民共和国法律。
+          </text>
+          <text class="section-content">
+            11.2 因本协议引起的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向我们所在地有管辖权的人民法院提起诉讼。
+          </text>
+        </view>
+
+        <view class="section">
+          <text class="section-title">十二、联系我们</text>
+          <text class="section-content">
+            如您对本协议有任何疑问或需要帮助,请通过以下方式联系我们:
+          </text>
+          <text class="section-content">客服电话:400-XXX-XXXX</text>
+          <text class="section-content">服务邮箱:service@ai-retail.com</text>
+          <text class="section-content">服务时间:周一至周日 9:00-21:00</text>
+        </view>
+
+        <!-- 底部间距 -->
+        <view class="bottom-spacer"></view>
+      </view>
+    </scroll-view>
+  </view>
+</template>
+
+<script setup lang="ts">
+import { onLoad } from '@dcloudio/uni-app';
+
+onLoad(() => {
+  uni.setNavigationBarTitle({
+    title: '用户服务协议'
+  });
+});
+</script>
+
+<style lang="scss" scoped>
+.container {
+  min-height: 100vh;
+  background: linear-gradient(180deg, #FFF9E6 0%, #FFFFFF 30%);
+}
+
+.content-scroll {
+  height: 100vh;
+}
+
+.content-wrapper {
+  padding: 40rpx 32rpx;
+}
+
+.header {
+  text-align: center;
+  margin-bottom: 40rpx;
+  padding-bottom: 32rpx;
+  border-bottom: 2rpx solid rgba(255, 193, 7, 0.2);
+  
+  .title {
+    display: block;
+    font-size: 44rpx;
+    font-weight: 700;
+    color: #1A1A1A;
+    margin-bottom: 20rpx;
+    letter-spacing: 2rpx;
+  }
+  
+  .update-time {
+    display: block;
+    font-size: 24rpx;
+    color: #999999;
+    margin-top: 8rpx;
+  }
+}
+
+.notice-card {
+  display: flex;
+  align-items: flex-start;
+  gap: 16rpx;
+  padding: 24rpx;
+  background: linear-gradient(135deg, #FFF3CD 0%, #FFE69C 100%);
+  border-radius: 16rpx;
+  border-left: 6rpx solid #FFC107;
+  margin-bottom: 48rpx;
+  
+  .notice-icon {
+    font-size: 36rpx;
+    flex-shrink: 0;
+    margin-top: 4rpx;
+  }
+  
+  .notice-text {
+    flex: 1;
+    font-size: 26rpx;
+    color: #856404;
+    line-height: 1.8;
+  }
+}
+
+.section {
+  margin-bottom: 48rpx;
+  
+  .section-title {
+    display: block;
+    font-size: 32rpx;
+    font-weight: 700;
+    color: #1A1A1A;
+    margin-bottom: 24rpx;
+    padding-left: 16rpx;
+    border-left: 6rpx solid #FFC107;
+    line-height: 1.4;
+  }
+  
+  .section-content {
+    display: block;
+    font-size: 28rpx;
+    color: #555555;
+    line-height: 1.8;
+    margin-bottom: 16rpx;
+    text-align: justify;
+    
+    &.sub-item {
+      padding-left: 32rpx;
+      color: #666666;
+      font-size: 26rpx;
+    }
+  }
+}
+
+.bottom-spacer {
+  height: 100rpx;
+}
+</style>

+ 54 - 24
haha-mp/src/pages/index/index.vue

@@ -42,10 +42,10 @@
     <!-- 底部信息卡片 -->
     <view class="info-card">
       <view class="info-item">
-        <text class="info-icon">💚</text>
+        <image class="info-icon payscore-icon" src="/static/icons/payscore.svg" mode="aspectFit"></image>
         <text class="info-text">微信支付分 550分及以上优享</text>
       </view>
-      <view class="info-item">
+      <view class="info-item" @tap="callService">
         <text class="info-icon">📞</text>
         <text class="info-text">客服: 400-0759-515</text>
       </view>
@@ -230,6 +230,26 @@ const goToCouponCenter = () => {
     url: '/pages/couponCenter/couponCenter'
   })
 }
+
+// 拨打客服电话
+const callService = () => {
+  uni.vibrateShort({ type: 'light' })
+  uni.makePhoneCall({
+    phoneNumber: '4000759515',
+    success: () => {
+      console.log('[首页] 拨号成功')
+    },
+    fail: (err) => {
+      console.error('[首页] 拨号失败:', err)
+      if (err.errMsg.indexOf('cancel') === -1) {
+        uni.showToast({
+          title: '拨号失败',
+          icon: 'none'
+        })
+      }
+    }
+  })
+}
 </script>
 
 <style lang="scss">
@@ -249,7 +269,9 @@ const goToCouponCenter = () => {
   text-align: center;
   padding: $spacing-xxl 0 $spacing-xl;
   animation: slideUp 0.6s cubic-bezier(0.25, 0.1, 0.25, 1);
-  
+  will-change: transform, opacity;
+  transform: translateZ(0);
+
   .brand-title {
     font-size: 56rpx;
     font-weight: 300;
@@ -258,7 +280,7 @@ const goToCouponCenter = () => {
     display: block;
     margin-bottom: $spacing-sm;
   }
-  
+
   .brand-slogan {
     font-size: 24rpx;
     color: $color-text-secondary;
@@ -272,7 +294,9 @@ const goToCouponCenter = () => {
   justify-content: center;
   align-items: center;
   padding: $spacing-xl 0;
-  animation: scaleIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55);
+  animation: scaleIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55) 0.2s both;
+  will-change: transform, opacity;
+  transform: translateZ(0);
 }
 
 .scan-button {
@@ -320,8 +344,8 @@ const goToCouponCenter = () => {
     border-radius: 50%;
     background: $color-primary;
     transform: translate(-50%, -50%);
-    animation: pulse 2s cubic-bezier(0.42, 0, 0.58, 1) infinite;
-    opacity: 0.3;
+    animation: pulse 3s cubic-bezier(0.42, 0, 0.58, 1) infinite;
+    opacity: 0.2;
     z-index: -1;
   }
 }
@@ -348,23 +372,24 @@ const goToCouponCenter = () => {
   align-items: center;
   gap: $spacing-xl;
   margin: $spacing-xxl 0;
-  animation: slideUp 1s cubic-bezier(0.25, 0.1, 0.25, 1);
-  
+  animation: slideUp 1s cubic-bezier(0.25, 0.1, 0.25, 1) 0.4s both;
+  will-change: transform, opacity;
+  transform: translateZ(0);
+
   &-item {
     display: flex;
     flex-direction: column;
     align-items: center;
     justify-content: center;
     padding: $spacing-md;
-    transition: all $duration-fast $ease-out;
     position: relative;
     flex: 0 0 auto;
-    
+
     &:active {
-      transform: scale(0.9);
+      opacity: 0.8;
     }
   }
-  
+
   .action-icon {
     width: 120rpx;
     height: 120rpx;
@@ -375,23 +400,21 @@ const goToCouponCenter = () => {
     justify-content: center;
     box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
     margin-bottom: $spacing-sm;
-    transition: all $duration-fast $ease-out;
     border: 2rpx solid #F0F0F0;
     flex-shrink: 0;
-    
+
     image {
       width: 64rpx;
       height: 64rpx;
       display: block;
     }
-    
+
     &:active {
       box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
-      transform: translateY(-4rpx);
       border-color: $color-primary-light;
     }
   }
-  
+
   .action-label {
     font-size: 28rpx;
     color: $color-text-primary;
@@ -408,37 +431,44 @@ const goToCouponCenter = () => {
   border-radius: $radius-lg;
   padding: $spacing-lg;
   box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
-  animation: slideUp 1.2s cubic-bezier(0.25, 0.1, 0.25, 1);
+  animation: slideUp 1.2s cubic-bezier(0.25, 0.1, 0.25, 1) 0.6s both;
   margin-top: auto;
   width: 100%;
   box-sizing: border-box;
+  will-change: transform, opacity;
+  transform: translateZ(0);
   
   .info-item {
     display: flex;
     align-items: center;
+    justify-content: center;
     padding: $spacing-sm 0;
     min-height: 60rpx;
-    
+
     &:not(:last-child) {
       border-bottom: 1rpx solid $color-border;
       padding-bottom: $spacing-md;
       margin-bottom: $spacing-md;
     }
   }
-  
+
   .info-icon {
     font-size: 28rpx;
     margin-right: $spacing-sm;
     flex-shrink: 0;
     line-height: 1;
+
+    &.payscore-icon {
+      width: 36rpx;
+      height: 36rpx;
+    }
   }
-  
+
   .info-text {
     font-size: 24rpx;
     color: $color-text-secondary;
     line-height: 1.5;
-    flex: 1;
-    word-break: break-all;
+    text-align: center;
   }
 }
 </style>

+ 495 - 268
haha-mp/src/pages/login/login.vue

@@ -1,100 +1,106 @@
 <template>
   <view class="container">
-    <!-- 品牌区 -->
-    <view class="brand-section">
-      <view class="brand-logo">
-        <image class="logo" src="/static/brand-logo.svg" mode="aspectFit"></image>
+    <!-- 动态背景层 -->
+    <view class="bg-layer">
+      <view class="gradient-orb orb-1"></view>
+      <view class="gradient-orb orb-2"></view>
+      <view class="gradient-orb orb-3"></view>
+      <view class="wave-container">
+        <view class="wave wave-1"></view>
+        <view class="wave wave-2"></view>
       </view>
-      <text class="brand-title">欢迎登录</text>
-      <text class="brand-subtitle">快与慢充电桩 · 智能视觉零售柜</text>
     </view>
 
-    <!-- 登录表单 -->
-    <view class="form-section">
-      <view class="form-card">
-        <!-- 微信手机号快速登录按钮 -->
-        <button 
-          class="wechat-login-btn" 
-          open-type="getPhoneNumber" 
-          @getphonenumber="onGetPhoneNumber"
-          :loading="isLoading"
-        >
-          <text class="btn-icon">📱</text>
-          <text class="btn-text">微信手机号快速登录</text>
-        </button>
-
-        <!-- 分隔线 -->
-        <view class="divider">
-          <view class="divider-line"></view>
-          <text class="divider-text">或</text>
-          <view class="divider-line"></view>
-        </view>
-
-        <!-- 传统账号密码登录 -->
-        <view class="form-item">
-          <view class="input-wrapper">
-            <view class="input-icon">
-              <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
-                <path d="M20 21V19C20 17.8954 19.1046 17 18 17H6C4.89543 17 4 17.8954 4 19V21" stroke="#8C8C8C" stroke-width="2" stroke-linecap="round"/>
-                <circle cx="12" cy="7" r="4" stroke="#8C8C8C" stroke-width="2"/>
-              </svg>
+    <!-- 主内容区 -->
+    <view class="main-content">
+      <!-- 品牌展示区 -->
+      <view class="brand-showcase">
+        <view class="logo-wrapper">
+          <!-- 外层装饰环 -->
+          <view class="logo-outer-ring">
+            <!-- 内层装饰环 -->
+            <view class="logo-inner-ring">
+              <!-- 光晕效果 -->
+              <view class="logo-glow"></view>
+              <!-- Logo主体 -->
+              <view class="logo-circle">
+                <image class="logo" src="/static/brand-logo.svg" mode="aspectFit"></image>
+              </view>
             </view>
-            <input
-              class="form-input"
-              type="number"
-              placeholder="请输入手机号"
-              v-model="loginForm.phone"
-              maxlength="11"
-              placeholder-class="input-placeholder"
-            />
           </view>
         </view>
         
-        <view class="form-item">
-          <view class="input-wrapper">
-            <view class="input-icon">
-              <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
-                <rect x="3" y="11" width="18" height="11" rx="2" stroke="#8C8C8C" stroke-width="2"/>
-                <path d="M7 11V7C7 4.23858 9.23858 2 12 2C14.7614 2 17 4.23858 17 7V11" stroke="#8C8C8C" stroke-width="2" stroke-linecap="round"/>
-              </svg>
-            </view>
-            <input
-              class="form-input"
-              type="password"
-              placeholder="请输入密码"
-              v-model="loginForm.password"
-              placeholder-class="input-placeholder"
-            />
+        <view class="brand-text-group">
+          <text class="brand-subtitle">AI智能零售柜 · 即拿即走</text>
+        </view>
+        
+        <view class="feature-tags">
+          <view class="tag">
+            <text class="tag-icon">⚡</text>
+            <text class="tag-text">秒级开门</text>
           </view>
+          <view class="tag">
+            <text class="tag-icon">🔒</text>
+            <text class="tag-text">安全支付</text>
+          </view>
+          <view class="tag">
+            <text class="tag-icon">🤖</text>
+            <text class="tag-text">AI识别</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- 登录卡片 -->
+      <view class="login-card">
+        <view class="card-header">
+          <view class="header-line"></view>
+          <text class="card-title">快速登录</text>
+          <view class="header-line"></view>
         </view>
 
-        <button class="login-btn" @click="onPasswordLogin" :loading="isLoading">
-          <text class="btn-text">账号密码登录</text>
+        <!-- 微信手机号快速登录按钮 -->
+        <button
+          class="wechat-login-btn"
+          open-type="getPhoneNumber"
+          @getphonenumber="onGetPhoneNumber"
+          :loading="isLoading"
+          hover-class="btn-hover"
+        >
+          <view class="btn-shine"></view>
+          <text class="btn-text">一键登录</text>
         </button>
       </view>
 
       <!-- 用户协议 -->
-      <view class="agreement">
-        <text class="agreement-text">登录即代表您同意</text>
-        <text class="agreement-link">《用户协议》</text>
-        <text class="agreement-text">和</text>
-        <text class="agreement-link">《隐私政策》</text>
+      <view class="agreement-section">
+        <view class="agreement-card">
+          <text class="agreement-prefix">登录即表示您已阅读并同意</text>
+          <view class="agreement-links">
+            <text class="link-item" @tap="goToServiceAgreement">《用户服务协议》</text>
+            <text class="link-sep">与</text>
+            <text class="link-item" @tap="goToPrivacyPolicy">《隐私政策》</text>
+          </view>
+        </view>
+      </view>
+
+      <!-- 底部装饰 -->
+      <view class="footer-decoration">
+        <view class="dot-pattern">
+          <view class="dot"></view>
+          <view class="dot"></view>
+          <view class="dot"></view>
+        </view>
       </view>
     </view>
   </view>
 </template>
 
 <script setup lang="ts">
-import { ref, reactive } from 'vue';
+import { ref } from 'vue';
 import { onLoad } from '@dcloudio/uni-app';
-import { loginByPassword, loginByMiniappPhone } from '@/api/user';
+import { loginByMiniappPhone } from '@/api/user';
 import { setToken, setUserInfo } from '@/utils/auth';
 
-const loginForm = reactive({
-  phone: '',
-  password: ''
-});
-
 const isLoading = ref(false);
 
 // 登录后跳转的页面
@@ -107,38 +113,11 @@ onLoad((options: any) => {
   }
 });
 
-const onPasswordLogin = async () => {
-  if (!loginForm.phone || loginForm.phone.length !== 11) {
-    uni.showToast({ title: '请输入正确的手机号', icon: 'none' });
-    return;
-  }
-  if (!loginForm.password) {
-    uni.showToast({ title: '请输入密码', icon: 'none' });
-    return;
-  }
-
-  isLoading.value = true;
-  uni.showLoading({ title: '登录中...' });
-  
-  try {
-    const res = await loginByPassword({
-      phone: loginForm.phone,
-      password: loginForm.password
-    });
-    handleLoginSuccess(res);
-  } catch (error) {
-    console.error('登录失败', error);
-  } finally {
-    uni.hideLoading();
-    isLoading.value = false;
-  }
-};
-
-/**
- * 微信手机号快捷登录
- */
 const onGetPhoneNumber = async (e: any) => {
+  console.log('[登录] 获取手机号事件:', e.detail);
+  
   if (e.detail.errMsg !== 'getPhoneNumber:ok') {
+    console.error('[登录] 获取手机号失败:', e.detail.errMsg);
     uni.showToast({
       title: '获取手机号失败,请重试',
       icon: 'none'
@@ -151,63 +130,53 @@ const onGetPhoneNumber = async (e: any) => {
   
   try {
     // 获取登录code
+    console.log('[登录] 开始获取login code...');
     const loginRes = await new Promise<any>((resolve, reject) => {
       uni.login({
         provider: 'weixin',
-        success: resolve,
-        fail: reject
+        success: (res) => {
+          console.log('[登录] login成功:', res);
+          resolve(res);
+        },
+        fail: (err) => {
+          console.error('[登录] login失败:', err);
+          reject(err);
+        }
       });
     });
     
+    console.log('[登录] loginRes:', loginRes);
+    console.log('[登录] phoneCode:', e.detail.code);
+    
     const { code, encryptedData, iv } = e.detail;
     const res = await loginByMiniappPhone({ 
-      code: loginRes.code,  // 用于获取openid
-      phoneCode: code       // 用于获取手机号
+      code: loginRes.code,
+      phoneCode: code
     });
+    console.log('[登录] 登录成功:', res);
     handleLoginSuccess(res);
-  } catch (error) {
-    console.error('微信手机号登录失败', error);
-  } finally {
-    uni.hideLoading();
-    isLoading.value = false;
-  }
-};
-
-/**
- * 微信手机号快捷登录 (已禁用)
- */
-/*
-const onGetPhoneNumber = async (e: any) => {
-  if (e.detail.errMsg !== 'getPhoneNumber:ok') {
+  } catch (error: any) {
+    console.error('[登录] 微信手机号登录失败', error);
+    console.error('[登录] 错误详情:', error.message || error);
     uni.showToast({
-      title: '登录失败,请重试',
-      icon: 'none'
+      title: error.message || '登录失败,请重试',
+      icon: 'none',
+      duration: 3000
     });
-    return;
-  }
-  const { code, encryptedData, iv } = e.detail;
-  uni.showLoading({ title: '登录中...' });
-  try {
-    const res = await loginByWechatPhone({ code, encryptedData, iv });
-    handleLoginSuccess(res);
-  } catch (error) {
-    console.error('登录失败', error);
   } finally {
     uni.hideLoading();
+    isLoading.value = false;
   }
 };
-*/
 
 const handleLoginSuccess = (res: any) => {
   console.log('[登录成功] 收到的响应数据:', res);
   console.log('[登录成功] token:', res.token);
   console.log('[登录成功] userInfo:', res.userInfo);
 
-  // 使用auth工具保存token和用户信息
   setToken(res.token);
   setUserInfo(res.userInfo);
 
-  // 验证保存是否成功
   const savedToken = uni.getStorageSync('accessToken');
   console.log('[登录成功] 保存后验证 - token:', savedToken ? '已保存' : '保存失败');
 
@@ -218,12 +187,10 @@ const handleLoginSuccess = (res: any) => {
     icon: 'success'
   });
 
-  // 根据redirect参数跳转
   setTimeout(() => {
     if (redirectUrl.value) {
       uni.reLaunch({ url: redirectUrl.value });
     } else {
-      // 返回上一页或首页
       const pages = getCurrentPages();
       if (pages.length > 1) {
         uni.navigateBack();
@@ -233,208 +200,468 @@ const handleLoginSuccess = (res: any) => {
     }
   }, 1000);
 };
+
+// 跳转到用户服务协议
+const goToServiceAgreement = () => {
+  uni.navigateTo({
+    url: '/pages/agreement/serviceAgreement'
+  });
+};
+
+// 跳转到隐私政策
+const goToPrivacyPolicy = () => {
+  uni.navigateTo({
+    url: '/pages/agreement/privacyPolicy'
+  });
+};
 </script>
 
 <style lang="scss">
 .container {
+  min-height: 100vh;
+  background: linear-gradient(180deg, #FFFBF0 0%, #FFF9E6 30%, #FFFFFF 70%);
+  position: relative;
+  overflow: hidden;
+}
+
+/* ========== 动态背景层 ========== */
+.bg-layer {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 0;
+  pointer-events: none;
+  contain: layout style paint;
+}
+
+.gradient-orb {
+  position: absolute;
+  border-radius: 50%;
+  will-change: transform, opacity;
+  transform: translateZ(0);
+  backface-visibility: hidden;
+
+  &.orb-1 {
+    width: 500rpx;
+    height: 500rpx;
+    background: radial-gradient(circle, rgba(255, 215, 0, 0.2) 0%, transparent 70%);
+    top: -150rpx;
+    right: -100rpx;
+    animation: float 8s ease-in-out infinite;
+  }
+
+  &.orb-2 {
+    width: 400rpx;
+    height: 400rpx;
+    background: radial-gradient(circle, rgba(255, 193, 7, 0.15) 0%, transparent 70%);
+    top: 200rpx;
+    left: -120rpx;
+    animation: float 10s ease-in-out infinite reverse;
+  }
+
+  &.orb-3 {
+    width: 350rpx;
+    height: 350rpx;
+    background: radial-gradient(circle, rgba(255, 235, 59, 0.12) 0%, transparent 70%);
+    bottom: 200rpx;
+    right: -80rpx;
+    animation: float 12s ease-in-out infinite 2s;
+  }
+}
+
+.wave-container {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  height: 400rpx;
+  overflow: hidden;
+}
+
+.wave {
+  position: absolute;
+  bottom: 0;
+  left: -50%;
+  width: 200%;
+  height: 400rpx;
+  background: linear-gradient(180deg, transparent 0%, rgba(255, 215, 0, 0.05) 100%);
+  border-radius: 45% 48% 43% 47%;
+  animation: wave 15s linear infinite;
+
+  &.wave-2 {
+    display: none; /* 移除第二道波浪以提升性能 */
+  }
+}
+
+/* ========== 主内容区 ========== */
+.main-content {
+  position: relative;
+  z-index: 1;
   display: flex;
   flex-direction: column;
-  min-height: 100vh;
-  background: linear-gradient(180deg, $color-primary-bg 0%, $color-bg-secondary 40%);
-  padding: 0;
+  padding: 0 40rpx;
+  padding-bottom: calc(160rpx + constant(safe-area-inset-bottom));
+  padding-bottom: calc(160rpx + env(safe-area-inset-bottom));
 }
 
-/* ========== 品牌区 ========== */
-.brand-section {
+/* ========== 品牌展示区 ========== */
+.brand-showcase {
   display: flex;
   flex-direction: column;
   align-items: center;
-  padding: 120rpx 40rpx 80rpx;
-  animation: slideDown 0.6s cubic-bezier(0.25, 0.1, 0.25, 1);
-
-  .brand-logo {
-    width: 160rpx;
-    height: 160rpx;
-    margin-bottom: $spacing-lg;
-    animation: scaleIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55);
-    
-    .logo {
-      width: 100%;
-      height: 100%;
+  padding-top: 160rpx;
+  padding-bottom: 80rpx;
+  animation: slideDown 0.8s cubic-bezier(0.25, 0.1, 0.25, 1);
+}
+
+.logo-wrapper {
+  margin-bottom: 56rpx;
+  will-change: transform;
+  transform: translateZ(0);
+
+  .logo-outer-ring {
+    width: 280rpx;
+    height: 280rpx;
+    border-radius: 50%;
+    border: 2rpx solid rgba(255, 215, 0, 0.25);
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    animation: ringRotate 20s linear infinite;
+
+    .logo-inner-ring {
+      width: 256rpx;
+      height: 256rpx;
+      border-radius: 50%;
+      border: 2rpx dashed rgba(255, 215, 0, 0.3);
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      position: relative;
+
+      .logo-glow {
+        position: absolute;
+        width: 240rpx;
+        height: 240rpx;
+        border-radius: 50%;
+        background: radial-gradient(circle, rgba(255, 215, 0, 0.15) 0%, transparent 70%);
+        /* 移除filter: blur()以提升性能 */
+        opacity: 0.8;
+        animation: pulse 4s ease-in-out infinite;
+      }
+
+      .logo-circle {
+        width: 220rpx;
+        height: 220rpx;
+        background: linear-gradient(135deg, #FFFFFF 0%, #FFFEF5 100%);
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        box-shadow:
+          0 16rpx 40rpx rgba(255, 193, 7, 0.2),
+          inset 0 2rpx 8rpx rgba(255, 255, 255, 0.6);
+        padding: 28rpx;
+        position: relative;
+        z-index: 1;
+
+        .logo {
+          width: 100%;
+          height: 100%;
+          /* 移除drop-shadow滤镜 */
+        }
+      }
     }
   }
+}
 
+.brand-text-group {
+  text-align: center;
+  margin-bottom: 48rpx;
+  
   .brand-title {
-    font-size: 48rpx;
-    font-weight: 300;
-    color: $color-text-primary;
-    margin-bottom: $spacing-sm;
+    font-size: 56rpx;
+    font-weight: 700;
+    background: linear-gradient(135deg, #333333 0%, #666666 100%);
+    -webkit-background-clip: text;
+    -webkit-text-fill-color: transparent;
+    background-clip: text;
     letter-spacing: 4rpx;
+    display: block;
+    margin-bottom: 16rpx;
   }
-
+  
   .brand-subtitle {
-    font-size: 24rpx;
-    color: $color-text-secondary;
+    font-size: 26rpx;
+    color: #888888;
     letter-spacing: 2rpx;
+    font-weight: 400;
   }
 }
 
-/* ========== 表单区 ========== */
-.form-section {
-  flex: 1;
-  padding: 0 40rpx;
-  animation: slideUp 0.8s cubic-bezier(0.25, 0.1, 0.25, 1);
-}
-
-.form-card {
-  background: $color-bg-primary;
-  border-radius: $radius-xl;
-  padding: $spacing-xl;
-  box-shadow: $shadow-md;
-  margin-bottom: $spacing-lg;
-}
-
-.form-item {
-  margin-bottom: $spacing-lg;
+.feature-tags {
+  display: flex;
+  gap: 20rpx;
+  justify-content: center;
 
-  .input-wrapper {
+  .tag {
     display: flex;
     align-items: center;
-    background: $color-bg-secondary;
-    border-radius: $radius-lg;
-    padding: 0 $spacing-md;
-    transition: all $duration-fast $ease-out;
-    border: 2rpx solid transparent;
-
-    &:focus-within {
-      background: $color-bg-primary;
-      border-color: $color-primary;
-      box-shadow: 0 0 0 4rpx rgba(255, 193, 7, 0.1);
+    gap: 8rpx;
+    padding: 12rpx 20rpx;
+    background: rgba(255, 255, 255, 0.9);
+    border-radius: 40rpx;
+    box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
+    border: 1rpx solid rgba(255, 215, 0, 0.2);
+
+    .tag-icon {
+      font-size: 24rpx;
     }
 
-    .input-icon {
-      width: 40rpx;
-      height: 40rpx;
-      margin-right: $spacing-sm;
-      flex-shrink: 0;
-      
-      svg {
-        width: 100%;
-        height: 100%;
-      }
+    .tag-text {
+      font-size: 22rpx;
+      color: #555555;
+      font-weight: 500;
     }
+  }
+}
 
-    .form-input {
-      flex: 1;
-      height: 96rpx;
-      font-size: 28rpx;
-      color: $color-text-primary;
-      background: transparent;
-      border: none;
-    }
+/* ========== 登录卡片 ========== */
+.login-card {
+  background: rgba(255, 255, 255, 0.98);
+  border-radius: 32rpx;
+  padding: 56rpx 40rpx;
+  margin-bottom: 40rpx;
+  box-shadow:
+    0 16rpx 48rpx rgba(0, 0, 0, 0.06),
+    inset 0 1rpx 0 rgba(255, 255, 255, 0.8);
+  border: 1rpx solid rgba(255, 215, 0, 0.15);
+  animation: slideUp 0.8s cubic-bezier(0.25, 0.1, 0.25, 1) 0.3s both;
+  will-change: transform, opacity;
+  transform: translateZ(0);
+}
 
-    .input-placeholder {
-      color: $color-text-tertiary;
+.card-header {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 24rpx;
+  margin-bottom: 60rpx;
+  
+  .header-line {
+    width: 80rpx;
+    height: 2rpx;
+    background: linear-gradient(90deg, transparent 0%, rgba(255, 215, 0, 0.4) 100%);
+    
+    &:last-child {
+      background: linear-gradient(90deg, rgba(255, 215, 0, 0.4) 0%, transparent 100%);
     }
   }
+  
+  .card-title {
+    font-size: 30rpx;
+    font-weight: 600;
+    color: #333333;
+    letter-spacing: 2rpx;
+  }
 }
 
 .wechat-login-btn {
   width: 100%;
-  height: 96rpx;
-  background: linear-gradient(135deg, #07C160 0%, #06AD56 100%);
-  border-radius: $radius-lg;
+  min-height: 108rpx;
+  background: linear-gradient(135deg, #FFD700 0%, #FFC107 50%, #FFB300 100%);
+  border-radius: 54rpx;
   border: none;
-  margin-bottom: $spacing-lg;
   display: flex;
   align-items: center;
   justify-content: center;
-  box-shadow: 0 4rpx 16rpx rgba(7, 193, 96, 0.3);
-  transition: all $duration-normal $ease-out;
+  position: relative;
+  overflow: hidden;
+  box-shadow:
+    0 12rpx 40rpx rgba(255, 193, 7, 0.35),
+    0 4rpx 16rpx rgba(255, 193, 7, 0.2),
+    inset 0 2rpx 0 rgba(255, 255, 255, 0.3);
+  transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
 
   &::after {
     border: none;
   }
 
-  &:active {
-    transform: scale(0.98);
-    box-shadow: 0 4rpx 16rpx rgba(7, 193, 96, 0.4);
+  .btn-shine {
+    position: absolute;
+    top: 0;
+    left: -100%;
+    width: 100%;
+    height: 100%;
+    background: linear-gradient(
+      90deg,
+      transparent 0%,
+      rgba(255, 255, 255, 0.3) 50%,
+      transparent 100%
+    );
+    transition: left 0.6s ease;
   }
 
-  .btn-icon {
-    font-size: 32rpx;
-    margin-right: $spacing-sm;
+  &.btn-hover {
+    transform: translateY(-4rpx) scale(1.02);
+    box-shadow:
+      0 16rpx 48rpx rgba(255, 193, 7, 0.45),
+      0 6rpx 20rpx rgba(255, 193, 7, 0.25),
+      inset 0 2rpx 0 rgba(255, 255, 255, 0.4);
+
+    .btn-shine {
+      left: 100%;
+    }
   }
 
   .btn-text {
-    font-size: 32rpx;
-    font-weight: 500;
-    color: #FFFFFF;
+    font-size: 36rpx;
+    font-weight: 600;
+    color: #1A1A1A;
+    letter-spacing: 8rpx;
+    position: relative;
+    z-index: 1;
+    white-space: nowrap;
   }
 }
 
-.divider {
-  display: flex;
-  align-items: center;
-  margin: $spacing-lg 0;
-  
-  .divider-line {
-    flex: 1;
-    height: 1rpx;
-    background: $color-border-light;
-  }
-  
-  .divider-text {
+/* ========== 用户协议 ========== */
+.agreement-section {
+  animation: fadeIn 1s cubic-bezier(0.25, 0.1, 0.25, 1) 0.6s both;
+}
+
+.agreement-card {
+  text-align: center;
+  padding: 28rpx 36rpx;
+  background: rgba(255, 255, 255, 0.85);
+  border-radius: 20rpx;
+  border: 1rpx solid rgba(0, 0, 0, 0.04);
+
+  .agreement-prefix {
     font-size: 24rpx;
-    color: $color-text-tertiary;
-    padding: 0 $spacing-md;
+    color: #AAAAAA;
+    display: block;
+    margin-bottom: 8rpx;
+  }
+
+  .agreement-links {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 8rpx;
+    flex-wrap: wrap;
+
+    .link-item {
+      font-size: 24rpx;
+      color: #FFB300;
+      font-weight: 600;
+      text-decoration: underline;
+      text-decoration-color: rgba(255, 179, 0, 0.3);
+      cursor: pointer;
+
+      &:active {
+        opacity: 0.6;
+      }
+    }
+    
+    .link-sep {
+      font-size: 24rpx;
+      color: #CCCCCC;
+    }
   }
 }
 
-.login-btn {
-  width: 100%;
-  height: 96rpx;
-  background: linear-gradient(135deg, $color-primary-light 0%, $color-primary 100%);
-  border-radius: $radius-lg;
-  border: none;
-  margin-top: $spacing-xl;
+/* ========== 底部装饰 ========== */
+.footer-decoration {
   display: flex;
-  align-items: center;
   justify-content: center;
-  box-shadow: $shadow-primary;
-  transition: all $duration-normal $ease-out;
+  margin-top: auto;
+  padding-top: 60rpx;
 
-  &::after {
-    border: none;
+  .dot-pattern {
+    display: flex;
+    gap: 12rpx;
+
+    .dot {
+      width: 12rpx;
+      height: 12rpx;
+      border-radius: 50%;
+      background: linear-gradient(135deg, #FFD700 0%, #FFC107 100%);
+      opacity: 0.4;
+      /* 移除脉冲动画以提升性能 */
+    }
+  }
+}
+
+/* ========== 动画关键帧 ========== */
+@keyframes float {
+  0%, 100% {
+    transform: translateY(0) scale(1);
+  }
+  50% {
+    transform: translateY(-30rpx) scale(1.05);
   }
+}
 
-  &:active {
-    transform: scale(0.98);
-    box-shadow: 0 4rpx 16rpx rgba(255, 193, 7, 0.3);
+@keyframes wave {
+  0% {
+    transform: translateX(0) rotate(0deg);
   }
+  100% {
+    transform: translateX(50%) rotate(360deg);
+  }
+}
 
-  .btn-text {
-    font-size: 32rpx;
-    font-weight: 500;
-    color: $color-text-primary;
+@keyframes slideDown {
+  from {
+    opacity: 0;
+    transform: translateY(-60rpx);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
   }
 }
 
-/* ========== 用户协议 ========== */
-.agreement {
-  text-align: center;
-  padding: 0 $spacing-lg;
-  animation: fadeIn 1s cubic-bezier(0.25, 0.1, 0.25, 1);
+@keyframes slideUp {
+  from {
+    opacity: 0;
+    transform: translateY(60rpx);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
 
-  .agreement-text {
-    font-size: 24rpx;
-    color: $color-text-tertiary;
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
   }
+}
 
-  .agreement-link {
-    font-size: 24rpx;
-    color: $color-primary-dark;
-    font-weight: 500;
+@keyframes pulse {
+  0%, 100% {
+    opacity: 0.25;
+    transform: scale(1);
+  }
+  50% {
+    opacity: 0.4;
+    transform: scale(1.05);
+  }
+}
+
+@keyframes ringRotate {
+  from {
+    transform: rotate(0deg);
+  }
+  to {
+    transform: rotate(360deg);
   }
 }
 </style>

+ 55 - 1
haha-mp/src/pages/orderDetail/orderDetail.vue

@@ -155,9 +155,63 @@ const getStatusClass = (status: number) => {
 
 /**
  * 判断是否可以退款
+ * 只有已完成的订单可以退款,且订单完成时间不能超过7天
  */
 const canRefund = (order: OrderInfo) => {
-  return order.status === 1; // 只有已完成的订单可以退款
+  // 首先检查订单状态是否为已完成
+  if (order.status !== 1) {
+    return false;
+  }
+  
+  // 检查订单完成时间是否超过7天
+  if (order.payTime) {
+    const payTime = new Date(order.payTime);
+    const now = new Date();
+    const diffTime = now.getTime() - payTime.getTime();
+    const diffDays = diffTime / (1000 * 60 * 60 * 24);
+    
+    // 如果超过7天,不允许退款
+    if (diffDays > 7) {
+      return false;
+    }
+  }
+  
+  return true;
+};
+
+/**
+ * 判断订单是否超过退款期限(7天)
+ */
+const isRefundExpired = (order: OrderInfo) => {
+  if (order.status !== 1 || !order.payTime) {
+    return false;
+  }
+  
+  const payTime = new Date(order.payTime);
+  const now = new Date();
+  const diffTime = now.getTime() - payTime.getTime();
+  const diffDays = diffTime / (1000 * 60 * 60 * 24);
+  
+  return diffDays > 7;
+};
+
+/**
+ * 获取退款期限提示文本
+ */
+const getRefundExpireText = (order: OrderInfo) => {
+  if (!order.payTime) return '';
+  
+  const payTime = new Date(order.payTime);
+  const now = new Date();
+  const diffTime = now.getTime() - payTime.getTime();
+  const diffDays = diffTime / (1000 * 60 * 60 * 24);
+  
+  if (diffDays > 7) {
+    return '已超过退款期限(7天)';
+  } else {
+    const remainingDays = Math.ceil(7 - diffDays);
+    return `剩余 ${remainingDays} 天可申请退款`;
+  }
 };
 
 /**

+ 74 - 19
haha-mp/src/pages/orders/orders.vue

@@ -86,10 +86,63 @@ const getQuantity = (order: OrderInfo) => {
 
 /**
  * 判断是否可以申请退款
- * 只有已完成的订单可以退款
+ * 只有已完成的订单可以退款,且订单完成时间不能超过7天
  */
 const canRefund = (order: OrderInfo) => {
-  return order.status === 1; // 1-已完成
+  // 首先检查订单状态是否为已完成
+  if (order.status !== 1) {
+    return false;
+  }
+  
+  // 检查订单完成时间是否超过7天
+  if (order.payTime) {
+    const payTime = new Date(order.payTime);
+    const now = new Date();
+    const diffTime = now.getTime() - payTime.getTime();
+    const diffDays = diffTime / (1000 * 60 * 60 * 24);
+    
+    // 如果超过7天,不允许退款
+    if (diffDays > 7) {
+      return false;
+    }
+  }
+  
+  return true;
+};
+
+/**
+ * 判断订单是否超过退款期限(7天)
+ */
+const isRefundExpired = (order: OrderInfo) => {
+  if (order.status !== 1 || !order.payTime) {
+    return false;
+  }
+  
+  const payTime = new Date(order.payTime);
+  const now = new Date();
+  const diffTime = now.getTime() - payTime.getTime();
+  const diffDays = diffTime / (1000 * 60 * 60 * 24);
+  
+  return diffDays > 7;
+};
+
+/**
+ * 获取退款期限提示文本
+ */
+const getRefundExpireText = (order: OrderInfo) => {
+  if (!order.payTime) return '';
+  
+  const payTime = new Date(order.payTime);
+  const now = new Date();
+  const diffTime = now.getTime() - payTime.getTime();
+  const diffDays = diffTime / (1000 * 60 * 60 * 24);
+  
+  if (diffDays > 7) {
+    return '已超过退款期限';
+  } else {
+    const remainingDays = Math.ceil(7 - diffDays);
+    return `剩余 ${remainingDays} 天可申请退款`;
+  }
 };
 
 /**
@@ -163,7 +216,7 @@ const viewOrderDetail = (order: OrderInfo) => {
 <style scoped lang="scss">
 .container {
   min-height: 100vh;
-  background: linear-gradient(180deg, #FFF8E1 0%, #F5F5F5 30%);
+  background: #F5F5F5;
   position: relative;
   padding-top: 0;
 }
@@ -177,13 +230,17 @@ const viewOrderDetail = (order: OrderInfo) => {
   min-height: 80vh;
   padding: 40rpx;
   animation: fadeIn 0.6s cubic-bezier(0.25, 0.1, 0.25, 1);
+  will-change: transform, opacity;
+  transform: translateZ(0);
 }
 
 .empty-icon {
   width: 300rpx;
   height: 300rpx;
   margin-bottom: 40rpx;
-  animation: bounce 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55) 0.2s both;
+  animation: fadeIn 0.6s cubic-bezier(0.25, 0.1, 0.25, 1) 0.2s both;
+  will-change: transform, opacity;
+  transform: translateZ(0);
 }
 
 .empty-icon svg {
@@ -196,13 +253,13 @@ const viewOrderDetail = (order: OrderInfo) => {
   color: #666666;
   margin-bottom: 16rpx;
   font-weight: 500;
-  animation: slideUp 0.6s cubic-bezier(0.25, 0.1, 0.25, 1) 0.3s both;
+  animation: fadeIn 0.4s cubic-bezier(0.25, 0.1, 0.25, 1) 0.3s both;
 }
 
 .empty-tip {
   font-size: 28rpx;
   color: #999999;
-  animation: slideUp 0.6s cubic-bezier(0.25, 0.1, 0.25, 1) 0.4s both;
+  animation: fadeIn 0.4s cubic-bezier(0.25, 0.1, 0.25, 1) 0.4s both;
 }
 
 /* 订单列表 */
@@ -216,13 +273,13 @@ const viewOrderDetail = (order: OrderInfo) => {
   border-radius: 24rpx;
   margin-bottom: 24rpx;
   overflow: hidden;
-  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.04), 0 2rpx 8rpx rgba(0, 0, 0, 0.02);
-  animation: slideUp 0.5s cubic-bezier(0.25, 0.1, 0.25, 1) both;
-  transition: transform 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), box-shadow 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
-  
+  box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
+  transition: transform 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
+  will-change: transform;
+  transform: translateZ(0);
+
   &:active {
     transform: scale(0.98);
-    box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.06);
   }
 }
 
@@ -285,7 +342,7 @@ const viewOrderDetail = (order: OrderInfo) => {
   height: 160rpx;
   margin-right: 24rpx;
   flex-shrink: 0;
-  background: linear-gradient(135deg, #F5F5F5 0%, #EEEEEE 100%);
+  background: #F5F5F5;
   border-radius: 16rpx;
   overflow: hidden;
 }
@@ -298,7 +355,7 @@ const viewOrderDetail = (order: OrderInfo) => {
 .image-placeholder {
   width: 100%;
   height: 100%;
-  background: linear-gradient(135deg, #F5F5F5 0%, #EEEEEE 100%);
+  background: #F5F5F5;
 }
 
 .order-info {
@@ -368,8 +425,10 @@ const viewOrderDetail = (order: OrderInfo) => {
   justify-content: center;
   margin: 0;
   width: auto;
-  transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);
-  
+  transition: transform 0.2s cubic-bezier(0.25, 0.1, 0.25, 1);
+  will-change: transform;
+  transform: translateZ(0);
+
   &:active {
     transform: scale(0.95);
   }
@@ -386,10 +445,6 @@ const viewOrderDetail = (order: OrderInfo) => {
   color: #1A1A1A;
   font-weight: 600;
   box-shadow: 0 4rpx 12rpx rgba(255, 193, 7, 0.25);
-  
-  &:active {
-    box-shadow: 0 2rpx 8rpx rgba(255, 193, 7, 0.3);
-  }
 }
 
 .refund-btn {

+ 59 - 0
haha-mp/src/pages/refund/refund.vue

@@ -110,6 +110,10 @@
         <text class="info-label">退款总金额:</text>
         <text class="info-value refund-amount">¥{{ refundAmount.toFixed(2) }}</text>
       </view>
+      <view class="info-row" v-if="orderInfo.payTime">
+        <text class="info-label">退款期限:</text>
+        <text :class="['info-value', isRefundExpired ? 'expired' : '']">{{ refundExpireText }}</text>
+      </view>
     </view>
     
     <!-- 提示信息 -->
@@ -171,6 +175,35 @@ const refundAmount = computed(() => {
   }, 0);
 });
 
+// 判断是否超过退款期限
+const isRefundExpired = computed(() => {
+  if (!orderInfo.value.payTime) return false;
+  
+  const payTime = new Date(orderInfo.value.payTime);
+  const now = new Date();
+  const diffTime = now.getTime() - payTime.getTime();
+  const diffDays = diffTime / (1000 * 60 * 60 * 24);
+  
+  return diffDays > 7;
+});
+
+// 退款期限提示文本
+const refundExpireText = computed(() => {
+  if (!orderInfo.value.payTime) return '';
+  
+  const payTime = new Date(orderInfo.value.payTime);
+  const now = new Date();
+  const diffTime = now.getTime() - payTime.getTime();
+  const diffDays = diffTime / (1000 * 60 * 60 * 24);
+  
+  if (diffDays > 7) {
+    return '已超过退款期限';
+  } else {
+    const remainingDays = Math.ceil(7 - diffDays);
+    return `剩余 ${remainingDays} 天`;
+  }
+});
+
 const selectedReason = ref('');
 const refundRemark = ref('');
 
@@ -273,6 +306,27 @@ const loadOrderDetail = async () => {
     const detail = await getOrderDetail({ orderId: orderId.value });
     orderInfo.value = detail;
     
+    // 检查订单是否超过退款期限(7天)
+    if (detail.payTime) {
+      const payTime = new Date(detail.payTime);
+      const now = new Date();
+      const diffTime = now.getTime() - payTime.getTime();
+      const diffDays = diffTime / (1000 * 60 * 60 * 24);
+      
+      if (diffDays > 7) {
+        uni.showModal({
+          title: '退款期限已过',
+          content: '该订单已完成超过7天,不支持申请退款',
+          showCancel: false,
+          confirmText: '知道了',
+          success: () => {
+            uni.navigateBack();
+          }
+        });
+        return;
+      }
+    }
+    
     // 默认不选中任何商品(移除之前的默认全选逻辑)
     selectedProducts.value = [];
   } catch (error) {
@@ -782,6 +836,11 @@ radio-group {
   text-align: right;
 }
 
+.info-value.expired {
+  color: #ff4444;
+  font-weight: 600;
+}
+
 /* 提交按钮 */
 .submit-btn {
   margin: 40rpx 30rpx;

+ 14 - 0
haha-mp/src/static/brand-logo.svg

@@ -0,0 +1,14 @@
+<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <!-- 背景圆角矩形 -->
+  <rect x="10" y="10" width="180" height="180" rx="40" fill="#FFC107"/>
+  
+  <!-- AI字母图标 -->
+  <g transform="translate(45, 50)">
+    <!-- A -->
+    <path d="M20 80 L40 20 L60 80" stroke="#FFFFFF" stroke-width="12" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
+    <path d="M28 60 L52 60" stroke="#FFFFFF" stroke-width="12" stroke-linecap="round"/>
+    
+    <!-- I -->
+    <path d="M80 20 L80 80" stroke="#FFFFFF" stroke-width="12" stroke-linecap="round"/>
+  </g>
+</svg>

+ 7 - 0
haha-mp/src/static/wechat-icon.svg

@@ -0,0 +1,7 @@
+<svg width="44" height="44" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <path d="M8.5 13.5C8.5 14.3284 7.82843 15 7 15C6.17157 15 5.5 14.3284 5.5 13.5C5.5 12.6716 6.17157 12 7 12C7.82843 12 8.5 12.6716 8.5 13.5Z" fill="white"/>
+  <path d="M14.5 13.5C14.5 14.3284 13.8284 15 13 15C12.1716 15 11.5 14.3284 11.5 13.5C11.5 12.6716 12.1716 12 13 12C13.8284 12 14.5 12.6716 14.5 13.5Z" fill="white"/>
+  <path d="M16.5 6C16.5 6.82843 15.8284 7.5 15 7.5C14.1716 7.5 13.5 6.82843 13.5 6C13.5 5.17157 14.1716 4.5 15 4.5C15.8284 4.5 16.5 5.17157 16.5 6Z" fill="white"/>
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M8.23782 11.0364C5.53906 11.0364 3.5 13.0755 3.5 15.3742C3.5 16.5138 4.06289 17.4566 4.85938 18.0422L4.5 19.5L6.17109 18.6645C6.89062 18.857 7.5 18.9469 8.23782 18.9469C8.44336 18.9469 8.64727 18.9375 8.84844 18.9164C8.56016 18.3734 8.40625 17.7695 8.40625 17.1488C8.40625 14.8501 10.4453 12.811 13.1441 12.811C13.3969 12.811 13.6453 12.8352 13.8891 12.8789C13.1508 11.6797 11.7875 11.0364 8.23782 11.0364ZM7 16.5C6.17157 16.5 5.5 15.8284 5.5 15C5.5 14.1716 6.17157 13.5 7 13.5C7.82843 13.5 8.5 14.1716 8.5 15C8.5 15.8284 7.82843 16.5 7 16.5ZM13 16.5C12.1716 16.5 11.5 15.8284 11.5 15C11.5 14.1716 12.1716 13.5 13 13.5C13.8284 13.5 14.5 14.1716 14.5 15C14.5 15.8284 13.8284 16.5 13 16.5Z" fill="white"/>
+  <path fill-rule="evenodd" clip-rule="evenodd" d="M16.5 9.5C15.6716 9.5 15 10.1716 15 11C15 11.8284 15.6716 12.5 16.5 12.5C17.3284 12.5 18 11.8284 18 11C18 10.1716 17.3284 9.5 16.5 9.5ZM20.5 14C20.5 12.0695 18.6953 10.5 16.5 10.5C14.3047 10.5 12.5 12.0695 12.5 14C12.5 15.9305 14.3047 17.5 16.5 17.5C17.0156 17.5 17.5 17.4062 18.0156 17.2656L19.5 18L19.1406 16.5469C19.8281 15.9609 20.5 15.0625 20.5 14Z" fill="white"/>
+</svg>

+ 21 - 6
haha-service/src/main/java/com/haha/service/payment/impl/PaymentServiceImpl.java

@@ -152,10 +152,25 @@ public class PaymentServiceImpl implements PaymentService {
                     .build();
         }
         
-        // 4. 根据订单的 payChannel 获取支付渠道
+        // 4. 校验订单完成时间是否超过7天
+        if (order.getPayTime() != null) {
+            LocalDateTime now = LocalDateTime.now();
+            long daysDiff = java.time.temporal.ChronoUnit.DAYS.between(order.getPayTime(), now);
+            
+            if (daysDiff > 7) {
+                log.error("退款失败: 订单已完成超过7天,不允许退款, orderId={}, payTime={}", orderId, order.getPayTime());
+                return RefundResult.builder()
+                        .success(false)
+                        .errorCode("REFUND_EXPIRED")
+                        .errorMsg("订单已完成超过7天,不支持退款")
+                        .build();
+            }
+        }
+        
+        // 5. 根据订单的 payChannel 获取支付渠道
         PaymentChannel channel = PaymentChannel.fromCode(order.getPayChannel());
         
-        // 5. 如果 channel 为 null 或 BALANCE,直接更新退款状态(余额退款不经过第三方)
+        // 6. 如果 channel 为 null 或 BALANCE,直接更新退款状态(余额退款不经过第三方)
         if (channel == null || channel == PaymentChannel.BALANCE) {
             log.info("余额退款,直接更新订单状态: orderId={}", orderId);
             updateOrderRefundStatus(order, reason, null);
@@ -165,7 +180,7 @@ public class PaymentServiceImpl implements PaymentService {
                     .build();
         }
         
-        // 6. 获取支付策略
+        // 7. 获取支付策略
         PaymentStrategy strategy;
         try {
             strategy = channelFactory.getStrategy(channel);
@@ -178,7 +193,7 @@ public class PaymentServiceImpl implements PaymentService {
                     .build();
         }
         
-        // 7. 构建退款请求
+        // 8. 构建退款请求
         String refundNo = generateRefundNo(order.getOrderNo());
         RefundRequest refundRequest = RefundRequest.builder()
                 .orderId(orderId)
@@ -193,10 +208,10 @@ public class PaymentServiceImpl implements PaymentService {
         log.info("调用支付策略执行退款: orderNo={}, refundNo={}, amount={}", 
                 order.getOrderNo(), refundNo, order.getTotalAmount());
         
-        // 8. 调用策略退款
+        // 9. 调用策略退款
         RefundResult result = strategy.refund(refundRequest);
         
-        // 9. 更新订单退款状态
+        // 10. 更新订单退款状态
         if (result.isSuccess()) {
             updateOrderRefundStatus(order, reason, result.getRefundId());
             log.info("退款成功: orderId={}, refundId={}", orderId, result.getRefundId());