Sfoglia il codice sorgente

feat(lakala): 添加拉卡拉交易记录管理功能

- 在后台管理菜单中新增"拉卡拉交易记录"菜单项
- 创建 TradeOrder Vue 组件用于展示交易记录列表
- 实现交易记录的搜索、分页和详情展示功能
- 添加对应的后端控制器 TradeOrderController
- 新增 PaymentRecordService 服务类处理数据查询逻辑
- 配置 trade_order 路由规则并应用权限中间件
runphp 4 mesi fa
parent
commit
0693bdb26c

+ 273 - 0
resource/admin/TradeOrder.vue

@@ -0,0 +1,273 @@
+<template>
+  <div class="trade-order">
+    <!-- 搜索条件 -->
+    <el-card class="search-card">
+      <el-form :model="searchForm" label-width="140px" inline>
+        <el-form-item label="订单编号">
+          <el-input
+              v-model="searchForm.order_sn"
+              placeholder="请输入订单编号"
+              clearable
+              @keyup.enter="handleSearch"
+          />
+        </el-form-item>
+        <el-form-item label="商户支付订单号">
+          <el-input 
+            v-model="searchForm.out_trade_no" 
+            placeholder="请输入商户支付订单号" 
+            clearable
+            @keyup.enter="handleSearch"
+          />
+        </el-form-item>
+        <el-form-item label="拉卡拉交易号">
+          <el-input 
+            v-model="searchForm.transaction_id" 
+            placeholder="请输入拉卡拉交易号" 
+            clearable
+            @keyup.enter="handleSearch"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleSearch">查询</el-button>
+          <el-button @click="handleReset">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <!-- 列表数据 -->
+    <el-card class="table-card">
+      <template #header>
+        <div class="table-header">
+          <div class="header-title">拉卡拉交易记录列表</div>
+        </div>
+      </template>
+      
+      <el-table
+        v-loading="loading"
+        :data="tableData"
+        border
+        stripe
+      >
+        <el-table-column prop="id" label="ID" width="80" />
+        <el-table-column prop="order_sn" label="订单编号" width="180" />
+        <el-table-column prop="out_trade_no" label="商户支付订单号" min-width="200" />
+        <el-table-column prop="transaction_id" label="拉卡拉交易号" min-width="250" />
+        <el-table-column prop="amount" label="支付金额(元)" width="120" align="right">
+          <template #default="{ row }">
+            <span class="amount-highlight">{{ formatAmount(row.amount) }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="快递信息" min-width="250">
+          <template #default="{ row }">
+            <div class="express-info">
+              <div>快递公司:{{ row.express_name || '-' }}</div>
+              <div>快递单号:{{ row.express_number || '-' }}</div>
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column label="收货人信息" min-width="250">
+          <template #default="{ row }">
+            <div class="consignee-info">
+              <div>收货人:{{ row.consignee || '-' }}</div>
+              <div>联系电话:{{ row.mobile || '-' }}</div>
+              <div class="address-line">收货地址:{{ (row.province || '') + (row.city || '') + (row.district || '') + (row.address || '') }}</div>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+      
+      <!-- 分页 -->
+      <el-pagination
+        v-model:current-page="pagination.page"
+        v-model:page-size="pagination.limit"
+        :total="pagination.total"
+        :page-sizes="[10, 20, 50, 100]"
+        layout="total, sizes, prev, pager, next, jumper"
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        class="pagination"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "TradeOrder",
+  props: {
+    axiosInstance: {
+      type: Object,
+      default: null
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      searchForm: {
+        out_trade_no: '',
+        order_sn: '',
+        transaction_id: ''
+      },
+      statusOptions: [
+        { label: '待支付', value: 0 },
+        { label: '支付中', value: 1 },
+        { label: '成功', value: 2 },
+        { label: '失败', value: 3 },
+        { label: '已关闭', value: 4 },
+        { label: '退款中', value: 5 }
+      ],
+      bizTypeOptions: [
+        { label: '商品订单支付', value: 1 }
+      ],
+      tableData: [],
+      pagination: {
+        page: 1,
+        limit: 10,
+        total: 0
+      }
+    }
+  },
+  async created() {
+    this.fetchData()
+  },
+  methods: {
+    // 格式化金额显示
+    formatAmount(amount) {
+      return amount || amount === 0 ? amount : '-';
+    },
+
+    // 获取业务类型文本
+    getBizTypeText(bizType) {
+      const bizTypeMap = {
+        1: '商品订单支付'
+      };
+      return bizTypeMap[bizType] || bizType;
+    },
+
+    // 获取列表数据
+    async fetchData() {
+      if (!this.axiosInstance) {
+        this.$message.error('无法获取请求实例')
+        return
+      }
+      
+      this.loading = true
+      try {
+        const params = {
+          page: this.pagination.page,
+          limit: this.pagination.limit,
+          out_trade_no: this.searchForm.out_trade_no,
+          order_sn: this.searchForm.order_sn,
+          transaction_id: this.searchForm.transaction_id
+        }
+        
+        const res = await this.axiosInstance.get('/lakala/trade_order', { params })
+        if (res.code === 200) {
+          this.tableData = res.page.data
+          this.pagination.total = res.page.total
+          this.pagination.limit = res.page.per_page
+        } else {
+          this.$message.error(res.msg || res.message || '获取数据失败')
+        }
+      } catch (error) {
+        console.error('获取交易记录列表失败:', error)
+        this.$message.error('获取数据失败: ' + (error.message || '未知错误'))
+      } finally {
+        this.loading = false
+      }
+    },
+
+    // 查询
+    handleSearch() {
+      this.pagination.page = 1
+      this.fetchData()
+    },
+    
+    // 重置
+    handleReset() {
+      this.searchForm = {
+        out_trade_no: '',
+        order_sn: '',
+        transaction_id: ''
+      }
+      this.pagination.page = 1
+      this.fetchData()
+    },
+    
+    // 分页相关
+    handleSizeChange(val) {
+      this.pagination.limit = val
+      this.pagination.page = 1
+      this.fetchData()
+    },
+    
+    handleCurrentChange(val) {
+      this.pagination.page = val
+      this.fetchData()
+    }
+  }
+}
+</script>
+
+<style scoped>
+.trade-order {
+  padding: 20px;
+}
+
+.search-card {
+  margin-bottom: 20px;
+}
+
+.table-card {
+  margin-bottom: 20px;
+}
+
+.table-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.header-title {
+  font-size: 16px;
+  font-weight: bold;
+}
+
+.pagination {
+  margin-top: 20px;
+  text-align: right;
+}
+
+/* 支付金额高亮显示 */
+.amount-highlight {
+  font-size: 16px;
+  font-weight: 600;
+  color: #e65a00;
+}
+
+/* 快递信息样式 */
+.express-info div {
+  margin-bottom: 4px;
+  font-size: 13px;
+}
+
+.express-info div:last-child {
+  margin-bottom: 0;
+}
+
+/* 收货人信息样式 */
+.consignee-info div {
+  margin-bottom: 4px;
+  font-size: 13px;
+}
+
+.consignee-info div:last-child {
+  margin-bottom: 0;
+}
+
+.address-line {
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+</style>

+ 8 - 1
resource/admin/index.vue

@@ -14,6 +14,9 @@
           <el-menu-item index="profitShareOrder">
             <span>分帐申请</span>
           </el-menu-item>
+          <el-menu-item index="tradeOrder">
+            <span>拉卡拉交易记录</span>
+          </el-menu-item>
         </el-menu>
       </el-header>
       
@@ -30,12 +33,14 @@
 <script>
 import ProfitShareReceiver from './ProfitShareReceiver.vue'
 import ProfitShareOrder from './ProfitShareOrder.vue'
+import TradeOrder from './TradeOrder.vue'
 
 export default {
   name: 'LakalaAdmin',
   components: {
     ProfitShareReceiver,
-    ProfitShareOrder
+    ProfitShareOrder,
+    TradeOrder
   },
   props: {
     axiosInstance: {
@@ -54,6 +59,8 @@ export default {
         return 'ProfitShareReceiver'
       } else if (this.activeMenu === 'profitShareOrder') {
         return 'ProfitShareOrder'
+      } else if (this.activeMenu === 'tradeOrder') {
+        return 'TradeOrder'
       }
       return 'ProfitShareReceiver'
     }

+ 5 - 1
route/admin.php

@@ -4,7 +4,8 @@ declare(strict_types=1);
 use think\facade\Route;
 use SixShop\Lakala\Controller\Admin\{
     ProfitShareReceiverController,
-    ProfitShareOrderController
+    ProfitShareOrderController,
+    TradeOrderController
 };
 use SixShop\System\Middleware\MacroPageMiddleware;
 // Admin路由
@@ -21,4 +22,7 @@ Route::resource('profit_share_receiver', ProfitShareReceiverController::class, f
     ->middleware(['auth', MacroPageMiddleware::class]);
 
 Route::resource('profit_share_order', ProfitShareOrderController::class)
+    ->middleware(['auth', MacroPageMiddleware::class]);
+
+Route::resource('trade_order', TradeOrderController::class)
     ->middleware(['auth', MacroPageMiddleware::class]);

+ 21 - 0
src/Controller/Admin/TradeOrderController.php

@@ -0,0 +1,21 @@
+<?php
+declare(strict_types=1);
+namespace SixShop\Lakala\Controller\Admin;
+
+use SixShop\Core\Request;
+use SixShop\Lakala\Service\PaymentRecordService;
+use think\Response;
+use function SixShop\Core\page_response;
+
+class TradeOrderController
+{
+    public function index(Request $request, PaymentRecordService $service): Response
+    {
+        $params = $request->get([
+            'out_trade_no/s' => '',
+            'order_sn/s' => '',
+            'transaction_id/s' => '',
+        ]);
+        return page_response(page: $service->getTradeOrderList($params, $request->pageAndLimit()));
+    }
+}

+ 41 - 0
src/Service/PaymentRecordService.php

@@ -0,0 +1,41 @@
+<?php
+declare(strict_types=1);
+namespace SixShop\Lakala\Service;
+
+use SixShop\Payment\Model\ExtensionPaymentModel;
+use think\db\Query;
+use think\Paginator;
+
+class PaymentRecordService
+{
+    public function getTradeOrderList(array $params, array $pageAndLimit):Paginator
+    {
+        return ExtensionPaymentModel::alias('p')
+            ->leftJoin('order o', 'o.id = p.order_id')
+            ->where([
+                'p.pay_type' =>'lakala',
+                'p.status' => 2
+            ])
+            ->when($params['order_sn'], function (Query $query) use ($params) {
+                $query->whereLike('o.order_sn', '%' . $params['order_sn'] . '%');
+            })
+            ->when($params['out_trade_no'], function (Query $query) use ($params) {
+                $query->whereLike('p.out_trade_no', '%' . $params['out_trade_no'] . '%');
+            })
+            ->when($params['transaction_id'], function (Query $query) use ($params) {
+                $query->whereLike('p.transaction_id', '%' . $params['transaction_id'] . '%');
+            })
+            ->field([
+                'p.*', 'o.express_name', 'o.express_number',
+                'o.shipping_status',
+                'o.consignee',
+                'o.mobile',
+                'o.province',
+                'o.city',
+                'o.district',
+                'o.address',
+            ])
+            ->order('p.id', 'DESC')
+            ->paginate($pageAndLimit);
+    }
+}