2
0
Эх сурвалжийг харах

✨ feat(profile): 在小程序个人中心添加欠款信息显示功能

- 实现用户信用额度查询,使用React Query管理API状态
- 新增欠款信息卡片组件,当欠款金额大于0时显示
- 添加加载状态、错误处理和重试机制
- 显示累计欠款金额和还款提示信息
- 更新开发文档,标记个人中心欠款显示功能为已完成
yourname 4 өдөр өмнө
parent
commit
3b460780e7

+ 15 - 8
docs/stories/004.003.integrate-credit-payment.story.md

@@ -53,11 +53,11 @@ Draft
   - [x] 额度为0的用户禁用额度支付选项
   - [x] 保持与微信支付选项的并行工作
 
-- [ ] **在小程序个人中心显示欠款信息** (AC: 6)
-  - [ ] 检查小程序个人中心页面结构
-  - [ ] 添加欠款信息显示组件
-  - [ ] 调用额度查询API获取用户欠款信息
-  - [ ] 设计欠款信息显示样式(总额度、已用额度、可用额度、欠款金额)
+- [x] **在小程序个人中心显示欠款信息** (AC: 6)
+  - [x] 检查小程序个人中心页面结构
+  - [x] 添加欠款信息显示组件
+  - [x] 调用额度查询API获取用户欠款信息
+  - [x] 设计欠款信息显示样式(总额度、已用额度、可用额度、欠款金额)
 
 - [ ] **按照小程序mini规范编写测试** (AC: 1, 2, 3, 4, 5, 6, 7)
   - [ ] **支付页面额度支付单元测试**:在 `mini/tests/unit/pages/payment/` 创建测试文件,测试额度支付选项
@@ -450,8 +450,15 @@ Claude Code (d8d-model)
    - 保持与微信支付选项的并行工作
    - 修复server包和订单模块的依赖,添加额度模块依赖
 
-3. **完成的工作**:
+3. **完成的工作**:
    - 在小程序个人中心显示欠款信息
+     - 添加React Query查询用户信用额度
+     - 实现欠款信息卡片组件,只显示累计欠款金额
+     - 当欠款金额大于0时才显示卡片
+     - 实现加载状态和错误处理
+     - 显示"需结清金额"和还款提示
+
+4. **待完成的工作**:
    - 按照小程序mini规范编写测试
    - 验证模块间集成
 
@@ -469,10 +476,10 @@ Claude Code (d8d-model)
 10. `mini/src/pages/payment/index.tsx` - 添加额度支付选项和逻辑
 11. `packages/server/package.json` - 添加额度模块依赖
 12. `packages/orders-module-mt/package.json` - 添加额度模块依赖
+13. `mini/src/pages/profile/index.tsx` - 添加欠款信息显示组件
 
 **需要创建/修改的文件**:
-1. `mini/src/pages/profile/index.tsx` - 添加欠款信息显示(待完成)
-2. 测试文件(待完成)
+1. 测试文件(待完成)
 
 ## QA Results
 *此部分由QA代理在审查完成后填写*

+ 106 - 1
mini/src/pages/profile/index.tsx

@@ -1,6 +1,7 @@
-import { useState } from 'react'
+import { useState, useEffect } from 'react'
 import { View, Text, ScrollView } from '@tarojs/components'
 import Taro from '@tarojs/taro'
+import { useQuery } from '@tanstack/react-query'
 import { TabBarLayout } from '@/layouts/tab-bar-layout'
 import { useAuth } from '@/utils/auth'
 import { cn } from '@/utils/cn'
@@ -14,6 +15,7 @@ import TDesignCellGroup from '@/components/tdesign/cell-group'
 import TDesignCell from '@/components/tdesign/cell'
 import TDesignPopup from '@/components/tdesign/popup'
 import TDesignIcon from '@/components/tdesign/icon'
+import { creditBalanceClient } from '@/api'
 import './index.css'
 
 const ProfilePage: React.FC = () => {
@@ -21,6 +23,45 @@ const ProfilePage: React.FC = () => {
   const [updatingAvatar, setUpdatingAvatar] = useState(false)
   const [showCustomerService, setShowCustomerService] = useState(false)
 
+  // 查询用户信用额度
+  const {
+    data: creditBalance,
+    isLoading: creditBalanceLoading,
+    error: creditBalanceError,
+    refetch: refetchCreditBalance
+  } = useQuery({
+    queryKey: ['credit-balance', userProfile?.id],
+    queryFn: async () => {
+      if (!userProfile?.id) {
+        throw new Error('用户未登录')
+      }
+
+      try {
+        const response = await creditBalanceClient.me.$get({})
+
+        if (response.status === 200) {
+          const balanceData = await response.json()
+          return balanceData
+        } else if (response.status === 404) {
+          // 用户没有额度记录,返回默认值
+          return {
+            totalLimit: 0,
+            usedAmount: 0,
+            availableAmount: 0,
+            isEnabled: false
+          }
+        } else {
+          throw new Error(`获取额度失败: ${response.status}`)
+        }
+      } catch (error) {
+        console.error('查询用户额度失败:', error)
+        throw error
+      }
+    },
+    enabled: !!userProfile?.id,
+    retry: 1
+  })
+
   const handleLogout = async () => {
     try {
       Taro.showModal({
@@ -234,6 +275,70 @@ const ProfilePage: React.FC = () => {
           />
         </View>
 
+        {/* 欠款信息卡片 */}
+        {creditBalance && creditBalance.usedAmount > 0 && (
+          <View className="px-4 pt-4">
+            <View className="bg-white rounded-2xl overflow-hidden">
+              <View className="p-5 border-b border-gray-100">
+                <View className="flex items-center justify-between">
+                  <Text className="text-lg font-bold text-gray-800">欠款信息</Text>
+                  {creditBalanceLoading ? (
+                    <View className="i-heroicons-arrow-path-20-solid animate-spin w-5 h-5 text-blue-500" />
+                  ) : creditBalanceError ? (
+                    <Button
+                      size="sm"
+                      variant="ghost"
+                      onClick={() => refetchCreditBalance()}
+                      className="text-xs text-red-500"
+                    >
+                      重试
+                    </Button>
+                  ) : null}
+                </View>
+              </View>
+
+              <View className="p-5">
+                {creditBalanceLoading ? (
+                  <View className="flex items-center justify-center py-8">
+                    <View className="i-heroicons-arrow-path-20-solid animate-spin w-6 h-6 text-blue-500 mr-2" />
+                    <Text className="text-gray-500">加载中...</Text>
+                  </View>
+                ) : creditBalanceError ? (
+                  <View className="flex flex-col items-center justify-center py-8">
+                    <View className="i-heroicons-exclamation-circle-20-solid w-8 h-8 text-red-400 mb-2" />
+                    <Text className="text-gray-500 mb-2">加载失败</Text>
+                    <Button
+                      size="sm"
+                      variant="outline"
+                      onClick={() => refetchCreditBalance()}
+                    >
+                      重新加载
+                    </Button>
+                  </View>
+                ) : creditBalance && creditBalance.usedAmount > 0 ? (
+                  <View className="flex items-center justify-between">
+                    <View className="flex items-center">
+                      <View className="w-10 h-10 bg-red-100 rounded-full flex items-center justify-center mr-3">
+                        <Text className="text-red-600 text-lg">📊</Text>
+                      </View>
+                      <View>
+                        <Text className="text-sm text-gray-600">累计欠款</Text>
+                        <Text className="text-2xl font-bold text-red-600">
+                          ¥{creditBalance.usedAmount.toFixed(2)}
+                        </Text>
+                      </View>
+                    </View>
+                    <View className="text-right">
+                      <Text className="text-xs text-gray-500">需结清金额</Text>
+                      <Text className="text-xs text-red-500 mt-1">请及时还款</Text>
+                    </View>
+                  </View>
+                ) : null}
+              </View>
+            </View>
+          </View>
+        )}
+
         {/* 功能菜单 */}
         <View className="px-4 pt-4">
           {menuData.map((group, groupIndex) => (