瀏覽代碼

feat(second-trade): 实现卖家评价列表分页功能

- 控制器层新增分页参数支持,默认页码为1,默认每页10条
- 服务层接口调整返回类型为IPage,支持分页查询
- 实现类中集成MyBatis Plus分页插件,限制最大每页100条- 新增买家和卖家完成交易时间字段,完善评价信息展示
-优化无数据情况下的分页对象返回逻辑
- 更新Swagger文档注释,明确分页参数说明
wxd 4 周之前
父節點
當前提交
bee89cda51

+ 12 - 0
alien-entity/src/main/java/shop/alien/entity/second/vo/SellerEvaluationVo.java

@@ -1,5 +1,6 @@
 package shop.alien.entity.second.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import io.swagger.annotations.ApiModel;
@@ -101,5 +102,16 @@ public class SellerEvaluationVo {
     @ApiModelProperty(value = "创建时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date createdTime;
+
+
+    @ApiModelProperty(value = "买家完成交易时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date buyerCompleteTime;
+
+    @ApiModelProperty(value = "卖家完成交易时间")
+    @TableField("seller_complete_time")
+    private Date sellerCompleteTime;
+
+
 }
 

+ 313 - 292
alien-second/doc/获取卖家交易评价列表接口文档.md

@@ -1,4 +1,4 @@
-# 获取卖家交易评价列表接口文档
+# 获取卖家交易评价列表接口文档(分页版)
 
 ## 接口概述
 
@@ -6,16 +6,16 @@
 
 | 项目 | 内容 |
 |------|------|
-| 接口名称 | 获取用户作为卖家的交易评价列表 |
+| 接口名称 | 获取用户作为卖家的交易评价列表(分页) |
 | 接口路径 | `/secondTradeRecord/getSellerEvaluationList` |
 | 请求方式 | GET |
-| 接口版本 | v1.0 |
+| 接口版本 | v1.1(支持分页) |
 | 开发时间 | 2025-11-18 |
 | 接口状态 | ✅ 已完成 |
 
 ### 功能描述
 
-用于用户主页展示该用户作为卖家收到的所有交易评价,包含:
+用于用户主页展示该用户作为卖家收到的所有交易评价,**支持分页查询**,包含:
 - 买家完整信息(昵称、头像、真实姓名、性别、简介等)
 - 评价内容和评分
 - 买家和卖家的信用积分
@@ -32,41 +32,81 @@
 | 参数名 | 类型 | 必填 | 描述 | 示例值 | 默认值 |
 |--------|------|------|------|--------|--------|
 | sellerId | Integer | ✅ 是 | 卖家用户ID(主页用户ID) | 123 | - |
+| pageNum | Integer | ❌ 否 | 页码(从1开始) | 1 | 1 |
+| pageSize | Integer | ❌ 否 | 每页条数(最大100) | 10 | 10 |
+
+**参数说明:**
+- `pageNum`: 页码从1开始,传入小于1的值自动修正为1
+- `pageSize`: 每页条数,传入小于1的值自动修正为10,超过100自动限制为100
 
 ### 请求示例
 
 #### cURL
 
 ```bash
+# 获取第1页,每页10条(使用默认值)
 curl -X GET "http://localhost:8080/secondTradeRecord/getSellerEvaluationList?sellerId=123" \
   -H "Authorization: Bearer your_token_here"
+
+# 获取第2页,每页20条
+curl -X GET "http://localhost:8080/secondTradeRecord/getSellerEvaluationList?sellerId=123&pageNum=2&pageSize=20" \
+  -H "Authorization: Bearer your_token_here"
 ```
 
 #### JavaScript (Axios)
 
 ```javascript
+// 基本用法
 axios.get('/secondTradeRecord/getSellerEvaluationList', {
   params: {
-    sellerId: 123
+    sellerId: 123,
+    pageNum: 1,
+    pageSize: 10
   },
   headers: {
     'Authorization': 'Bearer your_token_here'
   }
 })
 .then(response => {
-  console.log(response.data);
+  const { records, total, pages, current, size } = response.data.data;
+  console.log(`当前第${current}页,每页${size}条`);
+  console.log(`共${total}条数据,${pages}页`);
+  console.log('评价列表:', records);
 })
 .catch(error => {
   console.error(error);
 });
+
+// 结合分页组件使用
+function loadEvaluations(sellerId, pageNum = 1, pageSize = 10) {
+  return axios.get('/secondTradeRecord/getSellerEvaluationList', {
+    params: { sellerId, pageNum, pageSize }
+  });
+}
+
+// 加载下一页
+function loadNextPage(currentPage) {
+  loadEvaluations(123, currentPage + 1, 10)
+    .then(response => {
+      // 处理数据
+    });
+}
 ```
 
 #### Java (RestTemplate)
 
 ```java
-String url = "http://localhost:8080/secondTradeRecord/getSellerEvaluationList?sellerId=123";
+String url = "http://localhost:8080/secondTradeRecord/getSellerEvaluationList" +
+             "?sellerId=123&pageNum=1&pageSize=10";
 RestTemplate restTemplate = new RestTemplate();
-R<List<SellerEvaluationVo>> result = restTemplate.getForObject(url, R.class);
+R<IPage<SellerEvaluationVo>> result = restTemplate.getForObject(url, R.class);
+
+IPage<SellerEvaluationVo> page = result.getData();
+System.out.println("总记录数:" + page.getTotal());
+System.out.println("总页数:" + page.getPages());
+System.out.println("当前页:" + page.getCurrent());
+System.out.println("每页条数:" + page.getSize());
+List<SellerEvaluationVo> records = page.getRecords();
 ```
 
 ---
@@ -79,7 +119,17 @@ R<List<SellerEvaluationVo>> result = restTemplate.getForObject(url, R.class);
 |--------|------|------|
 | code | Integer | 响应状态码,200表示成功 |
 | msg | String | 响应消息 |
-| data | Array&lt;SellerEvaluationVo&gt; | 评价列表数据 |
+| data | IPage&lt;SellerEvaluationVo&gt; | 分页数据对象 |
+
+### IPage 分页对象结构
+
+| 字段名 | 类型 | 描述 | 示例值 |
+|--------|------|------|--------|
+| records | Array&lt;SellerEvaluationVo&gt; | 当前页的评价列表 | [...] |
+| total | Long | 总记录数 | 45 |
+| size | Long | 每页条数 | 10 |
+| current | Long | 当前页码 | 1 |
+| pages | Long | 总页数 | 5 |
 
 ### SellerEvaluationVo 对象结构
 
@@ -160,79 +210,52 @@ R<List<SellerEvaluationVo>> result = restTemplate.getForObject(url, R.class);
 | D | 10-14次 | 严重违规 | 🔴 高风险 |
 | E | ≥15次 | 极差 | 🔴 极高风险(最差) |
 
-**风控等级计算说明**:
-- 基于用户在 `second_risk_control_record` 表中的违规记录数量
-- 违规类型包括:洗钱嫌疑、账号异常、交易欺诈、异常发布
-- 等级实时计算,反映用户最新的信用状态
-
 ---
 
 ## 响应示例
 
-### 成功响应
+### 成功响应(有数据)
 
 ```json
 {
   "code": 200,
   "msg": "成功",
-  "data": [
-    {
-      "id": 1,
-      "tradeNo": "S2025111800001",
-      "goodsId": 100,
-      "goodsTitle": "二手iPhone 13 128G 白色 95新",
-      "goodsHomeImage": "https://cdn.example.com/goods/iphone13.jpg",
-      "goodsPrice": 3999.00,
-      "transactionAmount": 3800.00,
-      "buyerId": 456,
-      "buyerName": "张三",
-      "buyerImage": "https://cdn.example.com/avatar/user456.jpg",
-      "buyerPhone": "13800138000",
-      "buyerRealName": "张三三",
-      "buyerSex": "男",
-      "buyerJianjie": "热爱数码产品,诚信交易",
-      "buyerEvaluate": "商品质量很好,和描述一致,卖家态度也不错,推荐!",
-      "buyerRating": 5,
-      "buyerCreditScore": 450,
-      "buyerCreditLevel": "A",
-      "sellerId": 123,
-      "sellerName": "李四",
-      "sellerImage": "https://cdn.example.com/avatar/user123.jpg",
-      "sellerCreditScore": 500,
-      "sellerCreditLevel": "O",
-      "transactionTime": "2025-11-18 10:00:00",
-      "tradeStatus": 4,
-      "createdTime": "2025-11-18 09:00:00"
-    },
-    {
-      "id": 2,
-      "tradeNo": "S2025111700025",
-      "goodsId": 101,
-      "goodsTitle": "小米手环7 黑色 全新未拆封",
-      "goodsHomeImage": "https://cdn.example.com/goods/miband7.jpg",
-      "goodsPrice": 199.00,
-      "transactionAmount": 180.00,
-      "buyerId": 789,
-      "buyerName": "王五",
-      "buyerImage": "https://cdn.example.com/avatar/user789.jpg",
-      "buyerPhone": "13900139000",
-      "buyerRealName": "王小五",
-      "buyerSex": "女",
-      "buyerJianjie": "喜欢运动健身",
-      "buyerEvaluate": "东西不错,发货速度快",
-      "buyerRating": 4,
-      "buyerCreditScore": 380,
-      "buyerCreditLevel": "O",
-      "sellerId": 123,
-      "sellerName": "李四",
-      "sellerImage": "https://cdn.example.com/avatar/user123.jpg",
-      "sellerCreditScore": 500,
-      "sellerCreditLevel": "O",
-      "transactionTime": "2025-11-17 15:30:00",
-      "tradeStatus": 4,
-      "createdTime": "2025-11-17 14:20:00"
-    }
-  ]
+  "data": {
+    "records": [
+      {
+        "id": 1,
+        "tradeNo": "S2025111800001",
+        "goodsId": 100,
+        "goodsTitle": "二手iPhone 13 128G 白色 95新",
+        "goodsHomeImage": "https://cdn.example.com/goods/iphone13.jpg",
+        "goodsPrice": 3999.00,
+        "transactionAmount": 3800.00,
+        "buyerId": 456,
+        "buyerName": "张三",
+        "buyerImage": "https://cdn.example.com/avatar/user456.jpg",
+        "buyerPhone": "13800138000",
+        "buyerRealName": "张三三",
+        "buyerSex": "男",
+        "buyerJianjie": "热爱数码产品,诚信交易",
+        "buyerEvaluate": "商品质量很好,和描述一致,卖家态度也不错,推荐!",
+        "buyerRating": 5,
+        "buyerCreditScore": 450,
+        "buyerCreditLevel": "A",
+        "sellerId": 123,
+        "sellerName": "李四",
+        "sellerImage": "https://cdn.example.com/avatar/user123.jpg",
+        "sellerCreditScore": 500,
+        "sellerCreditLevel": "O",
+        "transactionTime": "2025-11-18 10:00:00",
+        "tradeStatus": 4,
+        "createdTime": "2025-11-18 09:00:00"
+      }
+    ],
+    "total": 45,
+    "size": 10,
+    "current": 1,
+    "pages": 5
+  }
 }
 ```
 
@@ -242,7 +265,13 @@ R<List<SellerEvaluationVo>> result = restTemplate.getForObject(url, R.class);
 {
   "code": 200,
   "msg": "成功",
-  "data": []
+  "data": {
+    "records": [],
+    "total": 0,
+    "size": 10,
+    "current": 1,
+    "pages": 0
+  }
 }
 ```
 
@@ -270,6 +299,29 @@ R<List<SellerEvaluationVo>> result = restTemplate.getForObject(url, R.class);
 
 ---
 
+## 分页计算说明
+
+### 分页参数
+
+- **pageNum**: 当前页码,从 1 开始
+- **pageSize**: 每页显示条数
+- **total**: 总记录数
+- **pages**: 总页数 = Math.ceil(total / pageSize)
+
+### 分页示例
+
+假设某卖家有 45 条评价:
+
+| pageNum | pageSize | 返回记录 | 页面显示 |
+|---------|----------|----------|----------|
+| 1 | 10 | 1-10 | 第1页,共5页,显示10条 |
+| 2 | 10 | 11-20 | 第2页,共5页,显示10条 |
+| 3 | 10 | 21-30 | 第3页,共5页,显示10条 |
+| 4 | 10 | 31-40 | 第4页,共5页,显示10条 |
+| 5 | 10 | 41-45 | 第5页,共5页,显示5条 |
+
+---
+
 ## 业务规则
 
 ### 查询规则
@@ -279,29 +331,23 @@ R<List<SellerEvaluationVo>> result = restTemplate.getForObject(url, R.class);
    - ✅ 只返回未删除的记录(`delete_flag = 0`)
    - ✅ 按创建时间倒序排列(最新评价在前)
 
-2. **数据关联**
+2. **分页限制**
+   - ✅ pageNum < 1 时自动修正为 1
+   - ✅ pageSize < 1 时自动修正为 10
+   - ✅ pageSize > 100 时自动限制为 100(防止数据量过大)
+
+3. **数据关联**
    - 商品信息:通过 `goods_record_id` 关联 `second_goods_record` 表
    - 买家信息:通过 `buyer_id` 关联 `life_user` 表
    - 卖家信息:通过 `seller_id` 关联 `life_user` 表
    - 信用积分:通过 `user_id` 关联 `second_user_credit` 表
    - 风控等级:实时计算,查询 `second_risk_control_record` 表
 
-3. **性能优化**
-   - 使用批量查询避免 N+1 问题
+4. **性能优化**
+   - 使用 MyBatis Plus 分页插件
+   - 批量查询避免 N+1 问题
    - 关联数据使用 Map 索引,时间复杂度 O(1)
-   - 分组查询:商品、用户、积分分别批量获取
-
-### 数据完整性
-
-1. **字段缺失处理**
-   - 如果商品记录已删除,商品相关字段返回 `null`
-   - 如果用户信息不存在,用户相关字段返回 `null`
-   - 如果没有信用积分记录,`creditScore` 返回 `0`
-   - 风控等级计算异常时返回默认等级 `"O"`
-
-2. **评分有效性**
-   - 买家评分 `buyerRating` 有效范围:1-5 分
-   - 如果未评分,该字段可能为 `null`
+   - 只查询当前页的交易记录,再批量关联其他信息
 
 ---
 
@@ -316,109 +362,171 @@ R<List<SellerEvaluationVo>> result = restTemplate.getForObject(url, R.class);
 
 ---
 
-## 使用场景
-
-### 1. 用户主页展示
-
-在用户主页展示该用户作为卖家的历史交易评价,供其他用户查看。
-
-**场景示例**:
-- 用户 A 点击用户 B 的主页
-- 展示用户 B 作为卖家收到的所有评价
-- 显示评价内容、评分、买家信息等
-
-### 2. 信用评估
-
-通过评价内容、评分和风控等级综合评估卖家的信誉度。
-
-**评估维度**:
-- 评价数量:评价越多,信誉参考价值越高
-- 平均评分:反映买家满意度
-- 风控等级:反映用户违规情况
-- 信用积分:反映用户交易活跃度
-
-### 3. 交易决策辅助
-
-买家在决定是否与某卖家交易时,可以查看其历史评价。
-
-**决策参考**:
-- 查看近期评价内容
-- 查看风控评分等级
-- 了解卖家信用积分
-- 参考其他买家的评价
-
----
-
-## 技术实现
-
-### 实现方式
-
-| 技术点 | 实现方案 |
-|--------|----------|
-| 查询方式 | MyBatis Plus LambdaQueryWrapper |
-| 关联查询 | 批量查询 + Map 索引 |
-| 风控计算 | 实时查询违规记录并计算等级 |
-| 事务处理 | 无需事务(只读查询) |
-| 性能优化 | 批量查询避免 N+1 问题 |
-
-### 代码示例
-
-```java
-// 1. 查询交易记录
-LambdaQueryWrapper<SecondTradeRecord> tradeWrapper = new LambdaQueryWrapper<>();
-tradeWrapper.eq(SecondTradeRecord::getSellerId, sellerId)
-        .eq(SecondTradeRecord::getDeleteFlag, 0)
-        .isNotNull(SecondTradeRecord::getBuyerEvaluate)
-        .ne(SecondTradeRecord::getBuyerEvaluate, "")
-        .orderByDesc(SecondTradeRecord::getCreatedTime);
-List<SecondTradeRecord> tradeRecords = mapper.selectList(tradeWrapper);
-
-// 2. 批量查询商品信息
-LambdaQueryWrapper<SecondGoodsRecord> goodsWrapper = new LambdaQueryWrapper<>();
-goodsWrapper.in(SecondGoodsRecord::getId, goodsRecordIds);
-List<SecondGoodsRecord> goodsRecords = goodsRecordMapper.selectList(goodsWrapper);
-
-// 3. 批量查询用户信息
-LambdaQueryWrapper<LifeUser> userWrapper = new LambdaQueryWrapper<>();
-userWrapper.in(LifeUser::getId, buyerIds).eq(LifeUser::getDeleteFlag, 0);
-List<LifeUser> buyers = lifeUserMapper.selectList(userWrapper);
-
-// 4. 批量查询信用积分
-LambdaQueryWrapper<SecondUserCredit> creditWrapper = new LambdaQueryWrapper<>();
-creditWrapper.in(SecondUserCredit::getUserId, allUserIds)
-        .eq(SecondUserCredit::getDeleteFlag, 0);
-List<SecondUserCredit> credits = secondUserCreditMapper.selectList(creditWrapper);
-
-// 5. 计算风控等级
-String creditLevel = calculateCreditLevel(userId);
+## 前端分页实现示例
+
+### Vue 3 + Element Plus
+
+```vue
+<template>
+  <div class="evaluation-list">
+    <!-- 评价列表 -->
+    <div v-for="item in evaluations" :key="item.id" class="evaluation-item">
+      <div class="buyer-info">
+        <img :src="item.buyerImage" :alt="item.buyerName" />
+        <span>{{ item.buyerName }}</span>
+        <el-rate :model-value="item.buyerRating" disabled />
+      </div>
+      <div class="evaluation-content">{{ item.buyerEvaluate }}</div>
+      <div class="evaluation-time">{{ item.createdTime }}</div>
+    </div>
+    
+    <!-- 分页组件 -->
+    <el-pagination
+      v-model:current-page="pageNum"
+      v-model:page-size="pageSize"
+      :page-sizes="[10, 20, 50, 100]"
+      :total="total"
+      layout="total, sizes, prev, pager, next, jumper"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue';
+import axios from 'axios';
+
+const sellerId = ref(123);
+const pageNum = ref(1);
+const pageSize = ref(10);
+const total = ref(0);
+const evaluations = ref([]);
+
+// 加载评价列表
+const loadEvaluations = async () => {
+  try {
+    const response = await axios.get('/secondTradeRecord/getSellerEvaluationList', {
+      params: {
+        sellerId: sellerId.value,
+        pageNum: pageNum.value,
+        pageSize: pageSize.value
+      }
+    });
+    
+    const { records, total: totalCount } = response.data.data;
+    evaluations.value = records;
+    total.value = totalCount;
+  } catch (error) {
+    console.error('加载失败:', error);
+  }
+};
+
+// 每页条数改变
+const handleSizeChange = (newSize) => {
+  pageSize.value = newSize;
+  pageNum.value = 1; // 重置到第一页
+  loadEvaluations();
+};
+
+// 当前页改变
+const handleCurrentChange = (newPage) => {
+  pageNum.value = newPage;
+  loadEvaluations();
+};
+
+onMounted(() => {
+  loadEvaluations();
+});
+</script>
 ```
 
-### 数据库表
-
-| 表名 | 说明 | 关联字段 |
-|------|------|----------|
-| second_trade_record | 交易记录表 | 主表 |
-| second_goods_record | 商品记录表 | goods_record_id |
-| life_user | 用户表 | buyer_id, seller_id |
-| second_user_credit | 用户信用积分表 | user_id |
-| second_risk_control_record | 风控记录表 | user_id(用于计算等级) |
-
-### 相关文件
-
-1. **Controller**  
-   `alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java`
-
-2. **Service Interface**  
-   `alien-second/src/main/java/shop/alien/second/service/SecondTradeRecordService.java`
-
-3. **Service Implementation**  
-   `alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java`
-
-4. **VO Object**  
-   `alien-entity/src/main/java/shop/alien/entity/second/vo/SellerEvaluationVo.java`
+### React + Ant Design
+
+```jsx
+import React, { useState, useEffect } from 'react';
+import { Pagination, Rate, Avatar, List } from 'antd';
+import axios from 'axios';
+
+function SellerEvaluationList({ sellerId }) {
+  const [pageNum, setPageNum] = useState(1);
+  const [pageSize, setPageSize] = useState(10);
+  const [total, setTotal] = useState(0);
+  const [evaluations, setEvaluations] = useState([]);
+  const [loading, setLoading] = useState(false);
+
+  // 加载评价列表
+  const loadEvaluations = async () => {
+    setLoading(true);
+    try {
+      const response = await axios.get('/secondTradeRecord/getSellerEvaluationList', {
+        params: { sellerId, pageNum, pageSize }
+      });
+      
+      const { records, total: totalCount } = response.data.data;
+      setEvaluations(records);
+      setTotal(totalCount);
+    } catch (error) {
+      console.error('加载失败:', error);
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  useEffect(() => {
+    loadEvaluations();
+  }, [pageNum, pageSize, sellerId]);
+
+  // 页码改变
+  const handlePageChange = (page, size) => {
+    setPageNum(page);
+    setPageSize(size);
+  };
+
+  return (
+    <div>
+      <List
+        loading={loading}
+        dataSource={evaluations}
+        renderItem={(item) => (
+          <List.Item>
+            <List.Item.Meta
+              avatar={<Avatar src={item.buyerImage} />}
+              title={
+                <div>
+                  <span>{item.buyerName}</span>
+                  <Rate value={item.buyerRating} disabled style={{ marginLeft: 10 }} />
+                </div>
+              }
+              description={
+                <>
+                  <div>{item.buyerEvaluate}</div>
+                  <div style={{ color: '#999', fontSize: 12, marginTop: 5 }}>
+                    {item.createdTime}
+                  </div>
+                </>
+              }
+            />
+          </List.Item>
+        )}
+      />
+      
+      <Pagination
+        current={pageNum}
+        pageSize={pageSize}
+        total={total}
+        onChange={handlePageChange}
+        showSizeChanger
+        showQuickJumper
+        showTotal={(total) => `共 ${total} 条`}
+        pageSizeOptions={[10, 20, 50, 100]}
+      />
+    </div>
+  );
+}
 
-5. **Entity**  
-   `alien-entity/src/main/java/shop/alien/entity/second/SecondTradeRecord.java`
+export default SellerEvaluationList;
+```
 
 ---
 
@@ -430,120 +538,34 @@ String creditLevel = calculateCreditLevel(userId);
    - `sellerId` 为必传参数,用于查看指定用户的评价列表
    - 不传或传空会返回错误:`"卖家ID不能为空"`
 
-2. **数据权限**
+2. **分页参数**
+   - `pageNum` 和 `pageSize` 为可选参数,有默认值
+   - pageSize 最大值限制为 100,超过自动修正
+
+3. **数据权限**
    - 接口不做权限校验,任何人都可以查看用户主页的公开评价
    - 如需增加权限控制,请联系后端开发人员
 
-3. **空数据处理**
+4. **空数据处理**
    - 如果该用户没有收到任何评价,返回空数组 `[]`
-   - 不会返回 `null`,前端可以直接遍历
+   - total 为 0,pages 为 0
+   - 前端需要处理空状态展示
 
-4. **字段可空性**
+5. **字段可空性**
    - 部分字段可能为 `null`,前端需要做空值判断
    - 建议使用可选链操作符或空值合并运算符
 
-5. **评分范围**
-   - 买家评分 `buyerRating` 的有效范围是 1-5 分
-   - 超出范围的数据为异常数据
-
-### 💡 最佳实践
-
-1. **前端展示建议**
-   ```javascript
-   // 显示买家昵称,为空时显示默认值
-   const buyerName = evaluation.buyerName || '匿名用户';
-   
-   // 显示评分,为空时显示未评分
-   const rating = evaluation.buyerRating ? `${evaluation.buyerRating}分` : '未评分';
-   
-   // 风控等级颜色映射
-   const levelColorMap = {
-     'O': 'green',  // 最好
-     'A': 'green',
-     'B': 'orange',
-     'C': 'orange',
-     'D': 'red',
-     'E': 'red'     // 最差
-   };
-   ```
-
-2. **缓存策略**
-   - 评价数据变化频率低,建议前端缓存
-   - 缓存时间:5-10 分钟
-   - 用户主动刷新时清除缓存
-
-3. **分页处理**
-   - 当前接口返回所有评价
-   - 如评价数量过多,建议前端实现虚拟滚动
-   - 或联系后端增加分页功能
-
----
-
-## 测试用例
-
-### 测试场景 1:正常查询
-
-**测试步骤**:
-1. 准备测试数据:用户 ID 为 123 的卖家有 3 条评价记录
-2. 调用接口:`GET /secondTradeRecord/getSellerEvaluationList?sellerId=123`
-3. 验证响应:返回 3 条评价数据
-
-**期望结果**:
-- 返回 code = 200
-- data 数组长度为 3
-- 每条数据包含完整字段
-- 按创建时间倒序排列
-
----
-
-### 测试场景 2:无评价数据
-
-**测试步骤**:
-1. 准备测试数据:用户 ID 为 999 的卖家没有任何评价
-2. 调用接口:`GET /secondTradeRecord/getSellerEvaluationList?sellerId=999`
-3. 验证响应:返回空数组
-
-**期望结果**:
-- 返回 code = 200
-- data 为空数组 `[]`
-
----
-
-### 测试场景 3:参数缺失
-
-**测试步骤**:
-1. 调用接口:`GET /secondTradeRecord/getSellerEvaluationList`(不传 sellerId)
-2. 验证响应:返回错误信息
-
-**期望结果**:
-- 返回 code = 500
-- msg = "获取评价列表失败: 卖家ID不能为空"
-
----
-
-### 测试场景 4:风控等级计算
-
-**测试步骤**:
-1. 准备测试数据:
-   - 买家 A(ID 456)有 2 条违规记录
-   - 买家 B(ID 789)有 0 条违规记录
-2. 调用接口查询包含这两位买家的评价
-3. 验证风控等级
-
-**期望结果**:
-- 买家 A 的 `buyerCreditLevel` = "A"
-- 买家 B 的 `buyerCreditLevel` = "O"
-
 ---
 
 ## 版本历史
 
 | 版本 | 日期 | 修改内容 | 修改人 |
 |------|------|----------|--------|
-| v1.0 | 2025-11-18 | 初始版本,实现基本功能 | 开发团队 |
-| v1.0 | 2025-11-18 | 优化查询方式,使用 MyBatis Plus | 开发团队 |
-| v1.0 | 2025-11-18 | 增加风控评分等级计算 | 开发团队 |
-| v1.0 | 2025-11-18 | 增加更多用户信息字段 | 开发团队 |
+| v1.0 | 2025-11-18 | 初始版本,返回全部数据 | 开发团队 |
+| v1.1 | 2025-11-18 | **新增分页功能** | 开发团队 |
+| v1.1 | 2025-11-18 | 优化查询方式,使用 MyBatis Plus | 开发团队 |
+| v1.1 | 2025-11-18 | 增加风控评分等级计算 | 开发团队 |
+| v1.1 | 2025-11-18 | 增加更多用户信息字段 | 开发团队 |
 
 ---
 
@@ -557,5 +579,4 @@ String creditLevel = calculateCreditLevel(userId);
 
 ---
 
-*最后更新时间:2025-11-18*
-
+*最后更新时间:2025-11-18(v1.1 - 支持分页)*

+ 13 - 6
alien-second/src/main/java/shop/alien/second/controller/SecondTradeRecordController.java

@@ -1,6 +1,7 @@
 package shop.alien.second.controller;
 
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -161,17 +162,23 @@ public class SecondTradeRecordController {
         return R.data(secondTradeRecordService.modifyTradeRecord(type, tradeId, transactionTime, transactionLatitudeLongitude, transactionLatitudeLongitudeAddress, transactionLocation, messageId));
     }
 
-    @ApiOperation("获取用户作为卖家的交易评价列表")
+    @ApiOperation("获取用户作为卖家的交易评价列表(分页)")
     @ApiOperationSupport(order = 12)
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "sellerId", value = "卖家id(用户主页展示用,必传)", dataType = "Integer", paramType = "query", required = true)
+            @ApiImplicitParam(name = "sellerId", value = "卖家id(用户主页展示用,必传)", dataType = "Integer", paramType = "query", required = true),
+            @ApiImplicitParam(name = "pageNum", value = "页码", dataType = "Integer", paramType = "query", required = false, defaultValue = "1"),
+            @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "Integer", paramType = "query", required = false, defaultValue = "10")
     })
     @GetMapping("/getSellerEvaluationList")
-    public R<List<SellerEvaluationVo>> getSellerEvaluationList(@RequestParam(required = true) Integer sellerId) {
-        log.info("SecondTradeRecordController.getSellerEvaluationList?sellerId={}", sellerId);
+    public R<IPage<SellerEvaluationVo>> getSellerEvaluationList(
+            @RequestParam(required = true) Integer sellerId,
+            @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+            @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        log.info("SecondTradeRecordController.getSellerEvaluationList?sellerId={}, pageNum={}, pageSize={}", 
+                sellerId, pageNum, pageSize);
         try {
-            List<SellerEvaluationVo> evaluationList = secondTradeRecordService.getSellerEvaluationList(sellerId);
-            return R.data(evaluationList);
+            IPage<SellerEvaluationVo> evaluationPage = secondTradeRecordService.getSellerEvaluationList(sellerId, pageNum, pageSize);
+            return R.data(evaluationPage);
         } catch (Exception e) {
             log.error("SecondTradeRecordController.getSellerEvaluationList?error: {}", e.getMessage(), e);
             return R.fail("获取评价列表失败: " + e.getMessage());

+ 6 - 3
alien-second/src/main/java/shop/alien/second/service/SecondTradeRecordService.java

@@ -1,6 +1,7 @@
 package shop.alien.second.service;
 
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import shop.alien.entity.result.BusinessException;
 import shop.alien.entity.second.SecondTradeRecord;
@@ -41,10 +42,12 @@ public interface SecondTradeRecordService extends IService<SecondTradeRecord> {
     boolean modifyTradeRecord(int type, Integer tradeId, String transactionTime, String transactionLatitudeLongitude, String transactionLatitudeLongitudeAddress, String transactionLocation, String messageId) throws Exception;
 
     /**
-     * 获取用户作为卖家的交易评价列表
+     * 获取用户作为卖家的交易评价列表(分页)
      *
      * @param sellerId 卖家ID(用户ID,必传)
-     * @return 卖家评价列表,包含买家信息、评价内容、评分、风控评分等级等
+     * @param pageNum 页码
+     * @param pageSize 每页条数
+     * @return 卖家评价分页列表,包含买家信息、评价内容、评分、风控评分等级等
      */
-    List<SellerEvaluationVo> getSellerEvaluationList(Integer sellerId) throws Exception;
+    IPage<SellerEvaluationVo> getSellerEvaluationList(Integer sellerId, Integer pageNum, Integer pageSize) throws Exception;
 }

+ 42 - 9
alien-second/src/main/java/shop/alien/second/service/impl/SecondTradeRecordServiceImpl.java

@@ -5,6 +5,8 @@ import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -766,22 +768,38 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
     }
 
     /**
-     * 获取用户作为卖家的交易评价列表
+     * 获取用户作为卖家的交易评价列表(分页)
      *
      * @param sellerId 卖家ID(用户ID,必传)
-     * @return 卖家评价列表
+     * @param pageNum 页码
+     * @param pageSize 每页条数
+     * @return 卖家评价分页列表
      */
     @Override
-    public List<SellerEvaluationVo> getSellerEvaluationList(Integer sellerId) throws Exception {
+    public IPage<SellerEvaluationVo> getSellerEvaluationList(Integer sellerId, Integer pageNum, Integer pageSize) throws Exception {
         try {
-            log.info("SecondTradeRecordServiceImpl.getSellerEvaluationList(): sellerId={}", sellerId);
+            log.info("SecondTradeRecordServiceImpl.getSellerEvaluationList(): sellerId={}, pageNum={}, pageSize={}", 
+                    sellerId, pageNum, pageSize);
             
             // sellerId必传校验
             if (sellerId == null) {
                 throw new Exception("卖家ID不能为空");
             }
             
-            // 使用MyBatis Plus方式查询交易记录
+            // 参数默认值处理
+            if (pageNum == null || pageNum < 1) {
+                pageNum = 1;
+            }
+            if (pageSize == null || pageSize < 1) {
+                pageSize = 10;
+            }
+            // 限制最大每页条数
+            if (pageSize > 100) {
+                pageSize = 100;
+            }
+            
+            // 使用MyBatis Plus分页查询交易记录
+            Page<SecondTradeRecord> page = new Page<>(pageNum, pageSize);
             LambdaQueryWrapper<SecondTradeRecord> tradeWrapper = new LambdaQueryWrapper<>();
             tradeWrapper.eq(SecondTradeRecord::getSellerId, sellerId)
                     .eq(SecondTradeRecord::getDeleteFlag, 0)
@@ -789,11 +807,15 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
                     .ne(SecondTradeRecord::getBuyerEvaluate, "")
                     .orderByDesc(SecondTradeRecord::getCreatedTime);
             
-            List<SecondTradeRecord> tradeRecords = secondTradeRecordMapper.selectList(tradeWrapper);
+            IPage<SecondTradeRecord> tradePage = secondTradeRecordMapper.selectPage(page, tradeWrapper);
+            List<SecondTradeRecord> tradeRecords = tradePage.getRecords();
             
+            // 如果没有数据,直接返回空分页对象
             if (tradeRecords.isEmpty()) {
                 log.info("SecondTradeRecordServiceImpl.getSellerEvaluationList(): 未查询到评价记录");
-                return new java.util.ArrayList<>();
+                Page<SellerEvaluationVo> emptyPage = new Page<>(pageNum, pageSize);
+                emptyPage.setTotal(0);
+                return emptyPage;
             }
             
             // 获取所有商品记录ID、买家ID和卖家ID
@@ -858,6 +880,10 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
                 vo.setTransactionAmount(trade.getTransactionAmount());
                 vo.setBuyerId(trade.getBuyerId());
                 vo.setBuyerEvaluate(trade.getBuyerEvaluate());
+                // 卖家交易完成时间(评价时间,评分时间)
+                vo.setSellerCompleteTime(trade.getSellerCompleteTime());
+                // 买家交易完成时间(评价时间,评分时间)
+                vo.setBuyerCompleteTime(trade.getBuyerCompleteTime());
                 vo.setBuyerRating(trade.getBuyerRating());
                 vo.setTransactionTime(trade.getTransactionTime());
                 vo.setTradeStatus(trade.getTradeStatus());
@@ -910,8 +936,15 @@ public class SecondTradeRecordServiceImpl extends ServiceImpl<SecondTradeRecordM
                 evaluationList.add(vo);
             }
             
-            log.info("SecondTradeRecordServiceImpl.getSellerEvaluationList(): 查询到{}条评价记录", evaluationList.size());
-            return evaluationList;
+            // 构建分页返回对象
+            Page<SellerEvaluationVo> resultPage = new Page<>(pageNum, pageSize);
+            resultPage.setRecords(evaluationList);
+            resultPage.setTotal(tradePage.getTotal());
+            resultPage.setPages(tradePage.getPages());
+            
+            log.info("SecondTradeRecordServiceImpl.getSellerEvaluationList(): 查询到{}条评价记录,共{}页", 
+                    evaluationList.size(), resultPage.getPages());
+            return resultPage;
         } catch (Exception e) {
             log.error("SecondTradeRecordServiceImpl.getSellerEvaluationList(): Error Msg={}", e.getMessage(), e);
             throw new Exception("获取卖家评价列表失败: " + e.getMessage());