From 4d8a1e1e90919b8c9b7ca594d57a6aa5c0b29018 Mon Sep 17 00:00:00 2001
From: pengda <10266652509@qq.com>
Date: Thu, 15 May 2025 16:49:36 +0800
Subject: [PATCH] =?UTF-8?q?=E8=B4=9F=E6=AF=9B=E5=88=A9=E7=BB=9F=E8=AE=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/components/Pagination.vue            | 130 +++++++++++++++++++++++++++++++
 src/components/super/RankingLeftMenu.vue |   8 +-
 src/router/index.js                      |  42 +++++-----
 src/views/super/Ranking/RankDetail.vue   |  89 ++++++++++-----------
 src/views/super/Ranking/RankList.vue     |  33 ++++++++
 5 files changed, 234 insertions(+), 68 deletions(-)
 create mode 100644 src/components/Pagination.vue

diff --git a/src/components/Pagination.vue b/src/components/Pagination.vue
new file mode 100644
index 0000000..b6b031d
--- /dev/null
+++ b/src/components/Pagination.vue
@@ -0,0 +1,130 @@
+<template>
+    <div class="pagination">
+        <button @click="click('first')" :disabled="cur_page === 1">首页</button>
+        <button @click="click('prev')" :disabled="cur_page === 1">上一页</button>
+        <span class="page-info">第 {{ cur_page }} 页</span>
+        <button @click="click('next')" :disabled="!hasNext">下一页</button>
+        <button @click="click('last')" :disabled="!hasNext">尾页</button>
+        <input type="number" v-model.number="jumpPage" min="1" />
+        <button @click="click('jump')">跳转</button>
+    </div>
+</template>
+
+<script>
+export default {
+    name: 'SimplePager',
+    props: {
+        curPage: {
+            type: Number,
+            required: true
+        },
+        hasNext: {
+            type: Boolean,
+            default: true
+        }
+    },
+    data() {
+        return {
+            jumpPage: null,
+            cur_page: this.curPage,
+        };
+    },
+    watch: {
+        curPage(newVal) {
+            this.jumpPage = newVal;
+            this.cur_page = newVal;
+        }
+    },
+    methods: {
+        click(type) {
+            let payload = {
+                first: 0,
+                prev: 0,
+                next: 0,
+                last: 0,
+                jump: 0,
+                cur_page: this.cur_page
+            };
+
+            switch (type) {
+                case 'first':
+                    payload.first = 1;
+                    payload.cur_page = 1;
+                    break;
+                case 'prev':
+                    payload.prev = 1;
+                    payload.cur_page = Math.max(1, this.cur_page - 1);
+                    break;
+                case 'next':
+                    if (!this.hasNext) return;
+                    payload.next = 1;
+                    payload.cur_page = this.cur_page + 1;
+                    break;
+                case 'last':
+                    payload.last = 1;
+                    payload.cur_page = this.cur_page;
+                    break;
+                case 'jump':
+                    if (this.jumpPage && this.jumpPage > 0) {
+                        payload.jump = this.jumpPage;
+                        payload.cur_page = this.jumpPage;
+                    } else {
+                        return;
+                    }
+                    break;
+            }
+
+            this.$emit('change', payload);
+        }
+    }
+};
+</script>
+<style scoped>
+.pagination {
+    display: flex;
+    align-items: center;
+    flex-wrap: wrap;
+    gap: 8px;
+    margin: 12px 0;
+}
+
+button {
+    padding: 6px 12px;
+    border: 1px solid #ccc;
+    background-color: #f8f8f8;
+    cursor: pointer;
+    border-radius: 4px;
+    font-size: 14px;
+    transition: all 0.2s;
+}
+
+button:hover:not(:disabled) {
+    background-color: #e6f7ff;
+    border-color: #91d5ff;
+}
+
+button:disabled {
+    cursor: not-allowed;
+    opacity: 0.5;
+}
+
+.page-info {
+    font-size: 14px;
+    margin: 0 6px;
+}
+
+input[type='number'] {
+    width: 70px;
+    padding: 8px 8px;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+    font-size: 14px;
+    transition: border-color 0.2s, box-shadow 0.2s;
+    outline: none;
+}
+
+input[type='number']:focus {
+    border-color: #40a9ff;
+    box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
+}
+</style>
\ No newline at end of file
diff --git a/src/components/super/RankingLeftMenu.vue b/src/components/super/RankingLeftMenu.vue
index 250a2fd..1c59105 100644
--- a/src/components/super/RankingLeftMenu.vue
+++ b/src/components/super/RankingLeftMenu.vue
@@ -53,6 +53,10 @@ export default {
                             name: '退单数排行',
                             path: '/super/ranking/checkRefund',
                         },
+                        {
+                            name: '负毛利排行',
+                            path: '/super/ranking/loss',
+                        },
                     ]
                 },
                 {
@@ -78,10 +82,6 @@ export default {
                     imgActive: require('@/assets/super/ranking-menu.svg'),
                     list: [
                         {
-                            name: '负毛利',
-                            path: '/super/ranking/loss',
-                        },
-                        {
                             name: '采购价',
                             path: '/super/ranking/purchase',
                         },
diff --git a/src/router/index.js b/src/router/index.js
index 3c0ef1c..942ec7e 100755
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -161,6 +161,12 @@ const routes = [{
         props: {pageTitle:'产品 - 退单数排行', rank_type: 3, type: 'check_type'}
       },
       {
+        path: 'loss',
+        name: '产品负毛利排行',
+        component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/RankList.vue'),
+        props: {pageTitle:'产品 - 负毛利排行', rank_type: 5, type: 'loss'}
+      },
+      {
         path: 'agentProfit',
         name: '代理商毛利润排行',
         component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/RankBatchList.vue'),
@@ -179,12 +185,6 @@ const routes = [{
         props: {pageTitle:'代理商 - 新加盟', type: 'agentnew', showDateSelect: false}
       },
       {
-        path: 'loss',
-        name: '负毛利',
-        component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/RankDetail.vue'),
-        props: {pageTitle:'负毛利 - 排行', type: 'loss'}
-      },
-      {
         path: 'purchase',
         name: '采购价',
         component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/Purchase.vue'),
@@ -196,20 +196,26 @@ const routes = [{
         component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/Purchase.vue'),
         props: {pageTitle:'设置 - 阶段采购', type: 'stagePurchase'}
       },
+      {
+        path: 'detail',
+        name: '详情',
+        component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/RankDetail.vue'),
+        props: {pageTitle:'详情', type: 'day', showDateSelect: false, lookMore:false}
+      },
+      {
+        path: 'list',
+        name: '列表',
+        component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/RankList.vue'),
+        props: {pageTitle:'详情', showDateSelect: false, lookMore:false}
+      },
+      {
+        path: 'order',
+        name: '订单统计',
+        component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/RankDetail.vue'),
+        props: {pageTitle:'订单统计', type: 'order', showDateSelect: false}
+      },
     ]
   },
-  {
-    path: '/super/ranking/detail',
-    name: '详情',
-    component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/RankDetail.vue'),
-    props: {pageTitle:'详情', type: 'day', showDateSelect: false, lookMore:false}
-  },
-  {
-    path: '/super/ranking/list',
-    name: '列表',
-    component: () => import( /* webpackChunkName: "Ranking" */ '../views/super/Ranking/RankList.vue'),
-    props: {pageTitle:'详情', showDateSelect: false, lookMore:false}
-  },
 ]
 
 const router = new VueRouter({
diff --git a/src/views/super/Ranking/RankDetail.vue b/src/views/super/Ranking/RankDetail.vue
index 14adb14..70331eb 100644
--- a/src/views/super/Ranking/RankDetail.vue
+++ b/src/views/super/Ranking/RankDetail.vue
@@ -199,33 +199,22 @@
             </el-form>
         </div>
 
-        <div class=" flex-common" v-if="dataType == 'loss'">
-            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
-                <h3 style="margin: 0;"></h3>
-                <span style="font-size: 14px; color: #999;">总负毛利:{{ total_value }}</span>
-            </div>
-
+        <div class=" flex-common" v-if="dataType == 'order'">
             <el-form>
-                <el-table :data="tableData"
-                          style="width: 100%"
-                          @sort-change="handleSortChange"
-                          @cell-mouse-enter="handleRowHover">
-
-                    <el-table-column prop="sort" label="排序"></el-table-column>
-
-                    <el-table-column prop="1" label="日期" sortable="custom">
+                <el-table :data="tableData" style="width: 100%">
+                    <el-table-column prop="sale_id" label="订单ID"></el-table-column>
+                    <el-table-column prop="income" label="收入"></el-table-column>
+                    <el-table-column prop="cost" label="成本"></el-table-column>
+                    <el-table-column prop="profit" label="毛利"></el-table-column>
+                    <el-table-column prop="is_refund" label="是否退款">
                         <template slot-scope="scope">
-                            {{ scope.row.value_1 }}
-                        </template>
-                    </el-table-column>
-
-                    <el-table-column prop="2" label="负毛利" sortable="custom">
-                        <template slot-scope="scope">
-                            {{ scope.row.value_2 }}
+                            {{ scope.row.is_refund == 1 ? '是' : '否' }}
                         </template>
                     </el-table-column>
+                    <el-table-column prop="sale_date" label="销售日期"></el-table-column>
                 </el-table>
             </el-form>
+            <Pagination :curPage="cur_page" :hasNext="has_next" @change="handleChange" />
         </div>
     </div>
 </template>
@@ -233,6 +222,7 @@
 import DateSelect from '@/components/super/DateSelect.vue';
 import CustomDropdown from '@/components/CustomDropdown.vue';
 import HoverImage from "@/components/super/HoverImage.vue";
+import Pagination from "@/components/Pagination.vue";
 
 export default {
     name: 'rank_detail',
@@ -259,6 +249,7 @@ export default {
         },
     },
     components: {
+        Pagination,
         HoverImage,
         DateSelect,
         CustomDropdown
@@ -292,6 +283,10 @@ export default {
             top_list: [],
             growth_list: [],
             show_detail_index: 0,
+            has_next: false,
+            cur_page: 1,
+            page_size: 20,
+            page_point: 0,
         }
     },
     mounted() {
@@ -408,9 +403,8 @@ export default {
                 return true;
             }
 
-            if (this.dataType == 'loss') {
-                this.onlyYear = false;
-                this.getLossDetail(obj)
+            if (this.dataType == 'order') {
+                this.getOrderList()
                 return true;
             }
 
@@ -441,28 +435,6 @@ export default {
                 console.error(error, 'error')
             })
         },
-        getLossDetail(obj) {
-            const that = this
-            that.tableData = []
-            that.total_value = 0
-            this.$http('POST', '/supernew/ajax_get_loss_detail', {
-                aid: that.aid,
-                ver_type: that.ver_type,
-                check_type: that.check_type,
-                date: that.text,
-                ...obj
-            }).then(response => {
-                this.$nextTick(() => {
-                    that.tableData = response.data.list
-                    that.total_value = response.data.total_value
-                    that.total = response.data.total
-
-                    if (that.showfilterTitle) that.filterTitle = response.data.title
-                })
-            }).catch(error => {
-                console.error(error, 'error')
-            })
-        },
         getRankingList(obj) {
             const that = this
             that.tableData1 = []
@@ -492,6 +464,31 @@ export default {
                 console.error(error, 'error')
             })
         },
+        getOrderList(obj) {
+            const that = this
+            that.tableData = []
+            this.$http('POST', '/supernew/ajax_get_order_check_list', {
+                aid: that.aid,
+                ver_type: that.ver_type,
+                check_type: that.check_type,
+                page_point: that.page_point,
+                lose: 1,
+                ...obj
+            }).then(response => {
+                this.$nextTick(() => {
+                    that.tableData = response.data.list
+                    that.has_next = response.data.hasNext
+                    if(!that.has_next) that.cur_page = response.data.cur_page
+                    that.page_point = response.data.page_point
+                })
+            }).catch(error => {
+                console.error(error, 'error')
+            })
+        },
+        handleChange(payload) {
+            this.cur_page = payload.cur_page
+            this.getOrderList(payload)
+        }
     }
 }
 </script>
diff --git a/src/views/super/Ranking/RankList.vue b/src/views/super/Ranking/RankList.vue
index 82542cb..ddfa265 100644
--- a/src/views/super/Ranking/RankList.vue
+++ b/src/views/super/Ranking/RankList.vue
@@ -219,11 +219,13 @@ export default {
                 1: '毛利润',
                 2: '订单数',
                 3: '退单数',
+                5: '负毛利',
             },
             type_desc: {
                 'agent': '代理商昵称',
                 'ver_type': '品牌名称',
                 'check_type': '服务名称',
+                'loss': '服务名称',
             },
             type_select: {
                 'ver_type': '按品牌名称',
@@ -278,6 +280,10 @@ export default {
             if (this.$route.query.rank_type) this.dataRank = this.$route.query.rank_type
             if (Object.keys(this.$route.query).length > 0) this.showfilterTitle = true
 
+            if (this.dataType == 'loss') {
+                this.sort_order = 1;
+            }
+
             this.getRankingData(); // 每次路由变化都重新获取数据
         },
         handleUpdateView(newView) {
@@ -439,6 +445,9 @@ export default {
             if (this.dataType == 'check_type') {
                 this.getTypeRanking()
             }
+            if (this.dataType == 'loss') {
+                this.getLossList()
+            }
         },
         getAgentRanking() {
             const that = this
@@ -550,6 +559,30 @@ export default {
                 console.error(error, 'error')
             })
         },
+        getLossList() {
+            const that = this
+            that.tableData = []
+            this.$http('POST', '/supernew/ajax_get_loss_list', {
+                aid: that.aid,
+                ver_type: that.ver_type,
+                check_type: that.check_type,
+                date: that.text,
+                sort_by: that.sort_by,
+                sort_order: that.sort_order,
+                cur_page: that.currentPage,
+                page_size: that.pageSize,
+            }).then(response => {
+                this.$nextTick(() => {
+                    that.tableData = response.data.list
+                    that.total_value = response.data.total_value
+                    that.total = response.data.total
+
+                    if (that.showfilterTitle) that.filterTitle = response.data.title
+                })
+            }).catch(error => {
+                console.error(error, 'error')
+            })
+        },
         handleSizeChange(val) {
             this.pageSize = val
             this.getRankingData()