Ver Fonte

新增商品组合退款统计

大大的豆芽 há 10 horas atrás
pai
commit
958f14d395
23 ficheiros alterados com 921 adições e 39 exclusões
  1. 2 2
      admin-ui/.env.development
  2. 8 0
      admin-ui/src/api/order/clothItem.js
  3. 26 0
      admin-ui/src/api/statistics/storeCard.js
  4. 22 14
      admin-ui/src/views/order/cloth/orderList.vue
  5. 221 0
      admin-ui/src/views/order/statistics/bygoods.vue
  6. 201 0
      admin-ui/src/views/order/statistics/chargeTotal.vue
  7. 1 0
      admin-ui/src/views/recharge/batchRecord/index.vue
  8. 1 1
      admin-ui/src/views/recharge/cardVersion/index.vue
  9. 31 0
      yiqi-admin/src/main/java/com/yiqi/admin/controller/order/OrderClothController.java
  10. 32 0
      yiqi-admin/src/main/java/com/yiqi/admin/controller/recharge/RechargePasswordCardController.java
  11. 3 3
      yiqi-common/src/main/java/com/yiqi/core/domain/dto/GoodsSkuStockRecordDTO.java
  12. 28 0
      yiqi-common/src/main/java/com/yiqi/order/domain/dto/GoodsStatisticsQueryDTO.java
  13. 0 3
      yiqi-common/src/main/java/com/yiqi/order/domain/dto/RechargeCardPayDTO.java
  14. 42 0
      yiqi-common/src/main/java/com/yiqi/order/domain/vo/GoodsStatisticsVO.java
  15. 3 0
      yiqi-common/src/main/java/com/yiqi/order/domain/vo/OrderClothPrintVO.java
  16. 147 0
      yiqi-common/src/main/java/com/yiqi/recharge/domain/vo/StoreCardStatisticsVO.java
  17. 13 0
      yiqi-common/src/main/java/com/yiqi/recharge/service/IRechargePasswordCardService.java
  18. 7 0
      yiqi-common/src/main/java/com/yiqi/system/service/ISysStoreService.java
  19. 3 3
      yiqi-core/src/main/java/com/yiqi/order/service/impl/OrderGoodsServiceImpl.java
  20. 13 0
      yiqi-core/src/main/java/com/yiqi/recharge/mapper/RechargePasswordCardMapper.java
  21. 22 2
      yiqi-core/src/main/java/com/yiqi/recharge/service/impl/RechargePasswordCardServiceImpl.java
  22. 77 1
      yiqi-core/src/main/resources/mapper/recharge/RechargePasswordCardMapper.xml
  23. 18 10
      yiqi-system/src/main/java/com/yiqi/system/service/impl/SysStoreServiceImpl.java

+ 2 - 2
admin-ui/.env.development

@@ -5,8 +5,8 @@ VUE_APP_TITLE = 一七管理系统
 ENV = 'development'
 
 
-VUE_APP_BASE_API_HOST = 'http://127.0.0.1:9801'
-VUE_APP_BASE_API = 'http://127.0.0.1:9801'
+VUE_APP_BASE_API_HOST = 'http://192.168.1.114:9801'
+VUE_APP_BASE_API = 'http://192.168.1.114:9801'
 #VUE_APP_BASE_API_HOST = 'http://139.224.65.227:8091/prod-api'
 #VUE_APP_BASE_API = 'http://139.224.65.227:8091/prod-api'
 # VUE_APP_BASE_API_HOST = 'http://192.168.5.247:9801/'

+ 8 - 0
admin-ui/src/api/order/clothItem.js

@@ -92,6 +92,14 @@ export function listOrderClothItem(query) {
     })
 }
 
+// 查询洗衣订单衣服明细列表
+export function getOrderClothDetail(orderSn) {
+    return request({
+        url: '/mapi/order/cloth/detail/'+orderSn,
+        method: 'get'
+    })
+}
+
 // 查询洗衣订单衣服明细详细
 export function getClothItem(id) {
     return request({

+ 26 - 0
admin-ui/src/api/statistics/storeCard.js

@@ -0,0 +1,26 @@
+import request from '@/utils/request'
+
+/**
+ * 分页获取门店会员卡统计
+ * @param {Object} query 查询参数
+ */
+export function listStoreCardStatistics(query) {
+  return request({
+    url: '/mapi/recharge/card/total/list',
+    method: 'get',
+    params: query
+  })
+}
+
+/**
+ * 导出门店会员卡统计
+ * @param {Object} query 查询参数
+ */
+export function exportStoreCardStatistics(query) {
+  return request({
+    url: '/mapi/recharge/card/total/export',
+    method: 'get',
+    params: query,
+    responseType: 'blob'
+  })
+}

+ 22 - 14
admin-ui/src/views/order/cloth/orderList.vue

@@ -165,21 +165,29 @@
                             <template slot="label"> 支付方式 </template>
                             <span v-if="orderDetail.payTimeType === '1' && orderDetail.payStatus == 0">取衣付款</span>
                             <span v-else>
-                                <template v-if="orderDetail.payType == '0'">微信</template>
-                                <template v-if="orderDetail.payType == '1'">支付宝</template>
-                                <template v-if="orderDetail.payType == '2'">现金</template>
-                                <template v-if="orderDetail.payType == '3'">余额</template>
-                                <template v-if="orderDetail.payType == '8'">组合支付</template>
+                                <template v-if="orderDetail.payType == '0'">微信 ({{ orderDetail.payAmount }}元)</template>
+                                <template v-if="orderDetail.payType == '1'">支付宝({{ orderDetail.payAmount }}元)</template>
+                                <template v-if="orderDetail.payType == '2'">现金({{ orderDetail.payAmount }}元)</template>
+                                <template v-if="orderDetail.payType == '3'">余额({{ orderDetail.payAmount }}元)</template>
+                                <template v-if="orderDetail.payType == '8'">组合
+                                   (
+                                     <span v-if="orderDetail.memberPayAmount">会员:{{orderDetail.memberPayAmount}}</span>
+                                     <span v-if="orderDetail.balancePayAmount"> 余额:{{orderDetail.balancePayAmount}}</span>
+                                     <span v-if="orderDetail.wechatPayAmount"> 微信:{{orderDetail.wechatPayAmount}}</span>
+                                     <span v-if="orderDetail.alipayPayAmount"> 支付宝:{{orderDetail.alipayPayAmount}}</span>
+                                     <span v-if="orderDetail.cashPayAmount"> 现金:{{orderDetail.cashPayAmount}}</span>
+                                   )
+                                </template>
                             </span>
-                            ({{ orderDetail.payAmount }}元)
+
                         </el-descriptions-item>
                         <el-descriptions-item>
                             <template slot="label"> 姓名 </template>
-                            {{ orderDetail.appUserName }}
+                            {{ orderDetail.appUserInfoVO? orderDetail.appUserInfoVO.contactName : '' }}
                         </el-descriptions-item>
                         <el-descriptions-item>
                             <template slot="label"> 电话 </template>
-                            {{ orderDetail.appUserPhoneNumber }}
+                            {{ orderDetail.appUserInfoVO? orderDetail.appUserInfoVO.contactPhone : '' }}
                         </el-descriptions-item>
                         <el-descriptions-item>
                             <template slot="label"> 总金额(元) </template>
@@ -191,7 +199,7 @@
                         </el-descriptions-item>
                         <el-descriptions-item :span="2" v-if="userInfoVO.userType == '00'">
                             <template slot="label"> 门店名称 </template>
-                            {{ orderDetail.sysOrg ? orderDetail.sysOrg.name : '' }}
+                            {{ orderDetail.storeName }}
                         </el-descriptions-item>
                         <el-descriptions-item>
                             <template slot="label"> 订单备注 </template>
@@ -307,7 +315,7 @@
 
 <script>
 import { listOrderCloth, refundOrderCloth } from '../../../api/order/cloth'
-import { listOrderClothItem, printCloth } from '../../../api/order/clothItem'
+import { listOrderClothItem, printCloth, getOrderClothDetail } from '../../../api/order/clothItem'
 import { getLodop } from '@/utils/lodopUtils'
 import { allOrg } from '@/api/system/store'
 
@@ -453,12 +461,12 @@ export default {
         },
         /** 详情按钮 */
         handleDetail(row) {
-            console.log('handleDetail')
             this.reset()
             this.orderClothDetails = []
-            this.orderDetail = row
-            listOrderClothItem({ pageSize: 99999, pageNum: 1, orderNo: row.orderNo }).then((res) => {
-                this.orderClothDetails = res.rows
+
+            getOrderClothDetail(row.orderNo).then((res) => {
+                this.orderDetail = res.data
+                this.orderClothDetails = res.data.orderClothItemVOS
                 this.title = '订单详情'
                 this.open = true
             })

+ 221 - 0
admin-ui/src/views/order/statistics/bygoods.vue

@@ -0,0 +1,221 @@
+<template>
+  <div class="app-container">
+    <!-- 搜索表单 -->
+    <el-form :model="queryParams" ref="queryForm" @submit.native.prevent :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="日期范围" prop="dateRange">
+        <el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
+          value-format="yyyy-MM-dd" :picker-options="pickerOptions" @change="handleDateRangeChange">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="所属来源" prop="storeId">
+        <el-select v-model="queryParams.orgId" placeholder="请选择" clearable>
+          <el-option v-for="store in storeOptions" :key="store.id" :label="store.name" :value="store.id">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="商品类别" prop="goodsType">
+        <el-select v-model="queryParams.goodsType" placeholder="请选择商品类别" clearable>
+          <el-option v-for="dict in goodsTypeOptions" :key="dict.value" :label="dict.label" :value="dict.value">
+          </el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="商品名称" prop="goodsName">
+        <el-input v-model="queryParams.goodsName" placeholder="请输入商品名称" clearable size="small" @keyup.enter.native="handleQuery" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <!-- 操作按钮 -->
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <!-- 数据表格 -->
+    <el-table v-loading="loading" :data="statisticsList" border>
+      <el-table-column label="商品图片" align="center" width="100">
+        <template slot-scope="scope">
+          <el-image style="width: 50px; height: 50px" :src="scope.row.goodsImg" :preview-src-list="[scope.row.goodsImg]">
+          </el-image>
+        </template>
+      </el-table-column>
+      <el-table-column label="商品名称" align="center" prop="goodsName" />
+      <el-table-column label="实际销售数量" align="center" prop="actualSaleCount" />
+      <el-table-column label="实际销售金额" align="center" prop="actualSaleAmount">
+        <template slot-scope="scope">
+          {{ scope.row.actualSaleAmount ? scope.row.actualSaleAmount.toFixed(2) : 0 }}
+        </template>
+      </el-table-column>
+      <el-table-column label="销售数量" align="center" prop="saleCount" />
+      <el-table-column label="销售金额" align="center" prop="saleAmount">
+        <template slot-scope="scope">
+          {{ scope.row.saleAmount ? scope.row.saleAmount.toFixed(2) : 0 }}
+        </template>
+      </el-table-column>
+      <el-table-column label="退款数量" align="center" prop="refundCount" />
+      <el-table-column label="退款金额" align="center" prop="refundAmount">
+        <template slot-scope="scope">
+          {{ scope.row.refundAmount ? scope.row.refundAmount.toFixed(2) : 0 }}
+        </template>
+      </el-table-column>
+
+    </el-table>
+
+    <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
+  </div>
+</template>
+
+<script>
+import { listStatistics } from '@/api/order/goods'
+import { listStore } from "@/api/system/store"
+
+export default {
+  name: "GoodsStatistics",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 统计列表
+      statisticsList: [],
+      // 门店选项
+      storeOptions: [],
+      // 商品类别选项
+      goodsTypeOptions: [
+        { value: '1', label: '普通商品' },
+        { value: '2', label: '生活服务' },
+        { value: '3', label: '汽车美容' }
+      ],
+      // 日期范围
+      dateRange: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        startTime: null,
+        endTime: null,
+        orgId: null,
+        goodsType: null,
+        goodsName: null
+      },
+      // 日期选择器配置
+      pickerOptions: {
+        shortcuts: [{
+          text: '最近一周',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近半个月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 15)
+            picker.$emit('pick', [start, end])
+          }
+        }, {
+          text: '最近一个月',
+          onClick(picker) {
+            const end = new Date()
+            const start = new Date()
+            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
+            picker.$emit('pick', [start, end])
+          }
+        }]
+      }
+    }
+  },
+  created() {
+    // 设置默认日期范围为最近半个月
+    const end = new Date()
+    const start = new Date()
+    start.setTime(start.getTime() - 3600 * 1000 * 24 * 15)
+    this.dateRange = [this.formatDate(start), this.formatDate(end)]
+    this.queryParams.startTime = this.dateRange[0]
+    this.queryParams.endTime = this.dateRange[1]
+
+    this.getList()
+    this.getStoreOptions()
+  },
+  methods: {
+    /** 格式化日期为 yyyy-MM-dd */
+    formatDate(date) {
+      const year = date.getFullYear()
+      const month = String(date.getMonth() + 1).padStart(2, '0')
+      const day = String(date.getDate()).padStart(2, '0')
+      return `${year}-${month}-${day}`
+    },
+    /** 日期范围变化处理 */
+    handleDateRangeChange(val) {
+      if (val) {
+        this.queryParams.startTime = val[0]
+        this.queryParams.endTime = val[1]
+      } else {
+        this.queryParams.startTime = null
+        this.queryParams.endTime = null
+      }
+    },
+    /** 查询统计列表 */
+    getList() {
+      this.loading = true
+      listStatistics(this.queryParams).then(response => {
+        this.statisticsList = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+    /** 获取门店选项 */
+    getStoreOptions() {
+      listStore().then(response => {
+        this.storeOptions = response.rows
+      })
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm")
+      // 重置日期范围为最近半个月
+      const end = new Date()
+      const start = new Date()
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 15)
+      this.dateRange = [this.formatDate(start), this.formatDate(end)]
+      this.queryParams.startTime = this.dateRange[0]
+      this.queryParams.endTime = this.dateRange[1]
+      this.handleQuery()
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.$confirm('是否确认导出所有商品销售统计数据项?', "警告", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(() => {
+        this.download('/mapi/order/goods/statistics/export', {
+          ...this.queryParams
+        }, `商品销售统计_${new Date().getTime()}.xlsx`)
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.mb8 {
+  margin-bottom: 8px;
+}
+</style>

+ 201 - 0
admin-ui/src/views/order/statistics/chargeTotal.vue

@@ -0,0 +1,201 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="80px">
+      <el-form-item label="门店">
+        <el-select v-model="queryParams.storeId" placeholder="请选择门店" clearable filterable>
+          <el-option v-for="item in storeList" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="开卡时间">
+        <el-date-picker
+          v-model="dateRange"
+          type="daterange"
+          range-separator="至"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          value-format="yyyy-MM-dd"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
+        <el-button type="success" icon="el-icon-download" @click="handleExport">导出</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table :data="rawList" border style="width: 100%">
+      <el-table-column label="门店" prop="storeName" fixed="left" />
+      <!-- 累计数据 -->
+      <el-table-column label="累计数据" align="center">
+        <el-table-column label="卡张数" prop="totalCardCount" />
+        <el-table-column label="充值现金" prop="totalRechargeAmount" />
+        <el-table-column label="赠送" prop="totalGiveAmount" />
+        <el-table-column label="福利" prop="totalWelfareAmount" />
+        <el-table-column label="现金消耗" prop="totalConsumeRechargeAmount" />
+        <el-table-column label="赠送消耗" prop="totalConsumeGiveAmount" />
+        <el-table-column label="福利消耗" prop="totalConsumeWelfareAmount" />
+      </el-table-column>
+      <!-- 使用中数据 -->
+      <el-table-column label="使用中数据" align="center">
+        <el-table-column label="有效卡张数" prop="validCardCount" />
+        <el-table-column label="剩余现金" prop="validRechargeBalance" />
+        <el-table-column label="剩余赠送" prop="validGiveBalance" />
+        <el-table-column label="剩余福利" prop="validWelfareBalance" />
+        <el-table-column label="过期赠送余额" prop="expiredGiveBalance" />
+        <el-table-column label="已消耗现金" prop="usedConsumeRechargeAmount" />
+        <el-table-column label="已消耗赠送" prop="usedConsumeGiveAmount" />
+        <el-table-column label="已消耗福利" prop="usedConsumeWelfareAmount" />
+      </el-table-column>
+      <!-- 已退款数据 -->
+      <el-table-column label="已退款数据" align="center">
+        <el-table-column label="退款卡张数" prop="refundCardCount" />
+        <el-table-column label="退款现金" prop="refundRechargeBalance" />
+        <el-table-column label="退款赠送" prop="refundGiveBalance" />
+        <el-table-column label="退款福利" prop="refundWelfareBalance" />
+      </el-table-column>
+      <!-- 未激活数据 -->
+      <el-table-column label="未激活数据" align="center">
+        <el-table-column label="卡片数量" prop="inactiveCardCount" />
+        <el-table-column label="总现金" prop="inactiveRechargeAmount" />
+        <el-table-column label="总赠送" prop="inactiveGiveAmount" />
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { listStoreCardStatistics, exportStoreCardStatistics } from '@/api/statistics/storeCard'
+import { allOrg } from '@/api/system/store'
+
+export default {
+  name: 'StoreCardTotal',
+  data() {
+    return {
+      queryParams: {
+        storeId: undefined,
+        pageNum: 1,
+        pageSize: 10,
+        beginTime: undefined,
+        endTime: undefined
+      },
+      dateRange: [],
+      storeList: [],
+      total: 0,
+      rawList: [],
+      groups: []
+    }
+  },
+  created() {
+    this.getStoreList()
+    this.getList()
+  },
+  methods: {
+    getStoreList() {
+      allOrg({ sourceType: '02' }).then(res => {
+        this.storeList = res.data
+      })
+    },
+    getList() {
+      if (this.dateRange && this.dateRange.length === 2) {
+        this.queryParams.beginTime = this.dateRange[0]
+        this.queryParams.endTime = this.dateRange[1]
+      } else {
+        this.queryParams.beginTime = undefined
+        this.queryParams.endTime = undefined
+      }
+      listStoreCardStatistics(this.queryParams).then(res => {
+        this.rawList = res.rows
+        this.total = res.total
+        this.buildGroups()
+      })
+    },
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    resetQuery() {
+      this.queryParams = { pageNum: 1, pageSize: 10 }
+      this.dateRange = []
+      this.getList()
+    },
+    handleExport() {
+      exportStoreCardStatistics(this.queryParams).then(res => {
+        const blob = new Blob([res], { type: 'application/vnd.ms-excel' })
+        const link = document.createElement('a')
+        link.href = window.URL.createObjectURL(blob)
+        link.download = '门店会员卡统计.xlsx'
+        link.click()
+      })
+    },
+    buildGroups() {
+      // 分组数据
+      this.groups = [
+        {
+          key: 'total',
+          label: '累计',
+          columns: [
+            { label: '累计卡张数', prop: 'totalCardCount' },
+            { label: '累计充值现金', prop: 'totalRechargeAmount' },
+            { label: '累计赠送', prop: 'totalGiveAmount' },
+            { label: '累计福利', prop: 'totalWelfareAmount' },
+            { label: '累计消耗现金', prop: 'totalConsumeRechargeAmount' },
+            { label: '累计消耗赠送', prop: 'totalConsumeGiveAmount' },
+            { label: '累计消耗福利', prop: 'totalConsumeWelfareAmount' }
+          ],
+          data: this.rawList
+        },
+        {
+          key: 'valid',
+          label: '使用中',
+          columns: [
+            { label: '有效卡张数', prop: 'validCardCount' },
+            { label: '有效剩余现金', prop: 'validRechargeBalance' },
+            { label: '有效剩余赠送', prop: 'validGiveBalance' },
+            { label: '有效剩余福利', prop: 'validWelfareBalance' },
+            { label: '已过期赠送余额', prop: 'expiredGiveBalance' },
+            { label: '已消耗现金', prop: 'usedConsumeRechargeAmount' },
+            { label: '已消耗赠送', prop: 'usedConsumeGiveAmount' },
+            { label: '已消耗福利', prop: 'usedConsumeWelfareAmount' }
+          ],
+          data: this.rawList
+        },
+        {
+          key: 'refund',
+          label: '已退款',
+          columns: [
+            { label: '退款卡张数', prop: 'refundCardCount' },
+            { label: '退款现金', prop: 'refundRechargeBalance' },
+            { label: '退款赠送', prop: 'refundGiveBalance' },
+            { label: '退款福利', prop: 'refundWelfareBalance' }
+          ],
+          data: this.rawList
+        },
+        {
+          key: 'inactive',
+          label: '未激活',
+          columns: [
+            { label: '未激活卡片数量', prop: 'inactiveCardCount' },
+            { label: '未激活总现金', prop: 'inactiveRechargeAmount' },
+            { label: '未激活总赠送', prop: 'inactiveGiveAmount' }
+          ],
+          data: this.rawList
+        }
+      ]
+    }
+  }
+}
+</script>
+
+<style scoped>
+.mb8 {
+  margin-bottom: 8px;
+}
+</style>

+ 1 - 0
admin-ui/src/views/recharge/batchRecord/index.vue

@@ -62,6 +62,7 @@
                 <el-table-column label="批次号" align="center" prop="batchNo" min-width="160" :show-overflow-tooltip="true" />
                 <el-table-column label="批次名称" align="center" prop="batchName" min-width="160" :show-overflow-tooltip="true" />
                 <el-table-column label="所属企业" align="center" prop="companyName" min-width="130" :show-overflow-tooltip="true" />
+                <el-table-column label="单卡实收金额" align="center" prop="actualAmount" min-width="130" :show-overflow-tooltip="true" />
                 <el-table-column label="备注" align="center" prop="remark" min-width="200" :show-overflow-tooltip="true" />
                 <el-table-column label="激活过期时间" align="center" prop="lastExpireTime" width="160">
                     <template slot-scope="scope">

+ 1 - 1
admin-ui/src/views/recharge/cardVersion/index.vue

@@ -233,7 +233,7 @@
                         </el-form-item>
                       </el-col>
                       <el-col :span="12">
-                        <el-form-item label="实收金额" prop="actualAmount" required>
+                        <el-form-item label="单卡实收金额" prop="actualAmount" required>
                           <el-input-number v-model="multiInsertForm.actualAmount" placeholder="请输入实收金额" />
                         </el-form-item>
                       </el-col>

+ 31 - 0
yiqi-admin/src/main/java/com/yiqi/admin/controller/order/OrderClothController.java

@@ -758,6 +758,37 @@ public class OrderClothController extends BaseController {
         return success(orderClothService.selectOrderClothById(id));
     }
 
+    /**
+     * 获取洗衣订单详细信息
+     */
+    @GetMapping(value = "/detail/{orderSn}")
+    @ApiOperation(value = "获取洗衣订单详细信息")
+    public R<OrderClothPrintVO> getDetailInfo(@PathVariable("orderSn") String orderSn) {
+        OrderClothPrintVO orderClothPrintVO = new OrderClothPrintVO();
+        OrderCloth orderCloth = orderClothService.getOrderClothByOrderNo(orderSn);
+        com.yiqi.common.utils.bean.BeanUtils.copyProperties(orderCloth, orderClothPrintVO);
+        AppUserInfoVO userInfo = appUserService.getAppUserInfoById(orderClothPrintVO.getAppUserId());
+        OrderClothAddress orderClothAddress = orderClothAddressService.getByorderSn(orderClothPrintVO.getOrderNo());
+        if (orderClothAddress != null) {
+            userInfo.setAddress(orderClothAddress.getAddress());
+            userInfo.setAddressDetail(orderClothAddress.getAddressDetail());
+            userInfo.setProvince(orderClothAddress.getProvince());
+            userInfo.setCity(orderClothAddress.getCity());
+            userInfo.setArea(orderClothAddress.getArea());
+        }
+        userInfo.setContactName(orderClothPrintVO.getContactName());
+        userInfo.setContactPhone(orderClothPrintVO.getContactPhone());
+        orderClothPrintVO.setAppUserInfoVO(userInfo);
+        //获取衣服明细
+        List<OrderClothItemVO> orderClothItemList = orderClothItemService.queryClothItemByOrderId(orderClothPrintVO.getOrderNo());
+        if (CollUtil.isEmpty(orderClothItemList)) {
+            throw new ServiceException("未找到衣服明细");
+        }
+        orderClothPrintVO.setOrderClothItemVOS(orderClothItemList);
+        orderClothPrintVO.setStoreName(sysStoreService.getStoreNameById(orderClothPrintVO.getOrgId()));
+        return R.ok(orderClothPrintVO);
+    }
+
     /**
      * 获取零售商品订单详细信息
      */

+ 32 - 0
yiqi-admin/src/main/java/com/yiqi/admin/controller/recharge/RechargePasswordCardController.java

@@ -20,6 +20,7 @@ import com.yiqi.recharge.domain.dto.*;
 import com.yiqi.recharge.domain.vo.RechargeBalanceCountVO;
 import com.yiqi.recharge.domain.vo.RechargeCardBillMstrQueryVO;
 import com.yiqi.recharge.domain.vo.RechargePasswordCardQueryVO;
+import com.yiqi.recharge.domain.vo.StoreCardStatisticsVO;
 import com.yiqi.recharge.service.IRechargeCardBatchRecordService;
 import com.yiqi.recharge.service.IRechargeCardVersionService;
 import io.swagger.annotations.Api;
@@ -346,4 +347,35 @@ public class RechargePasswordCardController extends BaseController {
         List<RechargeCardBillMstrQueryVO> billMstrInfoList = rechargePasswordCardService.getBillMstrInfoList(billMstrQueryDTO);
         return getDataTable(billMstrInfoList);
     }
+
+    /**
+     * 分页查询门店会员卡统计
+     */
+    @GetMapping("/total/list")
+    @ApiOperation("分页查询门店会员卡统计")
+    public TableDataInfo<StoreCardStatisticsVO> totalList(
+            @RequestParam(required = false) Long storeId,
+            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date beginTime,
+            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endTime,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "10") int pageSize
+    ) {
+        return rechargePasswordCardService.getStoreCardStatisticsPage(storeId, beginTime, endTime, pageNum, pageSize);
+    }
+
+    /**
+     * 导出门店会员卡统计
+     */
+    @GetMapping("/total/export")
+    @ApiOperation("导出门店会员卡统计")
+    public void totalExport(
+            HttpServletResponse response,
+            @RequestParam(required = false) Long storeId,
+            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date beginTime,
+            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endTime
+    ) {
+        List<StoreCardStatisticsVO> list = rechargePasswordCardService.getStoreCardStatisticsExport(storeId, beginTime, endTime);
+        ExcelUtil<StoreCardStatisticsVO> util = new ExcelUtil<>(StoreCardStatisticsVO.class);
+        util.exportExcel(response, list, "门店会员卡统计");
+    }
 }

+ 3 - 3
yiqi-common/src/main/java/com/yiqi/core/domain/dto/GoodsSkuStockRecordDTO.java

@@ -224,12 +224,12 @@ public class GoodsSkuStockRecordDTO extends BaseEntity {
 
             // 客户退货 = 加货 只有总部会退货 所以都是总部
             if (isAdd) {
-                if (SourceType.STORE.getCode().equals(SecurityUtils.getLoginUser().getSourceType())) {
+                if (SecurityUtils.getLoginUser() != null && SourceType.STORE.getCode().equals(SecurityUtils.getLoginUser().getSourceType())) {
                     //门店退货
                     goodsSkuStockRecord.setSourceType(SecurityUtils.getLoginUser().getSourceType());
                     goodsSkuStockRecord.setOrgId(SecurityUtils.getLoginUser().getOrgId());
                     goodsSkuStockRecord.setRemark("线下门店退货");
-                }else{
+                } else {
                     goodsSkuStockRecord.setSourceType(SourceType.MANAGER.getCode());
                     goodsSkuStockRecord.setRemark("线上零售退货");
                 }
@@ -240,7 +240,7 @@ public class GoodsSkuStockRecordDTO extends BaseEntity {
                     goodsSkuStockRecord.setRemark("线上零售出货");
                 } else {
                     // 总部出货
-                    if (SourceType.MANAGER.getCode().equals(SecurityUtils.getLoginUser().getSourceType())) {
+                    if (SecurityUtils.getLoginUser() != null && SourceType.MANAGER.getCode().equals(SecurityUtils.getLoginUser().getSourceType())) {
 
                     } else {
                         // 门店零售出货

+ 28 - 0
yiqi-common/src/main/java/com/yiqi/order/domain/dto/GoodsStatisticsQueryDTO.java

@@ -0,0 +1,28 @@
+package com.yiqi.order.domain.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 商品销售统计查询DTO
+ */
+@Data
+@ApiModel("商品销售统计查询")
+public class GoodsStatisticsQueryDTO {
+
+    @ApiModelProperty("开始时间")
+    private String startTime;
+
+    @ApiModelProperty("结束时间")
+    private String endTime;
+
+    @ApiModelProperty("商品类别")
+    private String goodsType;
+
+    @ApiModelProperty("门店ID")
+    private Long orgId;
+
+    @ApiModelProperty("商品名称")
+    private String goodsName;
+} 

+ 0 - 3
yiqi-common/src/main/java/com/yiqi/order/domain/dto/RechargeCardPayDTO.java

@@ -59,8 +59,5 @@ public class RechargeCardPayDTO {
         this.orderNo = orderNo;
         this.payAmount = payAmount;
         this.buyGoodsType = buyGoodsType;
-        if (buyGoodsType.equals(GoodsType.NORMAL.getCode())) {
-            this.buyGoodsType = BuyGoodsType.COMMON_GOODS.getCode();
-        }
     }
 }

+ 42 - 0
yiqi-common/src/main/java/com/yiqi/order/domain/vo/GoodsStatisticsVO.java

@@ -0,0 +1,42 @@
+package com.yiqi.order.domain.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 商品销售统计VO
+ */
+@Data
+@ApiModel("商品销售统计")
+public class GoodsStatisticsVO {
+
+    @ApiModelProperty("商品ID")
+    private Long goodsId;
+
+    @ApiModelProperty("商品名称")
+    private String goodsName;
+
+    @ApiModelProperty("商品图片")
+    private String goodsImg;
+
+    @ApiModelProperty("销售数量")
+    private Integer saleCount;
+
+    @ApiModelProperty("销售金额")
+    private BigDecimal saleAmount;
+
+    @ApiModelProperty("退款数量")
+    private Integer refundCount;
+
+    @ApiModelProperty("退款金额")
+    private BigDecimal refundAmount;
+
+    @ApiModelProperty("实际销售数量")
+    private Integer actualSaleCount;
+
+    @ApiModelProperty("实际销售金额")
+    private BigDecimal actualSaleAmount;
+} 

+ 3 - 0
yiqi-common/src/main/java/com/yiqi/order/domain/vo/OrderClothPrintVO.java

@@ -22,6 +22,9 @@ import java.util.List;
 @Data
 public class OrderClothPrintVO extends OrderCloth {
 
+    @ApiModelProperty("门店名称")
+    private String storeName;
+
     @ApiModelProperty("客户信息")
     private AppUserInfoVO appUserInfoVO;
 

+ 147 - 0
yiqi-common/src/main/java/com/yiqi/recharge/domain/vo/StoreCardStatisticsVO.java

@@ -0,0 +1,147 @@
+package com.yiqi.recharge.domain.vo;
+
+import com.yiqi.common.annotation.Excel;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 门店会员卡统计VO
+ *
+ * @author xxx
+ * @date 2024-xx-xx
+ */
+@Data
+public class StoreCardStatisticsVO implements Serializable {
+    /**
+     * 门店ID
+     */
+    private Long storeId;
+    /**
+     * 门店名称
+     */
+    @Excel(name = "门店名称")
+    private String storeName;
+
+    // 累计
+    /**
+     * 累计卡张数
+     */
+    @Excel(name = "累计卡张数")
+    private Integer totalCardCount;
+    /**
+     * 累计充值现金
+     */
+    @Excel(name = "累计充值现金")
+    private BigDecimal totalRechargeAmount;
+    /**
+     * 累计赠送
+     */
+    @Excel(name = "累计赠送")
+    private BigDecimal totalGiveAmount;
+    /**
+     * 累计福利
+     */
+    @Excel(name = "累计福利")
+    private BigDecimal totalWelfareAmount;
+    /**
+     * 累计消耗现金
+     */
+    @Excel(name = "累计消耗现金")
+    private BigDecimal totalConsumeRechargeAmount;
+    /**
+     * 累计消耗赠送
+     */
+    @Excel(name = "累计消耗赠送")
+    private BigDecimal totalConsumeGiveAmount;
+    /**
+     * 累计消耗福利
+     */
+    @Excel(name = "累计消耗福利")
+    private BigDecimal totalConsumeWelfareAmount;
+
+    // 使用中
+    /**
+     * 有效卡张数
+     */
+    @Excel(name = "有效卡张数")
+    private Integer validCardCount;
+    /**
+     * 有效剩余现金
+     */
+    @Excel(name = "使用中剩余现金")
+    private BigDecimal validRechargeBalance;
+    /**
+     * 有效剩余赠送
+     */
+    @Excel(name = "使用中剩余赠送")
+    private BigDecimal validGiveBalance;
+    /**
+     * 有效剩余福利
+     */
+    @Excel(name = "使用中剩余福利")
+    private BigDecimal validWelfareBalance;
+
+    /**
+     * 已消耗现金
+     */
+    @Excel(name = "使用中已消耗现金")
+    private BigDecimal usedConsumeRechargeAmount;
+    /**
+     * 已消耗赠送
+     */
+    @Excel(name = "使用中已消耗赠送")
+    private BigDecimal usedConsumeGiveAmount;
+    /**
+     * 已消耗福利
+     */
+    @Excel(name = "使用中已消耗福利")
+    private BigDecimal usedConsumeWelfareAmount;
+
+    /**
+     * 已过期赠送余额
+     */
+    @Excel(name = "已过期赠送余额")
+    private BigDecimal expiredGiveBalance;
+
+    // 已退款
+    /**
+     * 退款卡张数
+     */
+    @Excel(name = "已退款卡张数")
+    private Integer refundCardCount;
+    /**
+     * 退款现金
+     */
+    @Excel(name = "已退款现金")
+    private BigDecimal refundRechargeBalance;
+    /**
+     * 退款赠送
+     */
+    @Excel(name = "已退款赠送")
+    private BigDecimal refundGiveBalance;
+    /**
+     * 退款福利
+     */
+    @Excel(name = "已退款福利")
+    private BigDecimal refundWelfareBalance;
+
+    // 未激活
+    /**
+     * 未激活卡片数量
+     */
+    @Excel(name = "未激活卡片数量")
+    private Integer inactiveCardCount;
+    /**
+     * 未激活总现金
+     */
+
+    @Excel(name = "未激活总现金")
+    private BigDecimal inactiveRechargeAmount;
+    /**
+     * 未激活总赠送
+     */
+    @Excel(name = "未激活总赠送")
+    private BigDecimal inactiveGiveAmount;
+}

+ 13 - 0
yiqi-common/src/main/java/com/yiqi/recharge/service/IRechargePasswordCardService.java

@@ -6,6 +6,7 @@ import java.util.List;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.yiqi.app.domain.AppUserBillMstr;
 import com.yiqi.common.core.domain.PageVO;
+import com.yiqi.common.core.page.TableDataInfo;
 import com.yiqi.common.exception.ServiceException;
 import com.yiqi.order.domain.dto.RechargeCardPayDTO;
 import com.yiqi.recharge.domain.RechargeCardBatchRecord;
@@ -16,6 +17,7 @@ import com.yiqi.recharge.domain.dto.weapp.WeAppCardRecordByUserDTO;
 import com.yiqi.recharge.domain.vo.RechargeBalanceCountVO;
 import com.yiqi.recharge.domain.vo.RechargeCardBillMstrQueryVO;
 import com.yiqi.recharge.domain.vo.RechargePasswordCardQueryVO;
+import com.yiqi.recharge.domain.vo.StoreCardStatisticsVO;
 import com.yiqi.recharge.domain.vo.weapp.WeAppCardsInfoVO;
 import com.yiqi.recharge.domain.vo.weapp.WeAppCardsUseRecordsVO;
 
@@ -149,4 +151,15 @@ public interface IRechargePasswordCardService extends IService<RechargePasswordC
      */
     public Boolean orderRefundByBalance(String orderSn, BigDecimal refundAmount);
 
+
+    /**
+     * 分页查询门店会员卡统计
+     */
+    TableDataInfo<StoreCardStatisticsVO> getStoreCardStatisticsPage(Long storeId, Date beginTime, Date endTime, int pageNum, int pageSize);
+
+    /**
+     * 导出门店会员卡统计
+     */
+    List<StoreCardStatisticsVO> getStoreCardStatisticsExport(Long storeId, Date beginTime, Date endTime);
+
 }

+ 7 - 0
yiqi-common/src/main/java/com/yiqi/system/service/ISysStoreService.java

@@ -22,6 +22,13 @@ public interface ISysStoreService extends IService<SysStore> {
      */
     public List<OrgVO> allOrg(String sourceType);
 
+    /**
+     * 根据门店id获取门店名称
+     * @param storeId
+     * @return
+     */
+    public String getStoreNameById(Long storeId);
+
     /**
      * 查询门店
      *

+ 3 - 3
yiqi-core/src/main/java/com/yiqi/order/service/impl/OrderGoodsServiceImpl.java

@@ -334,7 +334,7 @@ public class OrderGoodsServiceImpl extends ServiceImpl<OrderGoodsMapper, OrderGo
         }
         //会员余额支付
         if (orderGoods.getPayType().equals(PayType.BALANCE.getCode())) {
-            RechargeCardPayDTO rechargeCardPayDTO = new RechargeCardPayDTO(orderGoods.getAppUserId(), orderGoods.getId(), orderGoods.getSourceType(), orderGoods.getOrgId(), orderGoods.getOrderNo(), orderGoods.getPayAmount(), orderGoods.getGoodsType());
+            RechargeCardPayDTO rechargeCardPayDTO = new RechargeCardPayDTO(orderGoods.getAppUserId(), orderGoods.getId(), orderGoods.getSourceType(), orderGoods.getOrgId(), orderGoods.getOrderNo(), orderGoods.getPayAmount(), orderGoods.getGoodsType().equals(GoodsType.NORMAL.getCode()) ? BuyGoodsType.COMMON_GOODS.getCode() : orderGoods.getGoodsType());
             rechargePasswordCardService.orderPayByBalance(rechargeCardPayDTO);
             this.handlePaySuccessUpdateOrderStatus(orderGoods.getOrderNo(), null);
             orderPayResultVO = OrderPayResultVO.paySuccess(orderGoods.getOrderNo());
@@ -403,7 +403,7 @@ public class OrderGoodsServiceImpl extends ServiceImpl<OrderGoodsMapper, OrderGo
                  *     life("2", "生活服务"),
                  *     car("3", "汽车美容"),*
                  */
-                RechargeCardPayDTO rechargeCardPayDTO = new RechargeCardPayDTO(orderGoods.getAppUserId(), orderGoods.getId(), orderGoods.getSourceType(), orderGoods.getOrgId(), orderGoods.getOrderNo(), orderGoods.getMemberPayAmount(), orderGoods.getGoodsType());
+                RechargeCardPayDTO rechargeCardPayDTO = new RechargeCardPayDTO(orderGoods.getAppUserId(), orderGoods.getId(), orderGoods.getSourceType(), orderGoods.getOrgId(), orderGoods.getOrderNo(), orderGoods.getMemberPayAmount(), orderGoods.getGoodsType().equals(GoodsType.NORMAL.getCode()) ? BuyGoodsType.COMMON_GOODS.getCode() : orderGoods.getGoodsType());
                 rechargePasswordCardService.orderPayByBalance(rechargeCardPayDTO);
             }
         }
@@ -570,7 +570,7 @@ public class OrderGoodsServiceImpl extends ServiceImpl<OrderGoodsMapper, OrderGo
         if (orderGoods.getPayType().equals(PayType.BALANCE.getCode())) {
             orderGoods.setPayType(PayType.BALANCE.getCode());
             this.updateById(orderGoods);
-            RechargeCardPayDTO rechargeCardPayDTO = new RechargeCardPayDTO(orderGoods.getAppUserId(), orderGoods.getId(), orderGoods.getSourceType(), orderGoods.getOrgId(), orderGoods.getOrderNo(), orderGoods.getPayAmount(), orderGoods.getGoodsType());
+            RechargeCardPayDTO rechargeCardPayDTO = new RechargeCardPayDTO(orderGoods.getAppUserId(), orderGoods.getId(), orderGoods.getSourceType(), orderGoods.getOrgId(), orderGoods.getOrderNo(), orderGoods.getPayAmount(), orderGoods.getGoodsType().equals(GoodsType.NORMAL.getCode()) ? BuyGoodsType.COMMON_GOODS.getCode() : orderGoods.getGoodsType());
             rechargePasswordCardService.orderPayByBalance(rechargeCardPayDTO);
             this.handlePaySuccessUpdateOrderStatus(orderGoods.getOrderNo(), null);
             orderPayResultVO = OrderPayResultVO.paySuccess(orderGoods.getOrderNo());

+ 13 - 0
yiqi-core/src/main/java/com/yiqi/recharge/mapper/RechargePasswordCardMapper.java

@@ -14,6 +14,7 @@ import com.yiqi.recharge.domain.dto.weapp.WeAppCardRecordByUserDTO;
 import com.yiqi.recharge.domain.vo.RechargeBalanceCountVO;
 import com.yiqi.recharge.domain.vo.RechargeCardBillMstrQueryVO;
 import com.yiqi.recharge.domain.vo.RechargePasswordCardQueryVO;
+import com.yiqi.recharge.domain.vo.StoreCardStatisticsVO;
 import com.yiqi.recharge.domain.vo.weapp.WeAppCardsInfoVO;
 import com.yiqi.recharge.domain.vo.weapp.WeAppCardsUseRecordsVO;
 import org.apache.ibatis.annotations.Mapper;
@@ -119,4 +120,16 @@ public interface RechargePasswordCardMapper extends BaseMapper<RechargePasswordC
      * @return
      */
     RechargePasswordCard selectRechargePasswordCardBySn(String cardSn);
+
+    /**
+     * 分页查询门店会员卡统计
+     */
+    List<StoreCardStatisticsVO> selectStoreCardStatisticsPage(
+            @Param("storeId") Long storeId,
+            @Param("beginTime") Date beginTime,
+            @Param("endTime") Date endTime,
+            @Param("startRow") int startRow,
+            @Param("pageSize") int pageSize
+    );
+
 }

+ 22 - 2
yiqi-core/src/main/java/com/yiqi/recharge/service/impl/RechargePasswordCardServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.yiqi.common.core.page.TableDataInfo;
 import com.yiqi.common.exception.ServiceException;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.yiqi.app.domain.AppUser;
@@ -28,6 +29,7 @@ import com.yiqi.recharge.domain.dto.weapp.WeAppCardRecordByUserDTO;
 import com.yiqi.recharge.domain.vo.RechargeBalanceCountVO;
 import com.yiqi.recharge.domain.vo.RechargeCardBillMstrQueryVO;
 import com.yiqi.recharge.domain.vo.RechargePasswordCardQueryVO;
+import com.yiqi.recharge.domain.vo.StoreCardStatisticsVO;
 import com.yiqi.recharge.domain.vo.weapp.WeAppCardsInfoVO;
 import com.yiqi.recharge.domain.vo.weapp.WeAppCardsUseRecordsVO;
 import com.yiqi.recharge.mapper.RechargePasswordCardMapper;
@@ -74,8 +76,6 @@ public class RechargePasswordCardServiceImpl extends ServiceImpl<RechargePasswor
     @Autowired
     private IOrderRechargeService orderRechargeService;
     @Autowired
-    private ISysSettlementRateService settlementRateService;
-    @Autowired
     private IAppUserBillMstrService billMstrOrderService;
 
     @Override
@@ -729,4 +729,24 @@ public class RechargePasswordCardServiceImpl extends ServiceImpl<RechargePasswor
         }
         return true;
     }
+
+    @Override
+    public TableDataInfo<StoreCardStatisticsVO> getStoreCardStatisticsPage(Long storeId, Date beginTime, Date endTime, int pageNum, int pageSize) {
+        int startRow = (pageNum - 1) * pageSize;
+        // 获取分页数据
+        List<StoreCardStatisticsVO> list = baseMapper.selectStoreCardStatisticsPage(storeId, beginTime, endTime, startRow, pageSize);
+
+        // 获取总门店数
+        Long total = sysStoreService.count(new QueryWrapper<SysStore>().lambda()
+                .gt(SysStore::getId, 0)
+                .eq(SysStore::getDelFlag, DeleteStatus.OK.getCode()));
+
+        return new TableDataInfo<>(list, total.intValue());
+    }
+
+    @Override
+    public List<StoreCardStatisticsVO> getStoreCardStatisticsExport(Long storeId, Date beginTime, Date endTime) {
+        // 不分页,导出全部
+        return baseMapper.selectStoreCardStatisticsPage(storeId, beginTime, endTime, 0, Integer.MAX_VALUE);
+    }
 }

+ 77 - 1
yiqi-core/src/main/resources/mapper/recharge/RechargePasswordCardMapper.xml

@@ -309,6 +309,82 @@
         </foreach>
     </delete>
 
-
+    <!-- 分页查询门店会员卡统计 -->
+    <select id="selectStoreCardStatisticsPage" resultType="com.yiqi.recharge.domain.vo.StoreCardStatisticsVO">
+        SELECT 
+            s.id AS storeId,
+            s.name AS storeName,
+            COALESCE(stats.totalCardCount, 0) AS totalCardCount,
+            COALESCE(stats.totalRechargeAmount, 0) AS totalRechargeAmount,
+            COALESCE(stats.totalGiveAmount, 0) AS totalGiveAmount,
+            COALESCE(stats.totalWelfareAmount, 0) AS totalWelfareAmount,
+            COALESCE(stats.totalConsumeRechargeAmount, 0) AS totalConsumeRechargeAmount,
+            COALESCE(stats.totalConsumeGiveAmount, 0) AS totalConsumeGiveAmount,
+            COALESCE(stats.totalConsumeWelfareAmount, 0) AS totalConsumeWelfareAmount,
+            COALESCE(stats.validCardCount, 0) AS validCardCount,
+            COALESCE(stats.validRechargeBalance, 0) AS validRechargeBalance,
+            COALESCE(stats.validGiveBalance, 0) AS validGiveBalance,
+            COALESCE(stats.validWelfareBalance, 0) AS validWelfareBalance,
+            COALESCE(stats.expiredGiveBalance, 0) AS expiredGiveBalance,
+            COALESCE(stats.usedConsumeRechargeAmount, 0) AS usedConsumeRechargeAmount,
+            COALESCE(stats.usedConsumeGiveAmount, 0) AS usedConsumeGiveAmount,
+            COALESCE(stats.usedConsumeWelfareAmount, 0) AS usedConsumeWelfareAmount,
+            COALESCE(stats.refundCardCount, 0) AS refundCardCount,
+            COALESCE(stats.refundRechargeBalance, 0) AS refundRechargeBalance,
+            COALESCE(stats.refundGiveBalance, 0) AS refundGiveBalance,
+            COALESCE(stats.refundWelfareBalance, 0) AS refundWelfareBalance,
+            COALESCE(stats.inactiveCardCount, 0) AS inactiveCardCount,
+            COALESCE(stats.inactiveRechargeAmount, 0) AS inactiveRechargeAmount,
+            COALESCE(stats.inactiveGiveAmount, 0) AS inactiveGiveAmount
+        FROM 
+            sys_store s
+        LEFT JOIN (
+            SELECT 
+                c.recharge_store_id,
+                COUNT(*) AS totalCardCount,
+                SUM(c.recharge_amount) AS totalRechargeAmount,
+                SUM(c.give_amount) AS totalGiveAmount,
+                SUM(c.welfare_amount) AS totalWelfareAmount,
+                SUM(c.recharge_amount - c.recharge_balance) AS totalConsumeRechargeAmount,
+                SUM(c.give_amount - c.give_balance) AS totalConsumeGiveAmount,
+                SUM(c.welfare_amount - c.welfare_balance) AS totalConsumeWelfareAmount,
+                SUM(CASE WHEN c.recharge_status = '1' AND (c.expire_time IS NULL OR c.expire_time > NOW()) THEN 1 ELSE 0 END) AS validCardCount,
+                SUM(CASE WHEN c.recharge_status = '1' AND (c.expire_time IS NULL OR c.expire_time > NOW()) THEN c.recharge_balance ELSE 0 END) AS validRechargeBalance,
+                SUM(CASE WHEN c.recharge_status = '1' AND (c.expire_time IS NULL OR c.expire_time > NOW()) THEN c.give_balance ELSE 0 END) AS validGiveBalance,
+                SUM(CASE WHEN c.recharge_status = '1' AND (c.expire_time IS NULL OR c.expire_time > NOW()) THEN c.welfare_balance ELSE 0 END) AS validWelfareBalance,
+                SUM(CASE WHEN c.expire_time IS NOT NULL AND c.expire_time &lt; NOW() THEN c.give_balance ELSE 0 END) AS expiredGiveBalance,
+                SUM(CASE WHEN c.recharge_status = '1' AND (c.expire_time IS NULL OR c.expire_time > NOW()) THEN c.recharge_amount - c.recharge_balance ELSE 0 END) AS usedConsumeRechargeAmount,
+                SUM(CASE WHEN c.recharge_status = '1' AND (c.expire_time IS NULL OR c.expire_time > NOW()) THEN c.give_amount - c.give_balance ELSE 0 END) AS usedConsumeGiveAmount,
+                SUM(CASE WHEN c.recharge_status = '1' AND (c.expire_time IS NULL OR c.expire_time > NOW()) THEN c.welfare_amount - c.welfare_balance ELSE 0 END) AS usedConsumeWelfareAmount,
+                SUM(CASE WHEN c.recharge_status = '-2' THEN 1 ELSE 0 END) AS refundCardCount,
+                SUM(CASE WHEN c.recharge_status = '-2' THEN c.recharge_balance ELSE 0 END) AS refundRechargeBalance,
+                SUM(CASE WHEN c.recharge_status = '-2' THEN c.give_balance ELSE 0 END) AS refundGiveBalance,
+                SUM(CASE WHEN c.recharge_status = '-2' THEN c.welfare_balance ELSE 0 END) AS refundWelfareBalance,
+                SUM(CASE WHEN c.recharge_status = '0' THEN 1 ELSE 0 END) AS inactiveCardCount,
+                SUM(CASE WHEN c.recharge_status = '0' THEN c.recharge_amount ELSE 0 END) AS inactiveRechargeAmount,
+                SUM(CASE WHEN c.recharge_status = '0' THEN c.give_amount ELSE 0 END) AS inactiveGiveAmount
+            FROM 
+                recharge_password_card c
+            WHERE 
+                c.del_flag = '0'
+                <if test="beginTime != null">
+                    AND c.create_time &gt;= #{beginTime}
+                </if>
+                <if test="endTime != null">
+                    AND c.create_time &lt;= #{endTime}
+                </if>
+            GROUP BY 
+                c.recharge_store_id
+        ) stats ON s.id = stats.recharge_store_id
+        WHERE 
+            s.del_flag = '0'
+            AND s.id > 0
+            <if test="storeId != null">
+                AND s.id = #{storeId}
+            </if>
+        ORDER BY
+        totalRechargeAmount DESC
+        LIMIT #{startRow}, #{pageSize}
+    </select>
 
 </mapper>

+ 18 - 10
yiqi-system/src/main/java/com/yiqi/system/service/impl/SysStoreServiceImpl.java

@@ -48,9 +48,16 @@ public class SysStoreServiceImpl extends ServiceImpl<SysStoreMapper, SysStore> i
     private IManageFactoryService manageFactoryService;
 
 
-    public List<OrgVO> allOrg(String sourceType){
+    public List<OrgVO> allOrg(String sourceType) {
         return baseMapper.allOrg(sourceType);
     }
+
+    @Override
+    public String getStoreNameById(Long storeId) {
+        SysStore sysStore = baseMapper.selectById(storeId);
+        return sysStore != null ? sysStore.getName() : "";
+    }
+
     /**
      * 查询门店
      *
@@ -64,6 +71,7 @@ public class SysStoreServiceImpl extends ServiceImpl<SysStoreMapper, SysStore> i
 
     /**
      * 查询门店
+     *
      * @return 门店
      */
     @Override
@@ -97,14 +105,14 @@ public class SysStoreServiceImpl extends ServiceImpl<SysStoreMapper, SysStore> i
     @Override
     public int insertSysStore(SysStore sysStore) {
         //校验id是否存在
-        Map<String,Object> map = new HashMap<>();
-        map.put("code",sysStore.getCode());
-        map.put("del_flag",UserStatus.OK.getCode());
-        if(!CollectionUtils.isEmpty(baseMapper.selectByMap(map))){
+        Map<String, Object> map = new HashMap<>();
+        map.put("code", sysStore.getCode());
+        map.put("del_flag", UserStatus.OK.getCode());
+        if (!CollectionUtils.isEmpty(baseMapper.selectByMap(map))) {
             throw new ServiceException("已存在该门店编号");
         }
         ManageFactory manageFactory = manageFactoryService.getById(sysStore.getFactoryId());
-        if(manageFactory == null){
+        if (manageFactory == null) {
             throw new GlobalException("不存在该工厂");
         }
         sysStore.setBindAreaId(manageFactory.getBindAreaId());
@@ -130,10 +138,10 @@ public class SysStoreServiceImpl extends ServiceImpl<SysStoreMapper, SysStore> i
     @Override
     public int updateSysStore(SysStore sysStore) {
         QueryWrapper<SysStore> storeQueryWrapper = new QueryWrapper<SysStore>()
-            .eq("code",sysStore.getCode())
-            .eq("del_flag",UserStatus.OK.getCode())
-            .ne("id",sysStore.getId());
-        if(!CollectionUtils.isEmpty(baseMapper.selectList(storeQueryWrapper))){
+                .eq("code", sysStore.getCode())
+                .eq("del_flag", UserStatus.OK.getCode())
+                .ne("id", sysStore.getId());
+        if (!CollectionUtils.isEmpty(baseMapper.selectList(storeQueryWrapper))) {
             throw new ServiceException("已存在该门店编号");
         }
         sysStore.buildUpdateData();