Przeglądaj źródła

Merge remote-tracking branch 'origin/master'

xuchao 3 miesięcy temu
rodzic
commit
91a712695d
100 zmienionych plików z 5486 dodań i 144 usunięć
  1. 25 0
      snowy-admin-web/src/api/biz/bizAuthApi.js
  2. 28 0
      snowy-admin-web/src/api/biz/bizCouponRecordApi.js
  3. 28 0
      snowy-admin-web/src/api/biz/bizRebateRecordApi.js
  4. 28 0
      snowy-admin-web/src/api/biz/bizRechargeRecordApi.js
  5. 28 0
      snowy-admin-web/src/api/biz/bizRecommendRecordApi.js
  6. 117 13
      snowy-admin-web/src/views/biz/consumptionrecord/index.vue
  7. 100 0
      snowy-admin-web/src/views/biz/couponrecord/form.vue
  8. 198 0
      snowy-admin-web/src/views/biz/couponrecord/index.vue
  9. 73 20
      snowy-admin-web/src/views/biz/member/consumption.vue
  10. 131 0
      snowy-admin-web/src/views/biz/member/form.vue
  11. 24 9
      snowy-admin-web/src/views/biz/member/index.vue
  12. 82 0
      snowy-admin-web/src/views/biz/rebaterecord/form.vue
  13. 114 0
      snowy-admin-web/src/views/biz/rebaterecord/index.vue
  14. 1 1
      snowy-admin-web/src/views/biz/rechargeplanconfig/index.vue
  15. 82 0
      snowy-admin-web/src/views/biz/rechargerecord/form.vue
  16. 110 0
      snowy-admin-web/src/views/biz/rechargerecord/index.vue
  17. 76 0
      snowy-admin-web/src/views/biz/recommendrecord/form.vue
  18. 73 0
      snowy-admin-web/src/views/biz/recommendrecord/index.vue
  19. 40 0
      snowy-common/src/main/java/vip/xiaonuo/common/util/CommonCouponGeneratorUtil.java
  20. 4 0
      snowy-common/src/main/java/vip/xiaonuo/common/util/CommonCryptogramUtil.java
  21. 0 3
      snowy-common/src/main/java/vip/xiaonuo/common/util/CommonWxUtil.java
  22. 45 0
      snowy-common/src/main/java/vip/xiaonuo/common/wx/HttpServletUtils.java
  23. 9 0
      snowy-plugin-api/snowy-plugin-auth-api/src/main/java/vip/xiaonuo/auth/api/SaBaseLoginUserApi.java
  24. 13 1
      snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/controller/AuthClientController.java
  25. 30 0
      snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/result/WxAuthIUserInfo.java
  26. 0 22
      snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/result/WxAuthInfo.java
  27. 2 1
      snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/service/AuthService.java
  28. 25 1
      snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/service/impl/AuthServiceImpl.java
  29. 25 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/core/enums/FundChangeTypeEnum.java
  30. 10 4
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/controller/ConsumptionRecordController.java
  31. 33 30
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/entity/ConsumptionRecord.java
  32. 7 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/mapper/ConsumptionRecordMapper.java
  33. 34 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/mapper/mapping/ConsumptionRecordMapper.xml
  34. 8 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/param/ConsumptionRecordAddParam.java
  35. 13 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/param/ConsumptionRecordPageParam.java
  36. 14 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/param/ConsumptionResult.java
  37. 3 4
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/service/ConsumptionRecordService.java
  38. 142 20
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/service/impl/ConsumptionRecordServiceImpl.java
  39. 150 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/controller/BizCouponRecordController.java
  40. 96 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/entity/BizCouponRecord.java
  41. 34 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/enums/BizCouponRecordEnum.java
  42. 29 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/mapper/BizCouponRecordMapper.java
  43. 28 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/mapper/mapping/BizCouponRecordMapper.xml
  44. 74 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/param/BizCouponRecordAddParam.java
  45. 79 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/param/BizCouponRecordEditParam.java
  46. 35 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/param/BizCouponRecordIdParam.java
  47. 59 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/param/BizCouponRecordPageParam.java
  48. 90 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/service/BizCouponRecordService.java
  49. 144 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/service/impl/BizCouponRecordServiceImpl.java
  50. 89 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/controller/BizRebateRecordController.java
  51. 84 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/entity/BizRebateRecord.java
  52. 34 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/enums/BizRebateRecordEnum.java
  53. 30 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/mapper/BizRebateRecordMapper.java
  54. 26 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/mapper/mapping/BizRebateRecordMapper.xml
  55. 50 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/param/BizRebateRecordAddParam.java
  56. 55 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/param/BizRebateRecordEditParam.java
  57. 35 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/param/BizRebateRecordIdParam.java
  58. 61 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/param/BizRebateRecordPageParam.java
  59. 64 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/service/BizRebateRecordService.java
  60. 100 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/service/impl/BizRebateRecordServiceImpl.java
  61. 17 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargeplanconfig/controller/BizRechargePlanConfigController.java
  62. 136 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/controller/BizRechargeRecordController.java
  63. 126 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/entity/BizRechargeRecord.java
  64. 34 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/enums/BizRechargeRecordEnum.java
  65. 38 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/mapper/BizRechargeRecordMapper.java
  66. 30 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/mapper/mapping/BizRechargeRecordMapper.xml
  67. 47 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/param/BizRechargeRecordAddParam.java
  68. 103 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/param/BizRechargeRecordEditParam.java
  69. 35 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/param/BizRechargeRecordIdParam.java
  70. 63 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/param/BizRechargeRecordPageParam.java
  71. 89 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/service/BizRechargeRecordService.java
  72. 258 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/service/impl/BizRechargeRecordServiceImpl.java
  73. 91 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/controller/BizRecommendRecordController.java
  74. 58 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/entity/BizRecommendRecord.java
  75. 34 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/enums/BizRecommendRecordEnum.java
  76. 30 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/mapper/BizRecommendRecordMapper.java
  77. 19 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/mapper/mapping/BizRecommendRecordMapper.xml
  78. 42 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/param/BizRecommendRecordAddParam.java
  79. 47 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/param/BizRecommendRecordEditParam.java
  80. 35 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/param/BizRecommendRecordIdParam.java
  81. 51 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/param/BizRecommendRecordPageParam.java
  82. 64 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/service/BizRecommendRecordService.java
  83. 86 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/service/impl/BizRecommendRecordServiceImpl.java
  84. 96 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/task/rebateEffectTask.java
  85. 6 2
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/controller/BizUserController.java
  86. 4 2
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/mapper/mapping/BizUserMapper.xml
  87. 1 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/WxUserRegisterParam.java
  88. 4 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/result/BizMemberUserResult.java
  89. 36 11
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/impl/BizUserServiceImpl.java
  90. 75 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/controller/BizUserFundChangeRecordController.java
  91. 65 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/entity/BizUserFundChangeRecord.java
  92. 34 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/enums/BizUserFundChangeRecordEnum.java
  93. 25 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/mapper/BizUserFundChangeRecordMapper.java
  94. 5 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/mapper/mapping/BizUserFundChangeRecordMapper.xml
  95. 58 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/param/BizUserFundChangeRecordAddParam.java
  96. 63 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/param/BizUserFundChangeRecordEditParam.java
  97. 35 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/param/BizUserFundChangeRecordIdParam.java
  98. 51 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/param/BizUserFundChangeRecordPageParam.java
  99. 80 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/service/BizUserFundChangeRecordService.java
  100. 94 0
      snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/service/impl/BizUserFundChangeRecordServiceImpl.java

+ 25 - 0
snowy-admin-web/src/api/biz/bizAuthApi.js

@@ -0,0 +1,25 @@
+/**
+ *  Copyright [2022] [https://www.xiaonuo.vip]
+ *	Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *	1.请不要删除和修改根目录下的LICENSE文件。
+ *	2.请不要删除和修改Snowy源码头部的版权声明。
+ *	3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ *	4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ *	5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ *	6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+import { baseRequest } from '@/utils/request'
+
+const request = (url, ...arg) => baseRequest(`/auth/c/` + url, ...arg)
+/**
+ * 人员接口api
+ *
+ * @author yubaoshan
+ * @date 2022-09-22 22:33:20
+ */
+export default {
+	// 获取短信
+	sendMessage(data) {
+		return request('smsSend', data, 'get')
+	},
+}

+ 28 - 0
snowy-admin-web/src/api/biz/bizCouponRecordApi.js

@@ -0,0 +1,28 @@
+import { baseRequest } from '@/utils/request'
+
+const request = (url, ...arg) => baseRequest(`/biz/couponrecord/` + url, ...arg)
+
+/**
+ * 优惠券记录Api接口管理器
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+export default {
+	// 获取优惠券记录分页
+	bizCouponRecordPage(data) {
+		return request('page', data, 'get')
+	},
+	// 提交优惠券记录表单 edit为true时为编辑,默认为新增
+	bizCouponRecordSubmitForm(data, edit = false) {
+		return request(edit ? 'edit' : 'add', data)
+	},
+	// 删除优惠券记录
+	bizCouponRecordDelete(data) {
+		return request('delete', data)
+	},
+	// 获取优惠券记录详情
+	bizCouponRecordDetail(data) {
+		return request('detail', data, 'get')
+	}
+}

+ 28 - 0
snowy-admin-web/src/api/biz/bizRebateRecordApi.js

@@ -0,0 +1,28 @@
+import { baseRequest } from '@/utils/request'
+
+const request = (url, ...arg) => baseRequest(`/biz/rebaterecord/` + url, ...arg)
+
+/**
+ * 返利记录Api接口管理器
+ *
+ * @author wulei
+ * @date  2025/02/06 17:39
+ **/
+export default {
+	// 获取返利记录分页
+	bizRebateRecordPage(data) {
+		return request('page', data, 'get')
+	},
+	// 提交返利记录表单 edit为true时为编辑,默认为新增
+	bizRebateRecordSubmitForm(data, edit = false) {
+		return request(edit ? 'edit' : 'add', data)
+	},
+	// 删除返利记录
+	bizRebateRecordDelete(data) {
+		return request('delete', data)
+	},
+	// 获取返利记录详情
+	bizRebateRecordDetail(data) {
+		return request('detail', data, 'get')
+	}
+}

+ 28 - 0
snowy-admin-web/src/api/biz/bizRechargeRecordApi.js

@@ -0,0 +1,28 @@
+import { baseRequest } from '@/utils/request'
+
+const request = (url, ...arg) => baseRequest(`/biz/rechargerecord/` + url, ...arg)
+
+/**
+ * 充值记录表Api接口管理器
+ *
+ * @author wulei
+ * @date  2025/02/06 17:41
+ **/
+export default {
+	// 获取充值记录表分页
+	bizRechargeRecordPage(data) {
+		return request('page', data, 'get')
+	},
+	// 提交充值记录表表单 edit为true时为编辑,默认为新增
+	bizRechargeRecordSubmitForm(data, edit = false) {
+		return request(edit ? 'edit' : 'add', data)
+	},
+	// 删除充值记录表
+	bizRechargeRecordDelete(data) {
+		return request('delete', data)
+	},
+	// 获取充值记录表详情
+	bizRechargeRecordDetail(data) {
+		return request('detail', data, 'get')
+	}
+}

+ 28 - 0
snowy-admin-web/src/api/biz/bizRecommendRecordApi.js

@@ -0,0 +1,28 @@
+import { baseRequest } from '@/utils/request'
+
+const request = (url, ...arg) => baseRequest(`/biz/recommendrecord/` + url, ...arg)
+
+/**
+ * 推荐记录表Api接口管理器
+ *
+ * @author wulei
+ * @date  2025/02/06 17:42
+ **/
+export default {
+	// 获取推荐记录表分页
+	bizRecommendRecordPage(data) {
+		return request('page', data, 'get')
+	},
+	// 提交推荐记录表表单 edit为true时为编辑,默认为新增
+	bizRecommendRecordSubmitForm(data, edit = false) {
+		return request(edit ? 'edit' : 'add', data)
+	},
+	// 删除推荐记录表
+	bizRecommendRecordDelete(data) {
+		return request('delete', data)
+	},
+	// 获取推荐记录表详情
+	bizRecommendRecordDetail(data) {
+		return request('detail', data, 'get')
+	}
+}

+ 117 - 13
snowy-admin-web/src/views/biz/consumptionrecord/index.vue

@@ -1,4 +1,57 @@
 <template>
+	<a-card :bordered="false" style="margin-bottom: 10px" class="mb-2">
+		<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
+			<a-row :gutter="24">
+				<a-col :span="6">
+					<a-form-item label="会员姓名" name="userName">
+						<a-input v-model:value="searchFormState.userName" placeholder="会员姓名查询" allow-clear />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="消费操作" name="consumptionOperate">
+						<a-select v-model:value="searchFormState.consumptionOperate" placeholder="消费操作查询" :options="consumptionOperateList">
+						</a-select>
+					</a-form-item>
+				</a-col>
+
+				<a-col :span="6">
+					<a-form-item label="消费门店" name="orgId">
+						<a-tree-select
+							v-model:value="searchFormState.orgId"
+							style="width: 100%"
+							:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
+							placeholder="请选择消费门店"
+							allow-clear
+							tree-default-expand-all
+							:tree-data="treeData"
+							:field-names="{
+									children: 'children',
+									label: 'name',
+									value: 'id'
+								}"
+							selectable="false"
+							tree-line
+						/>
+					</a-form-item>
+				</a-col>
+				<template v-if="advanced">
+					<a-col :span="6">
+						<a-form-item label="消费日期:" name="consumptionTime">
+							<a-range-picker v-model:value="searchFormState.consumptionTime" value-format="YYYY-MM-DD" show-date />
+						</a-form-item>
+					</a-col>
+				</template>
+				<a-col :span="6">
+					<a-button type="primary" html-type="submit" @click="tableRef.refresh()">查询</a-button>
+					<a-button style="margin: 0 8px" @click="reset">重置</a-button>
+					<a @click="toggleAdvanced" style="margin-left: 8px">
+						{{ advanced ? '收起' : '展开' }}
+						<component :is="advanced ? 'up-outlined' : 'down-outlined'" />
+					</a>
+				</a-col>
+			</a-row>
+		</a-form>
+	</a-card>
 	<a-card :bordered="false">
 		<s-table
 			ref="tableRef"
@@ -13,13 +66,6 @@
 						<template #icon><plus-outlined /></template>
 						新增
 					</a-button>
-					<xn-batch-button
-						v-if="hasPerm('consumptionRecordBatchDelete')"
-						buttonName="批量删除"
-                        icon="DeleteOutlined"
-						:selectedRowKeys="selectedRowKeys"
-						@batchCallBack="deleteBatchConsumptionRecord"
-					/>
 				</a-space>
 			</template>
 			<template #bodyCell="{ column, record }">
@@ -32,6 +78,21 @@
 						</a-popconfirm>
 					</a-space>
 				</template>
+				<template v-if="column.dataIndex === 'consumptionOperate'">
+					<a-tag
+						:color="
+							record.consumptionOperate === '1'
+								? 'orange'
+								: record.consumptionOperate === '2'
+								  ? 'green'
+								  : record.consumptionOperate === '3'
+								    ? 'cyan'
+								      : 'purple'
+						"
+					>
+						{{ $TOOL.dictTypeData('consumption_operate', record.consumptionOperate) }}
+					</a-tag>
+				</template>
 			</template>
 		</s-table>
 	</a-card>
@@ -42,13 +103,33 @@
 	import { cloneDeep } from 'lodash-es'
 	import Form from './form.vue'
 	import consumptionRecordApi from '@/api/biz/consumptionRecordApi'
+	import tool from '@/utils/tool'
+	import bizOrgApi from '@/api/biz/bizOrgApi'
+
 	const tableRef = ref()
 	const formRef = ref()
+
+	const searchFormRef = ref()
+	let searchFormState = reactive({})
+	// 查询区域显示更多控制
+	const advanced = ref(false)
+	const toggleAdvanced = () => {
+		advanced.value = !advanced.value
+	}
+
+	const consumptionOperateList = tool.dictList('consumption_operate')
+	const treeData = ref([])
+
 	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
 	const columns = [
 		{
-			title: '用户id',
-			dataIndex: 'userId',
+			title: '会员姓名',
+			dataIndex: 'userName',
+			align: 'center',
+		},
+		{
+			title: '会员手机号',
+			dataIndex: 'phone',
 			align: 'center',
 		},
 		{
@@ -56,23 +137,33 @@
 			dataIndex: 'consumptionOperate',
 			align: 'center',
 		},
+		{
+			title: '原账户余额',
+			dataIndex: 'accountBalance',
+			align: 'center',
+		},
+		{
+			title: '原代金券余额',
+			dataIndex: 'voucherBalance',
+			align: 'center',
+		},
 		{
 			title: '消费金额',
 			dataIndex: 'consumptionMoney',
 			align: 'center',
 		},
 		{
-			title: '消费时间',
+			title: '消费日期',
 			dataIndex: 'consumptionTime',
 			align: 'center',
 		},
 		{
 			title: '消费门店',
-			dataIndex: 'consumptionOrg',
+			dataIndex: 'orgName',
 			align: 'center',
 		},
 		{
-			title: '备注',
+			title: '说明',
 			dataIndex: 'consumptionRemark',
 			align: 'center',
 		},
@@ -86,6 +177,12 @@
 			width: 150
 		})
 	}*/
+
+	// 获取机构树并加入顶级
+	bizOrgApi.orgTreeSelector().then((res) => {
+		treeData.value = res
+	})
+
 	const selectedRowKeys = ref([])
 	// 列表选择配置
 	const options = {
@@ -103,7 +200,14 @@
 		}
 	}
 	const loadData = (parameter) => {
-		return consumptionRecordApi.consumptionRecordPage(parameter).then((data) => {
+		const searchFormParam = JSON.parse(JSON.stringify(searchFormState))
+		// planTime范围查询条件重载
+		if (searchFormParam.consumptionTime) {
+			searchFormParam.consumptionTimeBegin = searchFormParam.consumptionTime[0]
+			searchFormParam.consumptionTimeEnd = searchFormParam.consumptionTime[1]
+			delete searchFormParam.consumptionTime
+		}
+		return consumptionRecordApi.consumptionRecordPage(Object.assign(parameter, searchFormParam)).then((data) => {
 			return data
 		})
 	}

+ 100 - 0
snowy-admin-web/src/views/biz/couponrecord/form.vue

@@ -0,0 +1,100 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '编辑优惠券记录' : '增加优惠券记录'"
+		:width="700"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
+			<a-form-item label="优惠券编码:" name="couponNo">
+				<a-input v-model:value="formData.couponNo" placeholder="请输入优惠券编码" allow-clear />
+			</a-form-item>
+			<a-form-item label="优惠券生成时间:" name="time">
+				<a-date-picker v-model:value="formData.time" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择优惠券生成时间" style="width: 100%" />
+			</a-form-item>
+			<a-form-item label="充值方案id:" name="rechargePlanId">
+				<a-input v-model:value="formData.rechargePlanId" placeholder="请输入充值方案id" allow-clear />
+			</a-form-item>
+			<a-form-item label="充值记录表id:" name="rechargeRecordId">
+				<a-input v-model:value="formData.rechargeRecordId" placeholder="请输入充值记录表id" allow-clear />
+			</a-form-item>
+			<a-form-item label="是否核销: 0.否 1.是:" name="couponStatus">
+				<a-input v-model:value="formData.couponStatus" placeholder="请输入是否核销: 0.否 1.是" allow-clear />
+			</a-form-item>
+			<a-form-item label="有效期开始时间:" name="startTime">
+				<a-date-picker v-model:value="formData.startTime" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择有效期开始时间" style="width: 100%" />
+			</a-form-item>
+			<a-form-item label="有效期截止时间:" name="endTime">
+				<a-date-picker v-model:value="formData.endTime" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择有效期截止时间" style="width: 100%" />
+			</a-form-item>
+			<a-form-item label="核销人:" name="destroyUser">
+				<a-input v-model:value="formData.destroyUser" placeholder="请输入核销人" allow-clear />
+			</a-form-item>
+			<a-form-item label="核销时间:" name="destroyTime">
+				<a-date-picker v-model:value="formData.destroyTime" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择核销时间" style="width: 100%" />
+			</a-form-item>
+			<a-form-item label="核销门店:" name="orgId">
+				<a-input v-model:value="formData.orgId" placeholder="请输入核销门店" allow-clear />
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="bizCouponRecordForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import bizCouponRecordApi from '@/api/biz/bizCouponRecordApi'
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({})
+	const submitLoading = ref(false)
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		open.value = false
+	}
+	// 默认要校验的
+	const formRules = {
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				bizCouponRecordApi
+					.bizCouponRecordSubmitForm(formDataParam, formDataParam.id)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 198 - 0
snowy-admin-web/src/views/biz/couponrecord/index.vue

@@ -0,0 +1,198 @@
+<template>
+	<a-card :bordered="false">
+		<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
+			<a-row :gutter="24">
+				<a-col :span="6">
+					<a-form-item label="优惠券编码" name="couponNo">
+						<a-input v-model:value="searchFormState.couponNo" placeholder="优惠券编码查询" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="是否核销" name="couponStatus">
+<!--						<a-input v-model:value="searchFormState.couponStatus" placeholder="是否核销查询" />-->
+						<a-select v-model:value="searchFormState.couponStatus" placeholder="是否核销查询" :options="couponStatusList">
+						</a-select>
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-button type="primary" @click="tableRef.refresh()">查询</a-button>
+					<a-button style="margin: 0 8px" @click="reset">重置</a-button>
+				</a-col>
+			</a-row>
+		</a-form>
+		<s-table
+			ref="tableRef"
+			:columns="columns"
+			:data="loadData"
+			bordered
+			:row-key="(record) => record.id"
+		>
+			<template #operator class="table-operator">
+				<a-space>
+					<a-button type="primary" @click="formRef.onOpen()" v-if="hasPerm('bizCouponRecordAdd')">
+						<template #icon><plus-outlined /></template>
+						新增
+					</a-button>
+					<xn-batch-button
+						v-if="hasPerm('bizCouponRecordBatchDelete')"
+						buttonName="批量删除"
+                        icon="DeleteOutlined"
+						:selectedRowKeys="selectedRowKeys"
+						@batchCallBack="deleteBatchBizCouponRecord"
+					/>
+				</a-space>
+			</template>
+			<template #bodyCell="{ column, record , index }">
+				<template v-if="column.dataIndex === 'action'">
+					<a-space>
+						<a @click="formRef.onOpen(record)" v-if="hasPerm('bizCouponRecordEdit')">编辑</a>
+						<a-divider type="vertical" v-if="hasPerm(['bizCouponRecordEdit', 'bizCouponRecordDelete'], 'and')" />
+						<a-popconfirm title="确定要删除吗?" @confirm="deleteBizCouponRecord(record)">
+							<a-button type="link" danger size="small" v-if="hasPerm('bizCouponRecordDelete')">删除</a-button>
+						</a-popconfirm>
+					</a-space>
+				</template>
+				<template v-if="column.dataIndex === 'serial'">
+					{{ index + 1 }}
+				</template>
+				<template v-if="column.dataIndex === 'couponStatus'">
+					<a-tag
+						:color="
+							record.couponStatus === '0'
+								? '#87d068'
+								: record.couponStatus === '1'
+								  ? '#f50'
+								      : '#f50'
+						"
+					>
+						{{ $TOOL.dictTypeData('is_destroy', record.couponStatus) }}
+					</a-tag>
+				</template>
+			</template>
+		</s-table>
+	</a-card>
+	<Form ref="formRef" @successful="tableRef.refresh()" />
+</template>
+
+<script setup name="couponrecord">
+	import { cloneDeep } from 'lodash-es'
+	import Form from './form.vue'
+	import bizCouponRecordApi from '@/api/biz/bizCouponRecordApi'
+	import tool from '@/utils/tool'
+	const searchFormState = ref({})
+	const searchFormRef = ref()
+	const tableRef = ref()
+	const formRef = ref()
+	const toolConfig = { refresh: true, height: true, columnSetting: true, striped: false }
+	const couponStatusList = tool.dictList('is_destroy')
+	const columns = [
+		{
+			title: '序号',
+			dataIndex: 'serial',
+			align: 'center',
+			width: 50
+		},
+		{
+			title: '优惠券编码',
+			dataIndex: 'couponNo',
+			align: 'center',
+			width: 200
+		},
+		{
+			title: '优惠券生成时间',
+			dataIndex: 'time',
+			align: 'center',
+			width: 150
+		},
+		{
+			title: '是否核销',
+			dataIndex: 'couponStatus',
+			align: 'center',
+			width: 80
+
+		},
+		{
+			title: '有效期开始时间',
+			dataIndex: 'startTime',
+			align: 'center',
+			width: 150
+		},
+		{
+			title: '有效期截止时间',
+			dataIndex: 'endTime',
+			align: 'center',
+			width: 150
+		},
+		{
+			title: '核销人',
+			dataIndex: 'destroyUserName',
+			align: 'center',
+			width: 120
+		},
+		{
+			title: '核销时间',
+			dataIndex: 'destroyTime',
+			align: 'center',
+			width: 150
+		},
+		{
+			title: '核销门店',
+			dataIndex: 'destroyOrgName',
+			align: 'center',
+			width: 150
+		},
+	]
+	// 操作栏通过权限判断是否显示
+	/*if (hasPerm(['bizCouponRecordEdit', 'bizCouponRecordDelete'])) {
+		columns.push({
+			title: '操作',
+			dataIndex: 'action',
+			align: 'center',
+			width: 150
+		})
+	}*/
+	const selectedRowKeys = ref([])
+	// 列表选择配置
+	const options = {
+		// columns数字类型字段加入 needTotal: true 可以勾选自动算账
+		alert: {
+			show: true,
+			clear: () => {
+				selectedRowKeys.value = ref([])
+			}
+		},
+		rowSelection: {
+			onChange: (selectedRowKey, selectedRows) => {
+				selectedRowKeys.value = selectedRowKey
+			}
+		}
+	}
+	const loadData = (parameter) => {
+		const searchFormParam = cloneDeep(searchFormState.value)
+		return bizCouponRecordApi.bizCouponRecordPage(Object.assign(parameter, searchFormParam)).then((data) => {
+			return data
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		tableRef.value.refresh(true)
+	}
+	// 删除
+	const deleteBizCouponRecord = (record) => {
+		let params = [
+			{
+				id: record.id
+			}
+		]
+		bizCouponRecordApi.bizCouponRecordDelete(params).then(() => {
+			tableRef.value.refresh(true)
+		})
+	}
+	// 批量删除
+	const deleteBatchBizCouponRecord = (params) => {
+		bizCouponRecordApi.bizCouponRecordDelete(params).then(() => {
+			tableRef.value.clearRefreshSelected()
+		})
+	}
+</script>

+ 73 - 20
snowy-admin-web/src/views/biz/member/consumption.vue

@@ -1,36 +1,34 @@
 <template>
 	<xn-form-container
-		:title="formData.id ? '编辑消费记录' : '增加消费记录'"
+		:title="formData.id ? '消费结算' : '消费结算'"
 		:width="700"
 		v-model:open="open"
 		:destroy-on-close="true"
 		@close="onClose"
 	>
-		<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
-			<a-form-item label="用户id:" name="userId">
-				<a-input v-model:value="formData.userId" placeholder="请输入用户id" allow-clear />
+		<a-form ref="formRef" :model="formData" :rules="formRules" :label-col="labelCol" :wrapper-col="wrapperCol">
+			<a-form-item label="会员姓名:" name="name">
+				<a-input v-model:value="formData.name" placeholder="请输入会员姓名" disabled allow-clear />
 			</a-form-item>
-			<a-form-item label="消费方式 1:代金券消费   2:余额消费  3:代金券+余额:" name="consumptionType">
-				<a-input v-model:value="formData.consumptionType" placeholder="请输入消费方式 1:代金券消费   2:余额消费  3:代金券+余额" allow-clear />
+			<a-form-item label="账户余额:" name="accountBalance">
+				<a-input v-model:value="formData.accountBalance" placeholder="请输入账户余额" disabled allow-clear />
 			</a-form-item>
-			<a-form-item label="代金券消费金额:" name="voucherMoney">
-				<a-input v-model:value="formData.voucherMoney" placeholder="请输入代金券消费金额" allow-clear />
+			<a-form-item label="代金券余额:" name="voucherBalance">
+				<a-input v-model:value="formData.voucherBalance" placeholder="请输入代金券余额" disabled allow-clear />
 			</a-form-item>
-			<a-form-item label="账户消费金额:" name="accountMoney">
-				<a-input v-model:value="formData.accountMoney" placeholder="请输入账户消费金额" allow-clear />
+			<a-form-item label="消费金额:" name="consumptionMoney">
+				<a-input-number v-model:value="formData.consumptionMoney" placeholder="请输入消费金额" allow-clear :min="0.1" :max="formData.accountBalance+formData.voucherBalance" style="width:100%"/>
 			</a-form-item>
-			<a-form-item label="消费时间:" name="consumptionTime">
-				<a-date-picker v-model:value="formData.consumptionTime" value-format="YYYY-MM-DD HH:mm:ss" show-time placeholder="请选择消费时间" style="width: 100%" />
+			<a-form-item label="手机号:" name="phoneNumber">
+				<a-input v-model:value="formData.phoneNumber" placeholder="请输入手机号" disabled allow-clear style="width:100%"/>
 			</a-form-item>
-			<a-form-item label="消费门店:" name="consumptionOrg">
-				<a-input v-model:value="formData.consumptionOrg" placeholder="请输入消费门店" allow-clear />
-			</a-form-item>
-			<a-form-item label="备注:" name="consumptionRemark">
-				<a-input v-model:value="formData.consumptionRemark" placeholder="请输入备注" allow-clear />
-			</a-form-item>
-			<a-form-item label="操作:1:赠送  2:扣减  3:消费:" name="consumptionOperate">
-				<a-input v-model:value="formData.consumptionOperate" placeholder="请输入操作:1:赠送  2:扣减  3:消费" allow-clear />
+			<a-form-item label="验证码:" name="phoneCode">
+				<a-input v-model:value="formData.phoneCode" placeholder="请输入验证码" allow-clear style="width:65%"/>
+				<a-button style="margin-left:20px;" type="primary" @click="sendMessage()" :disabled="isDisabled">
+					{{ isDisabled == true? countdown+'秒后重新发送':'发送验证码' }}
+				</a-button>
 			</a-form-item>
+
 		</a-form>
 		<template #footer>
 			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
@@ -43,6 +41,10 @@
 	import { cloneDeep } from 'lodash-es'
 	import { required } from '@/utils/formRules'
 	import consumptionRecordApi from '@/api/biz/consumptionRecordApi'
+	import bizUserApi from "@/api/biz/bizUserApi";
+	import bizAuthApi from "@/api/biz/bizAuthApi";
+
+	import {message, Modal} from 'ant-design-vue';
 	// 抽屉状态
 	const open = ref(false)
 	const emit = defineEmits({ successful: null })
@@ -51,12 +53,27 @@
 	const formData = ref({})
 	const submitLoading = ref(false)
 
+	const labelCol = ref({ span: 5 })
+	const wrapperCol = ref({ span: 18 })
+
+	const buttonText = ref('发送验证码')
+	const countdown = ref(300);
+	const isDisabled = ref(false);
+
 	// 打开抽屉
 	const onOpen = (record) => {
 		open.value = true
+		clearInterval(timer);
+		isDisabled.value = false;
+		countdown.value = 300;
+		isDisabled.value = false
 		if (record) {
 			let recordData = cloneDeep(record)
 			formData.value = Object.assign({}, recordData)
+			formData.value.userId = formData.value.id
+			formData.value.id = ''
+			formData.value.consumptionOperate = '3'
+			formData.value.phoneNumber = formData.value.phone
 		}
 	}
 	// 关闭抽屉
@@ -67,6 +84,12 @@
 	}
 	// 默认要校验的
 	const formRules = {
+		name: [required('请输入消费者姓名')],
+		consumptionMoney: [required('请输入消费金额')],
+		accountBalance:  [required('请输入账户余额')],
+		voucherBalance:  [required('请输入代金券余额')],
+		phoneNumber:  [required('请输入手机号')],
+		phoneCode:  [required('请输入验证码')],
 	}
 	// 验证并提交数据
 	const onSubmit = () => {
@@ -87,6 +110,36 @@
 			})
 			.catch(() => {})
 	}
+
+	let timer = null; // 定时器
+	const sendMessage = () => {
+		console.log("1111")
+		debugger
+		if(!formData.value.phoneNumber){
+			message.error('请先输入手机号!')
+			return
+		}
+		//bizAuthApi.sendMessage({phone:formData.value.phoneNumber}).then((res)=>{
+			/*if(res.code == '200'){
+				message.success("发送成功")
+			}else{
+				message.error(res.msg)
+			}*/
+			// 禁用按钮
+			isDisabled.value = true;
+			// 启动倒计时
+			timer = setInterval(() => {
+				if (countdown.value > 0) {
+					countdown.value--;
+				} else {
+					// 倒计时结束,重置状态
+					clearInterval(timer);
+					isDisabled.value = false;
+					countdown.value = 300;
+				}
+			}, 1000);
+		//})
+	}
 	// 抛出函数
 	defineExpose({
 		onOpen

+ 131 - 0
snowy-admin-web/src/views/biz/member/form.vue

@@ -0,0 +1,131 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '余额调整' : '余额调整'"
+		:width="700"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" :label-col="labelCol" :wrapper-col="wrapperCol">
+			<a-form-item label="会员姓名:" name="name">
+				<a-input v-model:value="formData.name" placeholder="请输入会员姓名" disabled allow-clear />
+			</a-form-item>
+			<a-form-item label="账户余额:" name="accountBalance">
+				<a-input v-model:value="formData.accountBalance" placeholder="请输入账户余额" disabled allow-clear />
+			</a-form-item>
+			<a-form-item label="代金券余额:" name="voucherBalance">
+				<a-input v-model:value="formData.voucherBalance" placeholder="请输入代金券余额" disabled allow-clear />
+			</a-form-item>
+			<a-form-item label="调整方式:" name="consumptionOperate">
+				<a-radio-group button-style="solid" v-model:value="formData.consumptionOperate">
+					<a-radio-button value="1">
+						赠送
+					</a-radio-button>
+					<a-radio-button value="2">
+						扣减
+					</a-radio-button>
+				</a-radio-group>
+			</a-form-item>
+			<a-form-item label="调整类型:" name="consumptionType">
+				<a-radio-group button-style="solid" v-model:value="formData.consumptionType">
+					<a-radio-button value="1">
+						代金券
+					</a-radio-button>
+					<a-radio-button value="2">
+						余额
+					</a-radio-button>
+				</a-radio-group>
+			</a-form-item>
+			<a-form-item label="调整金额:" name="consumptionMoney">
+				<a-input-number v-model:value="formData.consumptionMoney" placeholder="请输入调整金额" allow-clear :min="0.1" :max="99999999" style="width:100%"/>
+			</a-form-item>
+			<a-form-item label="说明:" name="consumptionRemark">
+				<a-input v-model:value="formData.consumptionRemark" placeholder="请输入说明" allow-clear />
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">提交</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="consumptionRecordForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import consumptionRecordApi from '@/api/biz/consumptionRecordApi'
+	import { Modal } from 'ant-design-vue'
+	import { createVNode } from 'vue'
+	import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({})
+	const submitLoading = ref(false)
+
+	const labelCol = ref({ span: 5 })
+	const wrapperCol = ref({ span: 18 })
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+			formData.value.consumptionOperate = ref('1')
+			formData.value.consumptionType = ref('1')
+			formData.value.userId = formData.value.id
+			formData.value.id = ''
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		open.value = false
+	}
+	// 默认要校验的
+	const formRules = {
+		name: [required('请输入消费者姓名')],
+		consumptionOperate:  [required('请选择调整操作')],
+		consumptionType: [required('调整方式')],
+		consumptionMoney: [required('请输入调整金额')],
+		consumptionRemark: [required('请输入说明')],
+		accountBalance:  [required('请输入账户余额')],
+		voucherBalance:  [required('请输入代金券余额')],
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		Modal.confirm({
+			title: '确定要为'+formData.value.name+(formData.value.consumptionOperate=='1'?'赠送':'扣减')+(formData.value.consumptionType=='1'?'代金券':'余额')+formData.value.consumptionMoney+'元吗?',
+			icon: createVNode(ExclamationCircleOutlined),
+			content: '',
+			onOk() {
+				submitLoading.value = true
+				formRef.value
+					.validate()
+					.then(() => {
+						submitLoading.value = true
+						const formDataParam = cloneDeep(formData.value)
+						consumptionRecordApi
+							.consumptionRecordSubmitForm(formDataParam, formDataParam.id)
+							.then(() => {
+								onClose()
+								emit('successful')
+							})
+							.finally(() => {
+								submitLoading.value = false
+							})
+					})
+					.catch(() => {})
+			},
+			onCancel() {}
+		})
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 24 - 9
snowy-admin-web/src/views/biz/member/index.vue

@@ -40,7 +40,9 @@
 					{{ index + 1 }}
 				</template>
 				<template v-if="column.dataIndex === 'gender'">
-					{{ $TOOL.dictTypeData('GENDER', record.gender) }}
+					<span v-if="record.gender !== null">
+						{{ $TOOL.dictTypeData('GENDER', record.gender) }}
+					</span>
 				</template>
 				<template v-if="column.dataIndex === 'userStatus'">
 					<a-tag :color="record.userStatus === 'ENABLE' ? 'blue' : 'pink'">{{
@@ -55,12 +57,13 @@
 			</template>
 		</s-table>
 	</a-card>
+	<Form ref="formRef" @successful="tableRef.refresh()" />
 	<Consumption ref="consumptionRef" @successful="tableRef.refresh()" />
 </template>
 <script setup name="bizUser">
 	import tool from '@/utils/tool'
 	import bizUserApi from '@/api/biz/bizUserApi'
-	import Form from "@/views/biz/consumptionrecord/form.vue";
+	import Form from "./form.vue";
 	import Consumption from './consumption.vue'
 
 	const consumptionRef = ref()
@@ -70,39 +73,51 @@
 			title: '序号',
 			dataIndex: 'serial',
 			align: 'center',
-			width: '50px'
+			width: 50
 		},
 		{
 			title: '账号',
 			dataIndex: 'account',
+			align: 'center',
+			width: 100,
 			ellipsis: true
 		},
 		{
 			title: '姓名',
-			dataIndex: 'name'
+			dataIndex: 'name',
+			width: 120,
+			align: 'center',
 		},
 		{
 			title: '性别',
 			dataIndex: 'gender',
-			width: '50px'
+			align: 'center',
+			width: 80
 		},
 		{
 			title: '手机',
 			dataIndex: 'phone',
+			align: 'center',
+			width: 120,
 			ellipsis: true
 		},
 		{
 			title: '账户余额',
-			dataIndex: 'accountBalance'
+			dataIndex: 'accountBalance',
+			width: 80,
+			align: 'center',
 		},
 		{
 			title: '代金券余额',
-			dataIndex: 'voucherBalance'
+			dataIndex: 'voucherBalance',
+			width: 80,
+			align: 'center',
 		},
 		{
 			title: '状态',
 			dataIndex: 'userStatus',
-			width: '80px'
+			align: 'center',
+			width: 80
 		}
 	]
 	if (hasPerm(['balanceAdjustment'])) {
@@ -110,7 +125,7 @@
 			title: '操作',
 			dataIndex: 'action',
 			align: 'center',
-			width: '150px'
+			width: 150
 		})
 	}
 	const statusData = tool.dictList('COMMON_STATUS')

+ 82 - 0
snowy-admin-web/src/views/biz/rebaterecord/form.vue

@@ -0,0 +1,82 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '编辑返利记录' : '增加返利记录'"
+		:width="700"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
+			<a-form-item label="代金券金额:" name="rebateAmout">
+				<a-input v-model:value="formData.rebateAmout" placeholder="请输入代金券金额" allow-clear />
+			</a-form-item>
+			<a-form-item label="推荐人:" name="recommendUserId">
+				<a-input v-model:value="formData.recommendUserId" placeholder="请输入推荐人" allow-clear />
+			</a-form-item>
+			<a-form-item label="充值人:" name="rechargeUserId">
+				<a-input v-model:value="formData.rechargeUserId" placeholder="请输入充值人" allow-clear />
+			</a-form-item>
+			<a-form-item label="代金券状态: 1. 待生效 2.已生效:" name="rebateStatus">
+				<a-input v-model:value="formData.rebateStatus" placeholder="请输入代金券状态: 1. 待生效 2.已生效" allow-clear />
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="bizRebateRecordForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import bizRebateRecordApi from '@/api/biz/bizRebateRecordApi'
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({})
+	const submitLoading = ref(false)
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		open.value = false
+	}
+	// 默认要校验的
+	const formRules = {
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				bizRebateRecordApi
+					.bizRebateRecordSubmitForm(formDataParam, formDataParam.id)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 114 - 0
snowy-admin-web/src/views/biz/rebaterecord/index.vue

@@ -0,0 +1,114 @@
+<template>
+	<a-card :bordered="false" class="xn-mb10">
+		<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
+			<a-row :gutter="24">
+				<a-col :span="6">
+					<a-form-item label="充值人" name="rechargeSearchKey">
+						<a-input v-model:value="searchFormState.rechargeSearchKey" placeholder="请输入充值人姓名或手机号" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="推荐人" name="recommendSearchKey">
+						<a-input v-model:value="searchFormState.recommendSearchKey" placeholder="请输入推荐人姓名或手机号" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="状态" name="rebateStatus">
+						<a-select v-model:value="searchFormState.rebateStatus" :options="statusData" placeholder="请选择" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-button type="primary" @click="tableRef.refresh()">查询</a-button>
+					<a-button style="margin: 0 8px" @click="reset">重置</a-button>
+				</a-col>
+			</a-row>
+		</a-form>
+	</a-card>
+	<a-card :bordered="false">
+		<s-table ref="tableRef" :columns="columns" :data="loadData" bordered :row-key="(record) => record.id">
+			<template #bodyCell="{ column, record, index }">
+				<template v-if="column.dataIndex === 'serial'">
+					{{ index + 1 }}
+				</template>
+				<template v-if="column.dataIndex === 'rebateRatio'">
+					{{ record.rebateRatio + ' %' }}
+				</template>
+				<template v-if="column.dataIndex === 'rebateStatus'">
+					<a-tag v-if="record.rebateStatus === '2'" color="green">已生效</a-tag>
+					<a-tag v-else color="orange">待生效</a-tag>
+				</template>
+				<!--				<template v-if="column.dataIndex === 'action'">-->
+				<!--					<a-space>-->
+				<!--						<a @click="formRef.onOpen(record)" v-if="hasPerm('bizRebateRecordEdit')">编辑</a>-->
+				<!--					</a-space>-->
+				<!--				</template>-->
+			</template>
+		</s-table>
+	</a-card>
+	<Form ref="formRef" @successful="tableRef.refresh()" />
+</template>
+
+<script setup name="rebaterecord">
+	import { cloneDeep } from 'lodash-es'
+	import Form from './form.vue'
+	import bizRebateRecordApi from '@/api/biz/bizRebateRecordApi'
+	import tool from '@/utils/tool'
+	const searchFormState = ref({})
+	const searchFormRef = ref()
+	const tableRef = ref()
+	const formRef = ref()
+	const columns = [
+		{
+			title: '序号',
+			dataIndex: 'serial',
+			width: 80
+		},
+		{
+			title: '充值人',
+			dataIndex: 'rechargeUserName'
+		},
+		{
+			title: '充值金额(元)',
+			dataIndex: 'rechargeAmount'
+		},
+		{
+			title: '推荐人',
+			dataIndex: 'recommendUserName'
+		},
+		{
+			title: '返利金额(元)',
+			dataIndex: 'rebateAmout'
+		},
+		{
+			title: '返利比例',
+			dataIndex: 'rebateRatio'
+		},
+		{
+			title: '充值时间',
+			dataIndex: 'rechargeTime'
+		},
+		{
+			title: '状态',
+			dataIndex: 'rebateStatus'
+		}
+	]
+	// // 操作栏通过权限判断是否显示
+	// columns.push({
+	// 	title: '操作',
+	// 	dataIndex: 'action',
+	// 	align: 'center',
+	// 	width: 150
+	// })
+	const statusData = tool.dictList('rebate_status')
+	const loadData = (parameter) => {
+		const searchFormParam = cloneDeep(searchFormState.value)
+		return bizRebateRecordApi.bizRebateRecordPage(Object.assign(parameter, searchFormParam)).then((data) => {
+			return data
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		tableRef.value.refresh(true)
+	}
+</script>

+ 1 - 1
snowy-admin-web/src/views/biz/rechargeplanconfig/index.vue

@@ -119,7 +119,7 @@
 			dataIndex: 'couponNum'
 		},
 		{
-			title: '账户余额增加金额(元)',
+			title: '账户增加金额(元)',
 			dataIndex: 'accountBalance'
 		},
 		{

+ 82 - 0
snowy-admin-web/src/views/biz/rechargerecord/form.vue

@@ -0,0 +1,82 @@
+<template>
+	<xn-form-container :title="'充值记录详情'" :width="800" v-model:open="open" :destroy-on-close="true" @close="onClose">
+		<a-form ref="formRef" :model="formData">
+			<a-descriptions :column="2" bordered>
+				<a-descriptions-item label="姓名">{{ formData.name }}</a-descriptions-item>
+				<a-descriptions-item label="充值金额">{{ formData.rechargeAmount }}</a-descriptions-item>
+				<a-descriptions-item label="充值金额">{{ formData.rechargeAmount }}</a-descriptions-item>
+				<a-descriptions-item label="充值时间">{{ formData.rechargeTime }}</a-descriptions-item>
+				<a-descriptions-item label="原账户余额">{{ formData.oldAccountBalance + '元' }}</a-descriptions-item>
+				<a-descriptions-item label="新账户余额">{{ formData.newAccountBalance + '元' }}</a-descriptions-item>
+				<a-descriptions-item label="返利金额" v-if="formData.rebateAmount != null">{{
+					formData.rebateAmount
+				}}</a-descriptions-item>
+				<a-descriptions-item label="蛋糕券数量" v-if="formData.couponNum != null">{{
+					formData.couponNum
+				}}</a-descriptions-item>
+				<a-descriptions-item label="订单号">{{ formData.orderNo }}</a-descriptions-item>
+				<a-descriptions-item label="是否支付">{{ formData.isPay }}</a-descriptions-item>
+				<a-descriptions-item label="充值方案说明:" v-if="formData.rechargePlanId != null">{{
+					formData.rechargePlanDescribe
+				}}</a-descriptions-item>
+			</a-descriptions>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="bizRechargeRecordForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import bizRechargeRecordApi from '@/api/biz/bizRechargeRecordApi'
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({})
+	const submitLoading = ref(false)
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		open.value = false
+	}
+	// 默认要校验的
+	const formRules = {}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				bizRechargeRecordApi
+					.bizRechargeRecordSubmitForm(formDataParam, formDataParam.id)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 110 - 0
snowy-admin-web/src/views/biz/rechargerecord/index.vue

@@ -0,0 +1,110 @@
+<template>
+	<a-card :bordered="false" class="xn-mb10">
+		<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
+			<a-row :gutter="24">
+				<a-col :span="6">
+					<a-form-item label="关键字搜素" name="searchKey">
+						<a-input v-model:value="searchFormState.userId" placeholder="请输入姓名或者手机号" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-form-item label="充值时间" name="rechargeTime">
+						<a-range-picker v-model:value="searchFormState.rechargeTime" value-format="YYYY-MM-DD HH:mm:ss" show-time />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-button type="primary" @click="tableRef.refresh()">查询</a-button>
+					<a-button style="margin: 0 8px" @click="reset">重置</a-button>
+				</a-col>
+			</a-row>
+		</a-form>
+	</a-card>
+	<a-card>
+		<s-table ref="tableRef" :columns="columns" :data="loadData" bordered :row-key="(record) => record.id">
+			<template #bodyCell="{ column, record, index }">
+				<template v-if="column.dataIndex === 'serial'">
+					{{ index + 1 }}
+				</template>
+				<template v-if="column.dataIndex === 'isPay'">
+					<a-tag v-if="record.isPay === true" color="blue">已支付</a-tag>
+					<a-tag v-else color="pink">待支付</a-tag>
+				</template>
+				<template v-if="column.dataIndex === 'action'">
+					<a-space>
+						<a @click="formRef.onOpen(record)">详情</a>
+					</a-space>
+				</template>
+			</template>
+		</s-table>
+	</a-card>
+	<Form ref="formRef" @successful="tableRef.refresh()" />
+</template>
+
+<script setup name="rechargerecord">
+	import { cloneDeep } from 'lodash-es'
+	import Form from './form.vue'
+	import bizRechargeRecordApi from '@/api/biz/bizRechargeRecordApi'
+	const searchFormState = ref({})
+	const searchFormRef = ref()
+	const tableRef = ref()
+	const formRef = ref()
+	const columns = [
+		{
+			title: '序号',
+			dataIndex: 'serial',
+			width: 80
+		},
+		{
+			title: '姓名',
+			dataIndex: 'name'
+		},
+		{
+			title: '手机号',
+			dataIndex: 'phone'
+		},
+		{
+			title: '充值金额(元)',
+			dataIndex: 'rechargeAmount'
+		},
+		{
+			title: '充值时间',
+			dataIndex: 'rechargeTime'
+		},
+		{
+			title: '原账户余额(元)',
+			dataIndex: 'oldAccountBalance'
+		},
+		{
+			title: '新账户余额(元)',
+			dataIndex: 'newAccountBalance'
+		},
+		{
+			title: '是否支付',
+			dataIndex: 'isPay'
+		}
+	]
+	// 操作栏通过权限判断是否显示
+	columns.push({
+		title: '操作',
+		dataIndex: 'action',
+		align: 'center',
+		width: 150
+	})
+	const loadData = (parameter) => {
+		const searchFormParam = cloneDeep(searchFormState.value)
+		// rechargeTime范围查询条件重载
+		if (searchFormParam.rechargeTime) {
+			searchFormParam.startRechargeTime = searchFormParam.rechargeTime[0]
+			searchFormParam.endRechargeTime = searchFormParam.rechargeTime[1]
+			delete searchFormParam.rechargeTime
+		}
+		return bizRechargeRecordApi.bizRechargeRecordPage(Object.assign(parameter, searchFormParam)).then((data) => {
+			return data
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		tableRef.value.refresh(true)
+	}
+</script>

+ 76 - 0
snowy-admin-web/src/views/biz/recommendrecord/form.vue

@@ -0,0 +1,76 @@
+<template>
+	<xn-form-container
+		:title="formData.id ? '编辑推荐记录表' : '增加推荐记录表'"
+		:width="700"
+		v-model:open="open"
+		:destroy-on-close="true"
+		@close="onClose"
+	>
+		<a-form ref="formRef" :model="formData" :rules="formRules" layout="vertical">
+			<a-form-item label="推荐人用户id:" name="recommendUserId">
+				<a-input v-model:value="formData.recommendUserId" placeholder="请输入推荐人用户id" allow-clear />
+			</a-form-item>
+			<a-form-item label="被推荐人用户id:" name="acceptUserId">
+				<a-input v-model:value="formData.acceptUserId" placeholder="请输入被推荐人用户id" allow-clear />
+			</a-form-item>
+		</a-form>
+		<template #footer>
+			<a-button style="margin-right: 8px" @click="onClose">关闭</a-button>
+			<a-button type="primary" @click="onSubmit" :loading="submitLoading">保存</a-button>
+		</template>
+	</xn-form-container>
+</template>
+
+<script setup name="bizRecommendRecordForm">
+	import { cloneDeep } from 'lodash-es'
+	import { required } from '@/utils/formRules'
+	import bizRecommendRecordApi from '@/api/biz/bizRecommendRecordApi'
+	// 抽屉状态
+	const open = ref(false)
+	const emit = defineEmits({ successful: null })
+	const formRef = ref()
+	// 表单数据
+	const formData = ref({})
+	const submitLoading = ref(false)
+
+	// 打开抽屉
+	const onOpen = (record) => {
+		open.value = true
+		if (record) {
+			let recordData = cloneDeep(record)
+			formData.value = Object.assign({}, recordData)
+		}
+	}
+	// 关闭抽屉
+	const onClose = () => {
+		formRef.value.resetFields()
+		formData.value = {}
+		open.value = false
+	}
+	// 默认要校验的
+	const formRules = {
+	}
+	// 验证并提交数据
+	const onSubmit = () => {
+		formRef.value
+			.validate()
+			.then(() => {
+				submitLoading.value = true
+				const formDataParam = cloneDeep(formData.value)
+				bizRecommendRecordApi
+					.bizRecommendRecordSubmitForm(formDataParam, formDataParam.id)
+					.then(() => {
+						onClose()
+						emit('successful')
+					})
+					.finally(() => {
+						submitLoading.value = false
+					})
+			})
+			.catch(() => {})
+	}
+	// 抛出函数
+	defineExpose({
+		onOpen
+	})
+</script>

+ 73 - 0
snowy-admin-web/src/views/biz/recommendrecord/index.vue

@@ -0,0 +1,73 @@
+<template>
+	<a-card :bordered="false" class="xn-mb10">
+		<a-form ref="searchFormRef" name="advanced_search" :model="searchFormState" class="ant-advanced-search-form">
+			<a-row :gutter="24">
+				<a-col :span="6">
+					<a-form-item label="推荐人" name="searchKey">
+						<a-input v-model:value="searchFormState.searchKey" placeholder="请输入推荐人姓名或手机号" />
+					</a-form-item>
+				</a-col>
+				<a-col :span="6">
+					<a-button type="primary" @click="tableRef.refresh()">查询</a-button>
+					<a-button style="margin: 0 8px" @click="reset">重置</a-button>
+				</a-col>
+			</a-row>
+		</a-form>
+	</a-card>
+	<a-card :bordered="false">
+		<s-table ref="tableRef" :columns="columns" :data="loadData" bordered :row-key="(record) => record.id">
+			<template #bodyCell="{ column, record, index }">
+				<template v-if="column.dataIndex === 'serial'">
+					{{ index + 1 }}
+				</template>
+				<!--				<template v-if="column.dataIndex === 'action'">-->
+				<!--					<a-space>-->
+				<!--						<a @click="formRef.onOpen(record)" v-if="hasPerm('bizRecommendRecordEdit')">编辑</a>-->
+				<!--						<a-divider type="vertical" v-if="hasPerm(['bizRecommendRecordEdit', 'bizRecommendRecordDelete'], 'and')" />-->
+				<!--						<a-popconfirm title="确定要删除吗?" @confirm="deleteBizRecommendRecord(record)">-->
+				<!--							<a-button type="link" danger size="small" v-if="hasPerm('bizRecommendRecordDelete')">删除</a-button>-->
+				<!--						</a-popconfirm>-->
+				<!--					</a-space>-->
+				<!--				</template>-->
+			</template>
+		</s-table>
+	</a-card>
+</template>
+
+<script setup name="recommendrecord">
+	import bizRecommendRecordApi from '@/api/biz/bizRecommendRecordApi'
+	import { cloneDeep } from 'lodash-es'
+	const tableRef = ref()
+	const searchFormState = ref({})
+	const searchFormRef = ref()
+	const columns = [
+		{
+			title: '序号',
+			dataIndex: 'serial',
+			width: 80
+		},
+		{
+			title: '推荐人',
+			dataIndex: 'recommendUserName'
+		},
+		{
+			title: '被推荐人',
+			dataIndex: 'acceptUserName'
+		},
+		{
+			title: '推荐时间',
+			dataIndex: 'createTime'
+		}
+	]
+	const loadData = (parameter) => {
+		const searchFormParam = cloneDeep(searchFormState.value)
+		return bizRecommendRecordApi.bizRecommendRecordPage(Object.assign(parameter, searchFormParam)).then((data) => {
+			return data
+		})
+	}
+	// 重置
+	const reset = () => {
+		searchFormRef.value.resetFields()
+		tableRef.value.refresh(true)
+	}
+</script>

+ 40 - 0
snowy-common/src/main/java/vip/xiaonuo/common/util/CommonCouponGeneratorUtil.java

@@ -0,0 +1,40 @@
+package vip.xiaonuo.common.util;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.UUID;
+
+/**
+ * @author wulei
+ * @date 2025/2/7
+ * @Version 1.0
+ * @Description 优惠券编码唯一生成器
+ */
+public class CommonCouponGeneratorUtil {
+    public static String generateCouponCode() {
+        try {
+            // 生成 UUID 作为输入
+            String input = UUID.randomUUID().toString();
+            // 使用 MD5 哈希算法
+            MessageDigest digest = MessageDigest.getInstance("MD5");
+            byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
+            // 将哈希值转换为十六进制字符串
+            StringBuilder sb = new StringBuilder();
+            for (byte b : hash) {
+                sb.append(String.format("%02X", b));
+            }
+            return "BBT-" + sb.substring(0, 12); // 取前 10 位
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("MD5 算法不可用", e);
+        }
+    }
+
+
+    public static void main(String[] args) {
+        for (int i = 0; i < 20; i++) {
+            System.out.println("生成的优惠券编码: " + generateCouponCode());
+        }
+
+    }
+}

+ 4 - 0
snowy-common/src/main/java/vip/xiaonuo/common/util/CommonCryptogramUtil.java

@@ -103,6 +103,10 @@ public class CommonCryptogramUtil {
         }
     }
 
+    public static void main(String[] args) {
+        System.out.printf(doSm4CbcDecrypt(doSm4CbcDecrypt("2963b0080c667173ef63d9f1b4d8159c84fb889274361a2f04f3ca1438a601c6002a8a4efa863ccad024ac0300bb40d2")));
+    }
+
     /**
      * 纯签名
      *

+ 0 - 3
snowy-common/src/main/java/vip/xiaonuo/common/util/CommonWxUtil.java

@@ -34,9 +34,6 @@ public class CommonWxUtil {
 
     private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
 
-    @Resource
-    private CommonCacheOperator commonCacheOperator;
-
     /**
      * 获取微信openId
      *

+ 45 - 0
snowy-common/src/main/java/vip/xiaonuo/common/wx/HttpServletUtils.java

@@ -0,0 +1,45 @@
+package vip.xiaonuo.common.wx;
+
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * @author wulei
+ * @date 2024/11/1
+ * @Version 1.0
+ * @Description TODO
+ */
+public class HttpServletUtils {
+
+    /**
+     * 获取请求体
+     *
+     * @param request
+     * @return
+     * @throws IOException
+     */
+    public static String getRequestBody(HttpServletRequest request) throws IOException {
+        ServletInputStream stream = null;
+        BufferedReader reader = null;
+        StringBuffer sb = new StringBuffer();
+        try {
+            stream = request.getInputStream();
+            // 获取响应
+            reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8));
+            String line;
+            while ((line = reader.readLine()) != null) {
+                sb.append(line);
+            }
+        } catch (IOException e) {
+            throw new IOException("读取返回支付接口数据流出现异常!");
+        } finally {
+            reader.close();
+        }
+        return sb.toString();
+    }
+}

+ 9 - 0
snowy-plugin-api/snowy-plugin-auth-api/src/main/java/vip/xiaonuo/auth/api/SaBaseLoginUserApi.java

@@ -50,6 +50,13 @@ public interface SaBaseLoginUserApi {
      **/
     SaBaseLoginUser getUserByAccount(String account);
 
+    /**
+     * 根据openId获取B端用户信息,查不到则返回null
+     * @param openId
+     * @return
+     */
+    SaBaseLoginUser getUserByOpenId(String openId);
+
     /**
      * 根据账号获取C端用户信息,查不到则返回null
      *
@@ -121,4 +128,6 @@ public interface SaBaseLoginUserApi {
      * @date 2022/4/27 22:57
      */
     void updateUserLoginInfo(String userId, String device);
+
+
 }

+ 13 - 1
snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/controller/AuthClientController.java

@@ -28,7 +28,9 @@ import vip.xiaonuo.auth.core.util.StpClientUtil;
 import vip.xiaonuo.auth.modular.login.param.AuthAccountPasswordLoginParam;
 import vip.xiaonuo.auth.modular.login.param.AuthGetPhoneValidCodeParam;
 import vip.xiaonuo.auth.modular.login.param.AuthPhoneValidCodeLoginParam;
+import vip.xiaonuo.auth.modular.login.param.AuthWxParam;
 import vip.xiaonuo.auth.modular.login.result.AuthPicValidCodeResult;
+import vip.xiaonuo.auth.modular.login.result.WxAuthIUserInfo;
 import vip.xiaonuo.auth.modular.login.service.AuthService;
 import vip.xiaonuo.common.pojo.CommonResult;
 
@@ -121,7 +123,17 @@ public class AuthClientController {
         return CommonResult.data(authService.getClientLoginUser());
     }
 
-
+    /**
+     * 根据微信code码登录
+     *
+     * @author xuyuxiang
+     * @date 2021/10/15 13:12
+     **/
+    @Operation(summary = "根据微信code码登录")
+    @PostMapping("/auth/c/doLoginByCode")
+    public CommonResult<WxAuthIUserInfo> doLoginByCode(@RequestBody @Valid AuthWxParam authWxParam) {
+        return CommonResult.data(authService.doLoginByCode(authWxParam.getCode(), SaClientTypeEnum.B.getValue()));
+    }
 
 
 }

+ 30 - 0
snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/result/WxAuthIUserInfo.java

@@ -0,0 +1,30 @@
+package vip.xiaonuo.auth.modular.login.result;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author wulei
+ * @date 2025/2/5
+ * @Version 1.0
+ * @Description 微信授权信息
+ */
+@Setter
+@Getter
+@AllArgsConstructor
+public class WxAuthIUserInfo {
+    /**
+     * openId
+     */
+    @Schema(description = "openId")
+    private String openId;
+    /**
+     * 登录完成返回的token
+     */
+    @Schema(description = "token")
+    private String token;
+
+}

+ 0 - 22
snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/result/WxAuthInfo.java

@@ -1,22 +0,0 @@
-package vip.xiaonuo.auth.modular.login.result;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Getter;
-import lombok.Setter;
-
-/**
- * @author wulei
- * @date 2025/2/5
- * @Version 1.0
- * @Description 微信授权信息
- */
-@Setter
-@Getter
-public class WxAuthInfo {
-
-    @Schema(description = "openId", requiredMode = Schema.RequiredMode.REQUIRED)
-    private String openId;
-
-
-
-}

+ 2 - 1
snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/service/AuthService.java

@@ -18,6 +18,7 @@ import vip.xiaonuo.auth.modular.login.param.AuthAccountPasswordLoginParam;
 import vip.xiaonuo.auth.modular.login.param.AuthGetPhoneValidCodeParam;
 import vip.xiaonuo.auth.modular.login.param.AuthPhoneValidCodeLoginParam;
 import vip.xiaonuo.auth.modular.login.result.AuthPicValidCodeResult;
+import vip.xiaonuo.auth.modular.login.result.WxAuthIUserInfo;
 
 /**
  * 登录Service接口
@@ -84,5 +85,5 @@ public interface AuthService {
     String doLoginById(String userId, String device, String type);
 
 
-
+    WxAuthIUserInfo doLoginByCode(String code, String type);
 }

+ 25 - 1
snowy-plugin/snowy-plugin-auth/src/main/java/vip/xiaonuo/auth/modular/login/service/impl/AuthServiceImpl.java

@@ -39,12 +39,15 @@ import vip.xiaonuo.auth.modular.login.param.AuthAccountPasswordLoginParam;
 import vip.xiaonuo.auth.modular.login.param.AuthGetPhoneValidCodeParam;
 import vip.xiaonuo.auth.modular.login.param.AuthPhoneValidCodeLoginParam;
 import vip.xiaonuo.auth.modular.login.result.AuthPicValidCodeResult;
+import vip.xiaonuo.auth.modular.login.result.WxAuthIUserInfo;
 import vip.xiaonuo.auth.modular.login.service.AuthService;
 import vip.xiaonuo.common.cache.CommonCacheOperator;
 import vip.xiaonuo.common.consts.CacheConstant;
 import vip.xiaonuo.common.exception.CommonException;
 import vip.xiaonuo.common.util.CommonCryptogramUtil;
 import vip.xiaonuo.common.util.CommonEmailUtil;
+import vip.xiaonuo.common.util.CommonWxUtil;
+import vip.xiaonuo.common.wx.WxPayConfig;
 import vip.xiaonuo.dev.api.DevConfigApi;
 import vip.xiaonuo.dev.api.DevSmsApi;
 
@@ -80,6 +83,10 @@ public class AuthServiceImpl implements AuthService {
 
     @Resource
     private CommonCacheOperator commonCacheOperator;
+    @Resource
+    private CommonWxUtil commonWxUtil;
+    @Resource
+    private WxPayConfig wxPayConfig;
 
 
     @Override
@@ -520,5 +527,22 @@ public class AuthServiceImpl implements AuthService {
         }
     }
 
-
+    @Override
+    public WxAuthIUserInfo doLoginByCode(String code, String type) {
+        // 通过code 获取openId
+        String openId = commonWxUtil.getOpenId(code, wxPayConfig.getGetOpenIdUrl(), wxPayConfig.getAppId(), wxPayConfig.getAppSecret());
+        if (ObjectUtil.isEmpty(openId)) {
+            throw new CommonException("code码错误");
+        }
+        // 通过openId查询用户信息
+        SaBaseLoginUser saBaseClientLoginUser = loginUserApi.getUserByOpenId(openId);
+        // 根据手机号获取用户信息,根据B端或C端判断
+        if (ObjectUtil.isEmpty(saBaseClientLoginUser)) {
+            // 未查询到登录用户直接返回openId
+            return new WxAuthIUserInfo(openId, null);
+        }
+        // 执行B端登录
+        String token = execLoginB(saBaseClientLoginUser, AuthDeviceTypeEnum.MINI.getValue());
+        return new WxAuthIUserInfo(openId, token);
+    }
 }

+ 25 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/core/enums/FundChangeTypeEnum.java

@@ -0,0 +1,25 @@
+package vip.xiaonuo.biz.core.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum FundChangeTypeEnum {
+
+    //充值
+    RECHARGE("1"),
+    //消费
+    CONSUME("2"),
+    //代金券生效
+    VOUCHER_EFFECT("3"),
+    //赠送
+    GIFT("4"),
+    //扣减
+    DEDUCT("5");
+
+    private final String value;
+
+    FundChangeTypeEnum(String value) {
+        this.value = value;
+    }
+
+}

+ 10 - 4
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/controller/ConsumptionRecordController.java

@@ -21,13 +21,11 @@ import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.biz.modular.consumptionrecord.param.*;
 import vip.xiaonuo.common.annotation.CommonLog;
+import vip.xiaonuo.common.annotation.CommonNoRepeat;
 import vip.xiaonuo.common.pojo.CommonResult;
 import vip.xiaonuo.biz.modular.consumptionrecord.entity.ConsumptionRecord;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordAddParam;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordEditParam;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordIdParam;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordPageParam;
 import vip.xiaonuo.biz.modular.consumptionrecord.service.ConsumptionRecordService;
 
 import jakarta.annotation.Resource;
@@ -72,6 +70,7 @@ public class ConsumptionRecordController {
     @CommonLog("消费结算&会员管理赠送消费")
     @SaCheckPermission("/biz/consumptionrecord/add")
     @PostMapping("/biz/consumptionrecord/add")
+    @CommonNoRepeat
     public CommonResult<String> add(@RequestBody @Valid ConsumptionRecordAddParam consumptionRecordAddParam) {
         consumptionRecordService.add(consumptionRecordAddParam);
         return CommonResult.ok();
@@ -120,4 +119,11 @@ public class ConsumptionRecordController {
     public CommonResult<ConsumptionRecord> detail(@Valid ConsumptionRecordIdParam consumptionRecordIdParam) {
         return CommonResult.data(consumptionRecordService.detail(consumptionRecordIdParam));
     }
+
+    @Operation(summary = "门店每日销售额统计")
+    @SaCheckPermission("/biz/consumptionrecord/getRecordTotal")
+    @GetMapping("/biz/consumptionrecord/getRecordTotal")
+    public CommonResult<ConsumptionResult> getRecordTotal() {
+        return CommonResult.data(consumptionRecordService.getRecordTotal());
+    }
 }

+ 33 - 30
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/entity/ConsumptionRecord.java

@@ -16,6 +16,8 @@ import com.baomidou.mybatisplus.annotation.*;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Getter;
 import lombok.Setter;
+import vip.xiaonuo.common.pojo.CommonEntity;
+
 import java.math.BigDecimal;
 import java.util.Date;
 
@@ -27,8 +29,8 @@ import java.util.Date;
  **/
 @Getter
 @Setter
-@TableName("consumption_record")
-public class ConsumptionRecord {
+@TableName("biz_consumption_record")
+public class ConsumptionRecord extends CommonEntity {
 
     /** 主键ID */
     @TableId
@@ -44,11 +46,11 @@ public class ConsumptionRecord {
     private String consumptionType;
 
     /** 代金券消费金额 */
-    @Schema(description = "代金券消费金额")
+    @Schema(description = "代金券金额")
     private BigDecimal voucherMoney;
 
     /** 账户消费金额 */
-    @Schema(description = "账户消费金额")
+    @Schema(description = "账户金额")
     private BigDecimal accountMoney;
 
     /** 消费时间 */
@@ -63,32 +65,6 @@ public class ConsumptionRecord {
     @Schema(description = "备注")
     private String consumptionRemark;
 
-    /** 删除标识 */
-    @Schema(description = "删除标识")
-    @TableLogic
-    @TableField(fill = FieldFill.INSERT)
-    private String deleteFlag;
-
-    /** 创建时间 */
-    @Schema(description = "创建时间")
-    @TableField(fill = FieldFill.INSERT)
-    private Date createTime;
-
-    /** 创建人 */
-    @Schema(description = "创建人")
-    @TableField(fill = FieldFill.INSERT)
-    private String createUser;
-
-    /** 修改时间 */
-    @Schema(description = "修改时间")
-    @TableField(fill = FieldFill.UPDATE)
-    private Date updateTime;
-
-    /** 修改人 */
-    @Schema(description = "修改人")
-    @TableField(fill = FieldFill.UPDATE)
-    private String updateUser;
-
     /** 操作:1:赠送  2:扣减  3:消费 */
     @Schema(description = "操作:1:赠送  2:扣减  3:消费")
     private String consumptionOperate;
@@ -96,4 +72,31 @@ public class ConsumptionRecord {
     /**总金额*/
     @Schema(description = "总金额")
     private BigDecimal consumptionMoney;
+
+    /**消费者姓名*/
+    @TableField(exist = false)
+    private String userName;
+    /**消费门店*/
+    @TableField(exist = false)
+    private String orgName;
+
+    /**原代金券余额*/
+    @Schema(description = "原代金券余额")
+    private BigDecimal voucherBalance;
+
+    /**原账户余额*/
+    @Schema(description = "原账户余额")
+    private BigDecimal accountBalance;
+
+    /**会员手机号*/
+    @TableField(exist = false)
+    private String phone;
+
+    /**现账户余额*/
+    @TableField(exist = false)
+    private BigDecimal newAccountBalance;
+
+    /**现代金券余额*/
+    @TableField(exist = false)
+    private BigDecimal newVoucherBalance;
 }

+ 7 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/mapper/ConsumptionRecordMapper.java

@@ -12,8 +12,12 @@
  */
 package vip.xiaonuo.biz.modular.consumptionrecord.mapper;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
 import vip.xiaonuo.biz.modular.consumptionrecord.entity.ConsumptionRecord;
+import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionResult;
 
 /**
  * 消费记录Mapper接口
@@ -22,4 +26,7 @@ import vip.xiaonuo.biz.modular.consumptionrecord.entity.ConsumptionRecord;
  * @date  2025/02/06 08:56
  **/
 public interface ConsumptionRecordMapper extends BaseMapper<ConsumptionRecord> {
+    Page<ConsumptionRecord> getPageList(@Param("page") Page<ConsumptionRecord> page, @Param("ew") QueryWrapper<ConsumptionRecord> ew);
+
+    ConsumptionResult getRecordTotal(@Param("ew") QueryWrapper<ConsumptionRecord> ew);
 }

+ 34 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/mapper/mapping/ConsumptionRecordMapper.xml

@@ -2,4 +2,38 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="vip.xiaonuo.biz.modular.consumptionrecord.mapper.ConsumptionRecordMapper">
 
+    <select id="getPageList" resultType="vip.xiaonuo.biz.modular.consumptionrecord.entity.ConsumptionRecord">
+        select
+            cr.id,
+            su.name userName,
+            cr.consumption_type,
+            IFNULL(cr.voucher_money,0) voucher_money,
+            IFNULL(cr.account_money,0) account_money,
+            cr.consumption_time,
+            so.name orgName,
+            cr.consumption_remark,
+            cr.consumption_operate,
+            IFNULL(cr.consumption_money,0) consumption_money,
+            IFNULL(cr.voucher_balance,0) voucher_balance,
+            IFNULL(cr.account_balance,0) account_balance,
+            su.PHONE,
+            su.ACCOUNT_BALANCE newAccountBalance,
+            su.VOUCHER_BALANCE newVoucherBalance
+        from biz_consumption_record cr
+        left join SYS_USER su on cr.user_id = su.id
+        left join SYS_ORG so on so.id = cr.consumption_org
+        <where>
+            ${ew.sqlSegment}
+        </where>
+    </select>
+
+    <select id="getRecordTotal" resultType="vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionResult">
+        select
+            count(*) orderCount,
+            sum(bcr.consumption_money) orderMoney
+        from biz_consumption_record bcr
+        <where>
+            ${ew.sqlSegment}
+        </where>
+    </select>
 </mapper>

+ 8 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/param/ConsumptionRecordAddParam.java

@@ -67,4 +67,12 @@ public class ConsumptionRecordAddParam {
     @Schema(description = "总金额")
     private BigDecimal consumptionMoney;
 
+    /**手机号*/
+    @Schema(description = "手机号")
+    private String phoneNumber;
+
+    /**验证码*/
+    @Schema(description = "验证码")
+    private String phoneCode;
+
 }

+ 13 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/param/ConsumptionRecordPageParam.java

@@ -48,4 +48,17 @@ public class ConsumptionRecordPageParam {
     @Schema(description = "关键词")
     private String searchKey;
 
+    /**姓名*/
+    private String userName;
+
+    /**消费操作*/
+    private String consumptionOperate;
+
+    /**消费门店*/
+    private String orgId;
+
+    /**消费日期*/
+    private String consumptionTimeBegin;
+    private String consumptionTimeEnd;
+
 }

+ 14 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/param/ConsumptionResult.java

@@ -0,0 +1,14 @@
+package vip.xiaonuo.biz.modular.consumptionrecord.param;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class ConsumptionResult {
+    /**当日订单竖*/
+    private Integer orderCount;
+
+    /**当日销售额*/
+    private BigDecimal orderMoney;
+}

+ 3 - 4
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/service/ConsumptionRecordService.java

@@ -15,10 +15,7 @@ package vip.xiaonuo.biz.modular.consumptionrecord.service;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import vip.xiaonuo.biz.modular.consumptionrecord.entity.ConsumptionRecord;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordAddParam;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordEditParam;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordIdParam;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordPageParam;
+import vip.xiaonuo.biz.modular.consumptionrecord.param.*;
 
 import java.util.List;
 
@@ -77,4 +74,6 @@ public interface ConsumptionRecordService extends IService<ConsumptionRecord> {
      * @date  2025/02/06 08:56
      **/
     ConsumptionRecord queryEntity(String id);
+
+    ConsumptionResult getRecordTotal();
 }

+ 142 - 20
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/consumptionrecord/service/impl/ConsumptionRecordServiceImpl.java

@@ -14,29 +14,35 @@ package vip.xiaonuo.biz.modular.consumptionrecord.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.PhoneUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import jakarta.annotation.Resource;
 import org.apache.commons.lang3.StringUtils;
+import org.checkerframework.checker.units.qual.C;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
+import vip.xiaonuo.biz.modular.consumptionrecord.param.*;
 import vip.xiaonuo.biz.modular.user.entity.BizUser;
 import vip.xiaonuo.biz.modular.user.service.BizUserService;
+import vip.xiaonuo.biz.modular.userfundchangerecord.entity.BizUserFundChangeRecord;
+import vip.xiaonuo.biz.modular.userfundchangerecord.service.BizUserFundChangeRecordService;
+import vip.xiaonuo.common.cache.CommonCacheOperator;
 import vip.xiaonuo.common.enums.CommonSortOrderEnum;
 import vip.xiaonuo.common.exception.CommonException;
 import vip.xiaonuo.common.page.CommonPageRequest;
 import vip.xiaonuo.biz.modular.consumptionrecord.entity.ConsumptionRecord;
 import vip.xiaonuo.biz.modular.consumptionrecord.mapper.ConsumptionRecordMapper;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordAddParam;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordEditParam;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordIdParam;
-import vip.xiaonuo.biz.modular.consumptionrecord.param.ConsumptionRecordPageParam;
 import vip.xiaonuo.biz.modular.consumptionrecord.service.ConsumptionRecordService;
+import vip.xiaonuo.common.util.CommonCryptogramUtil;
 
 import java.math.BigDecimal;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -51,17 +57,55 @@ public class ConsumptionRecordServiceImpl extends ServiceImpl<ConsumptionRecordM
     @Resource
     private BizUserService bizUserService;
 
+    @Resource
+    private CommonCacheOperator commonCacheOperator;
+
+    @Resource
+    private BizUserFundChangeRecordService bizUserFundChangeRecordService;
+
     @Override
     public Page<ConsumptionRecord> page(ConsumptionRecordPageParam consumptionRecordPageParam) {
         QueryWrapper<ConsumptionRecord> queryWrapper = new QueryWrapper<ConsumptionRecord>().checkSqlInjection();
-        if(ObjectUtil.isAllNotEmpty(consumptionRecordPageParam.getSortField(), consumptionRecordPageParam.getSortOrder())) {
-            CommonSortOrderEnum.validate(consumptionRecordPageParam.getSortOrder());
-            queryWrapper.orderBy(true, consumptionRecordPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
-                    StrUtil.toUnderlineCase(consumptionRecordPageParam.getSortField()));
+        if(ObjectUtil.isNotEmpty(consumptionRecordPageParam.getUserName())){
+            queryWrapper.like("su.name",consumptionRecordPageParam.getUserName());
+        }
+        if(ObjectUtil.isNotEmpty(consumptionRecordPageParam.getConsumptionOperate())){
+            queryWrapper.eq("cr.consumption_operate",consumptionRecordPageParam.getConsumptionOperate());
+        }
+        if(ObjectUtil.isNotEmpty(consumptionRecordPageParam.getOrgId())){
+            queryWrapper.eq("cr.consumption_org",consumptionRecordPageParam.getOrgId());
+        }
+        if(ObjectUtil.isNotEmpty(consumptionRecordPageParam.getConsumptionTimeBegin()) &&
+                ObjectUtil.isNotEmpty(consumptionRecordPageParam.getConsumptionTimeEnd())){
+            queryWrapper.between("cr.consumption_time",consumptionRecordPageParam.getConsumptionTimeBegin()+" 00:00:00",consumptionRecordPageParam.getConsumptionTimeEnd()+" 23:59:59");
+        }
+        // 校验数据范围
+        List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
+        if (ObjectUtil.isNotEmpty(loginUserDataScope)) {
+            queryWrapper.in("cr.consumption_org", loginUserDataScope);
         } else {
-            queryWrapper.lambda().orderByAsc(ConsumptionRecord::getId);
+            queryWrapper.in("cr.user_id", StpLoginUserUtil.getLoginUser().getId());
         }
-        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
+        queryWrapper.orderByDesc("cr.create_time");
+        Page<ConsumptionRecord> pageList = this.getBaseMapper().getPageList(CommonPageRequest.defaultPage(), queryWrapper);
+        for(ConsumptionRecord consumptionRecord : pageList.getRecords()){
+            if(ObjectUtil.isNotEmpty(consumptionRecord.getPhone())){
+                consumptionRecord.setPhone(CommonCryptogramUtil.doSm4CbcDecrypt(consumptionRecord.getPhone()));
+            }
+            if(StringUtils.equals(consumptionRecord.getConsumptionOperate(),"3") || StringUtils.equals(consumptionRecord.getConsumptionOperate(),"4")){
+                //消费结算,设置下说明
+                if(StringUtils.equals(consumptionRecord.getConsumptionType(),"1")){
+                    consumptionRecord.setConsumptionRemark("代金券消费"+consumptionRecord.getVoucherMoney().stripTrailingZeros().toPlainString()+"元");
+                }
+                if(StringUtils.equals(consumptionRecord.getConsumptionType(),"2")){
+                    consumptionRecord.setConsumptionRemark("账户余额消费"+consumptionRecord.getAccountMoney().stripTrailingZeros().toPlainString()+"元");
+                }
+                if(StringUtils.equals(consumptionRecord.getConsumptionType(),"3")){
+                    consumptionRecord.setConsumptionRemark("代金券消费"+consumptionRecord.getVoucherMoney().stripTrailingZeros().toPlainString()+"元"+",账户余额消费"+consumptionRecord.getAccountMoney().stripTrailingZeros().toPlainString()+"元");
+                }
+            }
+        }
+        return pageList;
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -72,38 +116,75 @@ public class ConsumptionRecordServiceImpl extends ServiceImpl<ConsumptionRecordM
         ConsumptionRecord consumptionRecord = BeanUtil.toBean(consumptionRecordAddParam, ConsumptionRecord.class);
         //获取用户信息
         BizUser bizUser = bizUserService.getById(consumptionRecordAddParam.getUserId());
+        //记录账户变动信息
+        BizUserFundChangeRecord bizUserFundChangeRecord = new BizUserFundChangeRecord();
+        bizUserFundChangeRecord.setOldAccountBalance(bizUser.getAccountBalance());
+        bizUserFundChangeRecord.setOldVoucherBalance(bizUser.getVoucherBalance());
+        //消费记录信息
+        consumptionRecord.setVoucherBalance(bizUser.getVoucherBalance());
+        consumptionRecord.setAccountBalance(bizUser.getAccountBalance());
         if(StringUtils.equals(consumptionRecordAddParam.getConsumptionOperate(),"1")){
+            bizUserFundChangeRecord.setChangeType("4");
             //会员赠送
             if(StringUtils.equals(consumptionRecordAddParam.getConsumptionType(),"1")){
                 //判断当前选择的是代金券还是余额 1:代金券   2:余额
                 //选择代金券,用户原有代金券金额+本地赠送金额
-                bizUser.setVoucherBalance(bizUser.getVoucherBalance().add(consumptionRecordAddParam.getVoucherMoney()));
-                consumptionRecord.setConsumptionMoney(consumptionRecordAddParam.getVoucherMoney());
+                bizUser.setVoucherBalance(bizUser.getVoucherBalance().add(consumptionRecordAddParam.getConsumptionMoney()));
+                consumptionRecord.setVoucherMoney(consumptionRecordAddParam.getConsumptionMoney());
             }else if(StringUtils.equals(consumptionRecordAddParam.getConsumptionType(),"2")){
                 //选择余额,用户原有余额+本次赠送余额金额
-                bizUser.setAccountBalance(bizUser.getAccountBalance().add(consumptionRecordAddParam.getAccountMoney()));
-                consumptionRecord.setConsumptionMoney(consumptionRecordAddParam.getAccountMoney());
+                bizUser.setAccountBalance(bizUser.getAccountBalance().add(consumptionRecordAddParam.getConsumptionMoney()));
+                consumptionRecord.setAccountMoney(consumptionRecordAddParam.getConsumptionMoney());
             }
         }else if(StringUtils.equals(consumptionRecordAddParam.getConsumptionOperate(),"2")){
+            bizUserFundChangeRecord.setChangeType("5");
+            if(bizUser.getVoucherBalance().compareTo(BigDecimal.ZERO) == 0){
+                throw new CommonException("会员当前代金券余额为0,不可扣减!");
+            }
+            if(bizUser.getAccountBalance().compareTo(BigDecimal.ZERO) == 0){
+                throw new CommonException("会员当前账户余额为0,不可扣减!");
+            }
             //会员扣减
             if(StringUtils.equals(consumptionRecordAddParam.getConsumptionType(),"1")){
                 //选择代金券,用户原有代金券金额-本次扣减金额
-                bizUser.setVoucherBalance(bizUser.getVoucherBalance().subtract(consumptionRecordAddParam.getVoucherMoney()));
-                consumptionRecord.setConsumptionMoney(consumptionRecordAddParam.getVoucherMoney());
+                if(consumptionRecord.getConsumptionMoney().compareTo(bizUser.getVoucherBalance()) > 0){
+                    throw new CommonException("会员当前代金券余额不足,不可扣减!");
+                }
+                bizUser.setVoucherBalance(bizUser.getVoucherBalance().subtract(consumptionRecordAddParam.getConsumptionMoney()));
+                consumptionRecord.setVoucherMoney(consumptionRecordAddParam.getConsumptionMoney());
             }else if(StringUtils.equals(consumptionRecordAddParam.getConsumptionType(),"2")){
                 //选择账户余额,用户原有余额-本次扣减余额
-                bizUser.setAccountBalance(bizUser.getAccountBalance().subtract(consumptionRecordAddParam.getAccountMoney()));
-                consumptionRecord.setConsumptionMoney(consumptionRecordAddParam.getAccountMoney());
+                if(consumptionRecord.getConsumptionMoney().compareTo(bizUser.getAccountBalance()) > 0){
+                    throw new CommonException("会员当前账户余额不足,不可扣减!");
+                }
+                bizUser.setAccountBalance(bizUser.getAccountBalance().subtract(consumptionRecordAddParam.getConsumptionMoney()));
+                consumptionRecord.setAccountMoney(consumptionRecordAddParam.getConsumptionMoney());
             }
-        }else {
+        }else{
+            bizUserFundChangeRecord.setChangeType("2");
             //正常消费结算
+            //人工结算需要短信校验,获取手机验证码
+            if(StringUtils.equals(consumptionRecordAddParam.getConsumptionOperate(),"3")){
+                Object code = commonCacheOperator.get(consumptionRecordAddParam.getPhoneNumber());
+                if(!StringUtils.equals(code.toString(),consumptionRecordAddParam.getPhoneCode())){
+                    throw new CommonException("验证码不正确!");
+                }else{
+                    commonCacheOperator.remove(consumptionRecordAddParam.getPhoneNumber());
+                }
+            }
             //判断当前消费金额是否大于代金券金额,优先扣减代金券金额
             if(consumptionRecordAddParam.getConsumptionMoney().compareTo(bizUser.getVoucherBalance()) > 0){
+                //判断代金券金额是否大于0
+                if(bizUser.getVoucherBalance().compareTo(BigDecimal.ZERO) > 0){
+                    consumptionRecord.setConsumptionType("3");
+                }else{
+                    consumptionRecord.setConsumptionType("2");
+                }
                 //计算本次消费和代金券差额
                 BigDecimal subtract = consumptionRecordAddParam.getConsumptionMoney().subtract(bizUser.getVoucherBalance());
                 //如果差额大于账户余额,表示账户余额不足
                 if(subtract.compareTo(bizUser.getAccountBalance()) > 0){
-                    throw new CommonException("账户余额不足!");
+                    throw new CommonException("账户余额不足,请先充值!");
                 }
                 //记录消费信息
                 consumptionRecord.setVoucherMoney(bizUser.getVoucherBalance());
@@ -116,12 +197,20 @@ public class ConsumptionRecordServiceImpl extends ServiceImpl<ConsumptionRecordM
                 //直接扣减代金券
                 bizUser.setVoucherBalance(bizUser.getVoucherBalance().subtract(consumptionRecordAddParam.getConsumptionMoney()));
                 consumptionRecord.setVoucherMoney(consumptionRecordAddParam.getConsumptionMoney());
+                consumptionRecord.setConsumptionType("1");
             }
         }
         //保存消费记录
+        consumptionRecord.setConsumptionOrg(StpLoginUserUtil.getLoginUser().getOrgId());
+        consumptionRecord.setConsumptionTime(new Date());
         this.save(consumptionRecord);
         //修改账户余额
         bizUserService.updateById(bizUser);
+        //账户变动信息
+        bizUserFundChangeRecord.setNewAccountBalance(bizUser.getAccountBalance());
+        bizUserFundChangeRecord.setNewVoucherBalance(bizUser.getVoucherBalance());
+        bizUserFundChangeRecord.setUserId(bizUser.getId());
+        bizUserFundChangeRecordService.save(bizUserFundChangeRecord);
     }
 
     //会员赠送/扣减
@@ -145,9 +234,23 @@ public class ConsumptionRecordServiceImpl extends ServiceImpl<ConsumptionRecordM
                 throw new CommonException("消费方式consumptionType不能为空!");
             }
         }
+        if(StringUtils.equals(consumptionRecordAddParam.getConsumptionOperate(),"3")){
+            //人工结算,手机号,短信验证码校验
+            if(ObjectUtil.isEmpty(consumptionRecordAddParam.getPhoneNumber())){
+                throw new CommonException("手机号phoneNumber不能为空!");
+            }
+            if(ObjectUtil.isEmpty(consumptionRecordAddParam.getPhoneCode())){
+                throw new CommonException("短信验证码phoneCode不能为空!");
+            }
+        }
         if(ObjectUtil.isEmpty(consumptionRecordAddParam.getUserId())){
             throw new CommonException("用户userId不能为空!");
         }
+        if(ObjectUtil.isNotEmpty(consumptionRecordAddParam.getPhoneNumber())){
+            if (!PhoneUtil.isMobile(consumptionRecordAddParam.getPhoneNumber())) {
+                throw new CommonException("手机号码:{}格式错误", consumptionRecordAddParam.getPhoneNumber());
+            }
+        }
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -178,4 +281,23 @@ public class ConsumptionRecordServiceImpl extends ServiceImpl<ConsumptionRecordM
         }
         return consumptionRecord;
     }
+
+    @Override
+    public ConsumptionResult getRecordTotal() {
+        String format = DateUtil.format(DateUtil.date(), "yyyy-MM-dd");
+        QueryWrapper<ConsumptionRecord> queryWrapper = new QueryWrapper<>();
+        // 校验数据范围
+        List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
+        if (ObjectUtil.isNotEmpty(loginUserDataScope)) {
+            queryWrapper.in("bcr.consumption_org", loginUserDataScope);
+        }else{
+            ConsumptionResult consumptionResult = new ConsumptionResult();
+            consumptionResult.setOrderCount(0);
+            consumptionResult.setOrderMoney(new BigDecimal(0));
+            return consumptionResult;
+        }
+        queryWrapper.in("bcr.consumption_operate",'3','4');
+        queryWrapper.between("bcr.consumption_time", format+" 00:00:00",format+" 23:59:59");
+        return this.getBaseMapper().getRecordTotal(queryWrapper);
+    }
 }

+ 150 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/controller/BizCouponRecordController.java

@@ -0,0 +1,150 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.common.annotation.CommonLog;
+import vip.xiaonuo.common.pojo.CommonResult;
+import vip.xiaonuo.biz.modular.couponrecord.entity.BizCouponRecord;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordAddParam;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordEditParam;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordIdParam;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordPageParam;
+import vip.xiaonuo.biz.modular.couponrecord.service.BizCouponRecordService;
+
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * 优惠券记录控制器
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ */
+@Tag(name = "优惠券记录控制器")
+@RestController
+@Validated
+public class BizCouponRecordController {
+
+    @Resource
+    private BizCouponRecordService bizCouponRecordService;
+
+    /**
+     * 获取优惠券记录分页
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    @Operation(summary = "获取优惠券记录分页")
+    @SaCheckPermission("/biz/couponrecord/page")
+    @GetMapping("/biz/couponrecord/page")
+    public CommonResult<Page<BizCouponRecord>> page(BizCouponRecordPageParam bizCouponRecordPageParam) {
+        return CommonResult.data(bizCouponRecordService.page(bizCouponRecordPageParam));
+    }
+
+    /**
+     * 添加优惠券记录
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    @Operation(summary = "添加优惠券记录")
+    @CommonLog("添加优惠券记录")
+    @SaCheckPermission("/biz/couponrecord/add")
+    @PostMapping("/biz/couponrecord/add")
+    public CommonResult<String> add(@RequestBody @Valid BizCouponRecordAddParam bizCouponRecordAddParam) {
+        bizCouponRecordService.add(bizCouponRecordAddParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 编辑优惠券记录
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    @Operation(summary = "编辑优惠券记录")
+    @CommonLog("编辑优惠券记录")
+    @SaCheckPermission("/biz/couponrecord/edit")
+    @PostMapping("/biz/couponrecord/edit")
+    public CommonResult<String> edit(@RequestBody @Valid BizCouponRecordEditParam bizCouponRecordEditParam) {
+        bizCouponRecordService.edit(bizCouponRecordEditParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除优惠券记录
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    @Operation(summary = "删除优惠券记录")
+    @CommonLog("删除优惠券记录")
+    @SaCheckPermission("/biz/couponrecord/delete")
+    @PostMapping("/biz/couponrecord/delete")
+    public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
+                                                   List<BizCouponRecordIdParam> bizCouponRecordIdParamList) {
+        bizCouponRecordService.delete(bizCouponRecordIdParamList);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 获取优惠券记录详情
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    @Operation(summary = "获取优惠券记录详情")
+    @SaCheckPermission("/biz/couponrecord/detail")
+    @GetMapping("/biz/couponrecord/detail")
+    public CommonResult<BizCouponRecord> detail(@Valid BizCouponRecordIdParam bizCouponRecordIdParam) {
+        return CommonResult.data(bizCouponRecordService.detail(bizCouponRecordIdParam));
+    }
+
+    /**
+     * 根据编码获取优惠券记录列表
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    @Operation(summary = "根据编码获取优惠券记录列表")
+    @SaCheckPermission("/biz/couponrecord/queryByCode")
+    @GetMapping("/biz/couponrecord/queryByCode")
+    public CommonResult<BizCouponRecord> queryByCode(@Valid BizCouponRecordPageParam bizCouponRecordPageParam) {
+        return CommonResult.data(bizCouponRecordService.queryByCode(bizCouponRecordPageParam));
+    }
+
+    /**
+     * 优惠券核销
+     * @param bizCouponRecordEditParam
+     * @return
+     */
+    @Operation(summary = "优惠券核销")
+    @CommonLog("优惠券核销")
+    @SaCheckPermission("/biz/couponrecord/destroy")
+    @PostMapping("/biz/couponrecord/destroy")
+    public CommonResult<String> destroy(@RequestBody @Valid BizCouponRecordEditParam bizCouponRecordEditParam) {
+        bizCouponRecordService.destroy(bizCouponRecordEditParam);
+        return CommonResult.ok();
+    }
+}

+ 96 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/entity/BizCouponRecord.java

@@ -0,0 +1,96 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import vip.xiaonuo.common.pojo.CommonEntity;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 优惠券记录实体
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+@Getter
+@Setter
+@TableName("biz_coupon_record")
+public class BizCouponRecord extends CommonEntity {
+
+    /** 优惠券记录表id */
+    @TableId
+    @Schema(description = "优惠券记录表id")
+    private String id;
+
+    /** 优惠券编码 */
+    @Schema(description = "优惠券编码")
+    private String couponNo;
+
+    /** 优惠券生成时间 */
+    @Schema(description = "优惠券生成时间")
+    private Date time;
+
+    /** 充值方案id */
+    @Schema(description = "充值方案id")
+    private String rechargePlanId;
+
+    /** 充值记录表id */
+    @Schema(description = "充值记录表id")
+    private String rechargeRecordId;
+
+    /** 是否核销: 0.否 1.是 */
+    @Schema(description = "是否核销: 0.否 1.是")
+    private String couponStatus;
+
+    /** 有效期开始时间 */
+    @Schema(description = "有效期开始时间")
+    private Date startTime;
+
+    /** 有效期截止时间 */
+    @Schema(description = "有效期截止时间")
+    private Date endTime;
+
+    /** 核销人 */
+    @Schema(description = "核销人")
+    private String destroyUser;
+
+    /** 核销时间 */
+    @Schema(description = "核销时间")
+    private Date destroyTime;
+
+    /** 核销门店 */
+    @Schema(description = "核销门店")
+    private String orgId;
+
+    /**核销人姓名*/
+    @TableField(exist = false)
+    private String destroyUserName;
+    /**核销门店*/
+    @TableField(exist = false)
+    private String destroyOrgName;
+    /**优惠券金额*/
+    @TableField(exist = false)
+    private String couponAmount;
+    /**会员姓名*/
+    @TableField(exist = false)
+    private String userName;
+    /**会员手机号*/
+    @TableField(exist = false)
+    private String phone;
+
+}

+ 34 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/enums/BizCouponRecordEnum.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.enums;
+
+import lombok.Getter;
+
+/**
+ * 优惠券记录枚举
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+@Getter
+public enum BizCouponRecordEnum {
+
+    /** 测试 */
+    TEST("TEST");
+
+    private final String value;
+
+    BizCouponRecordEnum(String value) {
+        this.value = value;
+    }
+}

+ 29 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/mapper/BizCouponRecordMapper.java

@@ -0,0 +1,29 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import vip.xiaonuo.biz.modular.couponrecord.entity.BizCouponRecord;
+
+/**
+ * 优惠券记录Mapper接口
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+public interface BizCouponRecordMapper extends BaseMapper<BizCouponRecord> {
+    Page<BizCouponRecord> getPageList(@Param("page") Page<BizCouponRecord> page, @Param("ew") QueryWrapper<BizCouponRecord> ew);
+}

+ 28 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/mapper/mapping/BizCouponRecordMapper.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="vip.xiaonuo.biz.modular.couponrecord.mapper.BizCouponRecordMapper">
+
+    <select id="getPageList" resultType="vip.xiaonuo.biz.modular.couponrecord.entity.BizCouponRecord">
+        select
+            bcr.id,
+            bcr.coupon_no,
+            bcr.time,
+            bcr.coupon_status,
+            bcr.start_time,
+            bcr.end_time,
+            bcr.destroy_user,
+            bcr.destroy_time,
+            bcr.org_id,
+            su.name userName,
+            su.phone,
+            u.name destroyUserName,
+            so.name destroyOrgName,
+            brr.coupon_amount
+        from biz_coupon_record bcr
+        left join biz_recharge_record brr on bcr.recharge_record_id = brr.id
+        left join SYS_USER su on su.id = brr.user_id
+        left join SYS_USER u on u.id = bcr.destroy_user
+        left join SYS_ORG so on so.id = bcr.org_id
+        ${ew.customSqlSegment}
+    </select>
+</mapper>

+ 74 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/param/BizCouponRecordAddParam.java

@@ -0,0 +1,74 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 优惠券记录添加参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+@Getter
+@Setter
+public class BizCouponRecordAddParam {
+
+    /** 优惠券编码 */
+    @Schema(description = "优惠券编码")
+    private String couponNo;
+
+    /** 优惠券生成时间 */
+    @Schema(description = "优惠券生成时间")
+    private Date time;
+
+    /** 充值方案id */
+    @Schema(description = "充值方案id")
+    private String rechargePlanId;
+
+    /** 充值记录表id */
+    @Schema(description = "充值记录表id")
+    private String rechargeRecordId;
+
+    /** 是否核销: 0.否 1.是 */
+    @Schema(description = "是否核销: 0.否 1.是")
+    private Boolean couponStatus;
+
+    /** 有效期开始时间 */
+    @Schema(description = "有效期开始时间")
+    private Date startTime;
+
+    /** 有效期截止时间 */
+    @Schema(description = "有效期截止时间")
+    private Date endTime;
+
+    /** 核销人 */
+    @Schema(description = "核销人")
+    private String destroyUser;
+
+    /** 核销时间 */
+    @Schema(description = "核销时间")
+    private Date destroyTime;
+
+    /** 核销门店 */
+    @Schema(description = "核销门店")
+    private String orgId;
+
+}

+ 79 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/param/BizCouponRecordEditParam.java

@@ -0,0 +1,79 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 优惠券记录编辑参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+@Getter
+@Setter
+public class BizCouponRecordEditParam {
+
+    /** 优惠券记录表id */
+    @Schema(description = "优惠券记录表id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+
+    /** 优惠券编码 */
+    @Schema(description = "优惠券编码")
+    private String couponNo;
+
+    /** 优惠券生成时间 */
+    @Schema(description = "优惠券生成时间")
+    private Date time;
+
+    /** 充值方案id */
+    @Schema(description = "充值方案id")
+    private String rechargePlanId;
+
+    /** 充值记录表id */
+    @Schema(description = "充值记录表id")
+    private String rechargeRecordId;
+
+    /** 是否核销: 0.否 1.是 */
+    @Schema(description = "是否核销: 0.否 1.是")
+    private Boolean couponStatus;
+
+    /** 有效期开始时间 */
+    @Schema(description = "有效期开始时间")
+    private Date startTime;
+
+    /** 有效期截止时间 */
+    @Schema(description = "有效期截止时间")
+    private Date endTime;
+
+    /** 核销人 */
+    @Schema(description = "核销人")
+    private String destroyUser;
+
+    /** 核销时间 */
+    @Schema(description = "核销时间")
+    private Date destroyTime;
+
+    /** 核销门店 */
+    @Schema(description = "核销门店")
+    private String orgId;
+
+}

+ 35 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/param/BizCouponRecordIdParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+
+/**
+ * 优惠券记录Id参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+@Getter
+@Setter
+public class BizCouponRecordIdParam {
+
+    /** 优惠券记录表id */
+    @Schema(description = "优惠券记录表id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+}

+ 59 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/param/BizCouponRecordPageParam.java

@@ -0,0 +1,59 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 优惠券记录查询参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+@Getter
+@Setter
+public class BizCouponRecordPageParam {
+
+    /** 当前页 */
+    @Schema(description = "当前页码")
+    private Integer current;
+
+    /** 每页条数 */
+    @Schema(description = "每页条数")
+    private Integer size;
+
+    /** 排序字段 */
+    @Schema(description = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @Schema(description = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+
+    /** 关键词 */
+    @Schema(description = "关键词")
+    private String searchKey;
+
+    /** 优惠券编码 */
+    @Schema(description = "优惠券编码")
+    private String couponNo;
+
+    /** 是否核销: 0.否 1.是 */
+    @Schema(description = "是否核销: 0.否 1.是")
+    private Boolean couponStatus;
+
+}

+ 90 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/service/BizCouponRecordService.java

@@ -0,0 +1,90 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import vip.xiaonuo.biz.modular.couponrecord.entity.BizCouponRecord;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordAddParam;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordEditParam;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordIdParam;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordPageParam;
+
+import java.util.List;
+
+/**
+ * 优惠券记录Service接口
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+public interface BizCouponRecordService extends IService<BizCouponRecord> {
+
+    /**
+     * 获取优惠券记录分页
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    Page<BizCouponRecord> page(BizCouponRecordPageParam bizCouponRecordPageParam);
+
+    /**
+     * 添加优惠券记录
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    void add(BizCouponRecordAddParam bizCouponRecordAddParam);
+
+    /**
+     * 编辑优惠券记录
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    void edit(BizCouponRecordEditParam bizCouponRecordEditParam);
+
+    /**
+     * 删除优惠券记录
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    void delete(List<BizCouponRecordIdParam> bizCouponRecordIdParamList);
+
+    /**
+     * 获取优惠券记录详情
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     */
+    BizCouponRecord detail(BizCouponRecordIdParam bizCouponRecordIdParam);
+
+    /**
+     * 获取优惠券记录详情
+     *
+     * @author wulei
+     * @date  2025/02/06 17:38
+     **/
+    BizCouponRecord queryEntity(String id);
+
+    /**
+     * 根据优惠券编码查询优惠券信息
+     * @param bizCouponRecordPageParam
+     * @return
+     */
+    BizCouponRecord queryByCode(BizCouponRecordPageParam bizCouponRecordPageParam);
+
+    /**优惠券核销*/
+    void destroy(BizCouponRecordEditParam bizCouponRecordEditParam);
+}

+ 144 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/couponrecord/service/impl/BizCouponRecordServiceImpl.java

@@ -0,0 +1,144 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.couponrecord.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
+import vip.xiaonuo.common.enums.CommonSortOrderEnum;
+import vip.xiaonuo.common.exception.CommonException;
+import vip.xiaonuo.common.page.CommonPageRequest;
+import vip.xiaonuo.biz.modular.couponrecord.entity.BizCouponRecord;
+import vip.xiaonuo.biz.modular.couponrecord.mapper.BizCouponRecordMapper;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordAddParam;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordEditParam;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordIdParam;
+import vip.xiaonuo.biz.modular.couponrecord.param.BizCouponRecordPageParam;
+import vip.xiaonuo.biz.modular.couponrecord.service.BizCouponRecordService;
+import vip.xiaonuo.common.util.CommonCryptogramUtil;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 优惠券记录Service接口实现类
+ *
+ * @author wulei
+ * @date  2025/02/06 17:38
+ **/
+@Service
+public class BizCouponRecordServiceImpl extends ServiceImpl<BizCouponRecordMapper, BizCouponRecord> implements BizCouponRecordService {
+
+    @Override
+    public Page<BizCouponRecord> page(BizCouponRecordPageParam bizCouponRecordPageParam) {
+        QueryWrapper<BizCouponRecord> queryWrapper = new QueryWrapper<BizCouponRecord>().checkSqlInjection();
+        if(ObjectUtil.isNotEmpty(bizCouponRecordPageParam.getCouponNo())) {
+            queryWrapper.like("bcr.coupon_no", bizCouponRecordPageParam.getCouponNo());
+        }
+        if(ObjectUtil.isNotEmpty(bizCouponRecordPageParam.getCouponStatus())) {
+            queryWrapper.eq("bcr.coupon_status", bizCouponRecordPageParam.getCouponStatus());
+        }
+        // 校验数据范围
+        List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
+        if (ObjectUtil.isEmpty(loginUserDataScope)) {
+            queryWrapper.in("brr.user_id", StpLoginUserUtil.getLoginUser().getId());
+        }
+        queryWrapper.orderByDesc("bcr.create_time");
+        Page<BizCouponRecord> pageList = this.getBaseMapper().getPageList(CommonPageRequest.defaultPage(), queryWrapper);
+        for(BizCouponRecord bizCouponRecord : pageList.getRecords()){
+            if(ObjectUtil.isNotEmpty(bizCouponRecord.getPhone())){
+                //电话号码解密
+                bizCouponRecord.setPhone(CommonCryptogramUtil.doSm4CbcDecrypt(bizCouponRecord.getPhone()));
+            }
+        }
+        return pageList;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void add(BizCouponRecordAddParam bizCouponRecordAddParam) {
+        BizCouponRecord bizCouponRecord = BeanUtil.toBean(bizCouponRecordAddParam, BizCouponRecord.class);
+        this.save(bizCouponRecord);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void edit(BizCouponRecordEditParam bizCouponRecordEditParam) {
+        BizCouponRecord bizCouponRecord = this.queryEntity(bizCouponRecordEditParam.getId());
+        BeanUtil.copyProperties(bizCouponRecordEditParam, bizCouponRecord);
+        this.updateById(bizCouponRecord);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void delete(List<BizCouponRecordIdParam> bizCouponRecordIdParamList) {
+        // 执行删除
+        this.removeByIds(CollStreamUtil.toList(bizCouponRecordIdParamList, BizCouponRecordIdParam::getId));
+    }
+
+    @Override
+    public BizCouponRecord detail(BizCouponRecordIdParam bizCouponRecordIdParam) {
+        return this.queryEntity(bizCouponRecordIdParam.getId());
+    }
+
+    @Override
+    public BizCouponRecord queryEntity(String id) {
+        BizCouponRecord bizCouponRecord = this.getById(id);
+        if(ObjectUtil.isEmpty(bizCouponRecord)) {
+            throw new CommonException("优惠券记录不存在,id值为:{}", id);
+        }
+        return bizCouponRecord;
+    }
+
+    @Override
+    public BizCouponRecord queryByCode(BizCouponRecordPageParam bizCouponRecordPageParam) {
+        BizCouponRecord bizCouponRecord = this.getOne(new QueryWrapper<BizCouponRecord>().lambda().
+                eq(BizCouponRecord::getCouponNo, bizCouponRecordPageParam.getCouponNo()).
+                eq(BizCouponRecord::getCouponStatus,"0").
+                last("limit 1"));
+        return bizCouponRecord;
+    }
+
+    /***/
+    @Override
+    public void destroy(BizCouponRecordEditParam bizCouponRecordEditParam) {
+        //获取优惠券信息
+        BizCouponRecord bizCouponRecord = this.queryEntity(bizCouponRecordEditParam.getId());
+        //判断该优惠券是否过期
+        if(ObjectUtil.isNotEmpty(bizCouponRecordEditParam.getEndTime())){
+            if(new Date().getTime() > bizCouponRecord.getEndTime().getTime()){
+                throw new CommonException("优惠券已过期!");
+            }
+        }
+        if(StringUtils.equals(bizCouponRecord.getCouponStatus(),"1")){
+            throw new CommonException("优惠券已经核销过!");
+        }
+        //状态修改成已核销
+        bizCouponRecord.setCouponStatus("1");
+        //核销人
+        bizCouponRecord.setDestroyUser(StpLoginUserUtil.getLoginUser().getId());
+        //核销时间
+        bizCouponRecord.setDestroyTime(new Date());
+        //核销门店
+        bizCouponRecord.setOrgId(StpLoginUserUtil.getLoginUser().getOrgId());
+        this.updateById(bizCouponRecord);
+    }
+}

+ 89 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/controller/BizRebateRecordController.java

@@ -0,0 +1,89 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.common.annotation.CommonLog;
+import vip.xiaonuo.common.pojo.CommonResult;
+import vip.xiaonuo.biz.modular.rebaterecord.entity.BizRebateRecord;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordAddParam;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordEditParam;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordIdParam;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordPageParam;
+import vip.xiaonuo.biz.modular.rebaterecord.service.BizRebateRecordService;
+
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * 返利记录控制器
+ *
+ * @author wulei
+ * @date  2025/02/06 17:39
+ */
+@Tag(name = "返利记录控制器")
+@RestController
+@Validated
+public class BizRebateRecordController {
+
+    @Resource
+    private BizRebateRecordService bizRebateRecordService;
+
+    /**
+     * 获取返利记录分页
+     *
+     * @author wulei
+     * @date  2025/02/06 17:39
+     */
+    @Operation(summary = "获取返利记录分页")
+    @SaCheckPermission("/biz/rebaterecord/page")
+    @GetMapping("/biz/rebaterecord/page")
+    public CommonResult<Page<BizRebateRecord>> page(BizRebateRecordPageParam bizRebateRecordPageParam) {
+        return CommonResult.data(bizRebateRecordService.page(bizRebateRecordPageParam));
+    }
+
+    /**
+     * 获取用户返利记录分页
+     *
+     * @author wulei
+     * @date  2025/02/06 17:39
+     */
+    @Operation(summary = "获取用户返利记录分页")
+    @GetMapping("/biz/rebaterecord/userPage")
+    public CommonResult<Page<BizRebateRecord>> userPage(BizRebateRecordPageParam bizRebateRecordPageParam) {
+        return CommonResult.data(bizRebateRecordService.userPage(bizRebateRecordPageParam));
+    }
+
+
+    /**
+     * 获取返利记录详情
+     *
+     * @author wulei
+     * @date  2025/02/06 17:39
+     */
+    @Operation(summary = "获取返利记录详情")
+    @GetMapping("/biz/rebaterecord/detail")
+    public CommonResult<BizRebateRecord> detail(@Valid BizRebateRecordIdParam bizRebateRecordIdParam) {
+        return CommonResult.data(bizRebateRecordService.detail(bizRebateRecordIdParam));
+    }
+}

+ 84 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/entity/BizRebateRecord.java

@@ -0,0 +1,84 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import vip.xiaonuo.common.pojo.CommonEntity;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 返利记录实体
+ *
+ * @author wulei
+ * @date  2025/02/06 17:39
+ **/
+@Getter
+@Setter
+@TableName("biz_rebate_record")
+public class BizRebateRecord extends CommonEntity {
+
+    /** 代金券记录id */
+    @TableId
+    @Schema(description = "代金券记录id")
+    private String id;
+
+    /** 代金券金额 */
+    @Schema(description = "代金券金额")
+    private BigDecimal rebateAmount;
+
+    /** 充值金额 */
+    @Schema(description = "充值金额")
+    @TableField(exist = false)
+    private BigDecimal rechargeAmount;
+
+    /** 返点比例 */
+    @Schema(description = "返点比例")
+    @TableField(exist = false)
+    private BigDecimal rebateRatio;
+
+    /** 推荐人 */
+    @Schema(description = "推荐人")
+    private String recommendUserId;
+
+    /** 推荐人 */
+    @Schema(description = "推荐人姓名")
+    @TableField(exist = false)
+    private String recommendUserName;
+
+    /** 充值记录id */
+    @Schema(description = "充值记录id")
+    private String rechargeRecordId;
+
+    /** 充值人 */
+    @Schema(description = "充值人")
+    private String rechargeUserId;
+
+    /** 充值人 */
+    @Schema(description = "充值人姓名")
+    @TableField(exist = false)
+    private String rechargeUserName;
+
+    /** 代金券状态: 1. 待生效 2.已生效 */
+    @Schema(description = "代金券状态: 1. 待生效 2.已生效")
+    private String rebateStatus;
+
+    /** 充值时间 */
+    @Schema(description = "充值时间")
+    @TableField(exist = false)
+    private Date rechargeTime;
+}

+ 34 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/enums/BizRebateRecordEnum.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.enums;
+
+import lombok.Getter;
+
+/**
+ * 返利记录枚举
+ *
+ * @author wulei
+ * @date  2025/02/06 17:39
+ **/
+@Getter
+public enum BizRebateRecordEnum {
+
+    /** 测试 */
+    TEST("TEST");
+
+    private final String value;
+
+    BizRebateRecordEnum(String value) {
+        this.value = value;
+    }
+}

+ 30 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/mapper/BizRebateRecordMapper.java

@@ -0,0 +1,30 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import vip.xiaonuo.biz.modular.rebaterecord.entity.BizRebateRecord;
+
+/**
+ * 返利记录Mapper接口
+ *
+ * @author wulei
+ * @date 2025/02/06 17:39
+ **/
+public interface BizRebateRecordMapper extends BaseMapper<BizRebateRecord> {
+
+    Page<BizRebateRecord> page(@Param("page") Page<BizRebateRecord> page, @Param("ew") QueryWrapper<BizRebateRecord> queryWrapper);
+}

+ 26 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/mapper/mapping/BizRebateRecordMapper.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="vip.xiaonuo.biz.modular.rebaterecord.mapper.BizRebateRecordMapper">
+
+    <select id="page" resultType="vip.xiaonuo.biz.modular.rebaterecord.entity.BizRebateRecord">
+        SELECT
+            t.id,
+            t.rebate_amount,
+            t.recharge_record_id,
+            t.recommend_user_id,
+            t.recharge_user_id,
+            DATE_FORMAT(t.create_time, '%Y-%m-%d') AS createTime,
+            t.rebate_status,
+            u1.`NAME` rechargeUserName,
+            u2.`NAME` recommendUserName,
+            r.recharge_amount,
+            r.recharge_time,
+            r.rebate_ratio
+        FROM
+            biz_rebate_record t
+        INNER JOIN biz_recharge_record r ON r.id = t.recharge_record_id
+        LEFT JOIN SYS_USER u1 ON u1.ID = t.recharge_user_id
+        LEFT JOIN SYS_USER u2 ON u2.ID = t.recommend_user_id
+        ${ew.customSqlSegment}
+    </select>
+</mapper>

+ 50 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/param/BizRebateRecordAddParam.java

@@ -0,0 +1,50 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 返利记录添加参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:39
+ **/
+@Getter
+@Setter
+public class BizRebateRecordAddParam {
+
+    /** 代金券金额 */
+    @Schema(description = "代金券金额")
+    private BigDecimal rebateAmount;
+
+    /** 推荐人 */
+    @Schema(description = "推荐人")
+    private String recommendUserId;
+
+    /** 充值人 */
+    @Schema(description = "充值人")
+    private String rechargeUserId;
+
+    /** 代金券状态: 1. 待生效 2.已生效 */
+    @Schema(description = "代金券状态: 1. 待生效 2.已生效")
+    private String rebateStatus;
+
+}

+ 55 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/param/BizRebateRecordEditParam.java

@@ -0,0 +1,55 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 返利记录编辑参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:39
+ **/
+@Getter
+@Setter
+public class BizRebateRecordEditParam {
+
+    /** 代金券记录id */
+    @Schema(description = "代金券记录id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+
+    /** 代金券金额 */
+    @Schema(description = "代金券金额")
+    private BigDecimal rebateAmount;
+
+    /** 推荐人 */
+    @Schema(description = "推荐人")
+    private String recommendUserId;
+
+    /** 充值人 */
+    @Schema(description = "充值人")
+    private String rechargeUserId;
+
+    /** 代金券状态: 1. 待生效 2.已生效 */
+    @Schema(description = "代金券状态: 1. 待生效 2.已生效")
+    private String rebateStatus;
+
+}

+ 35 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/param/BizRebateRecordIdParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+
+/**
+ * 返利记录Id参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:39
+ **/
+@Getter
+@Setter
+public class BizRebateRecordIdParam {
+
+    /** 代金券记录id */
+    @Schema(description = "代金券记录id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+}

+ 61 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/param/BizRebateRecordPageParam.java

@@ -0,0 +1,61 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 返利记录查询参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:39
+ **/
+@Getter
+@Setter
+public class BizRebateRecordPageParam {
+
+    /** 当前页 */
+    @Schema(description = "当前页码")
+    private Integer current;
+
+    /** 每页条数 */
+    @Schema(description = "每页条数")
+    private Integer size;
+
+    /** 排序字段 */
+    @Schema(description = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @Schema(description = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+
+    /** 关键词 */
+    @Schema(description = "关键词")
+    private String searchKey;
+
+    /** 推荐人 */
+    @Schema(description = "推荐人")
+    private String recommendSearchKey;
+
+    /** 充值人 */
+    @Schema(description = "充值人")
+    private String rechargeSearchKey;
+
+    /** 代金券状态: 1. 待生效 2.已生效 */
+    @Schema(description = "代金券状态: 1. 待生效 2.已生效")
+    private String rebateStatus;
+
+}

+ 64 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/service/BizRebateRecordService.java

@@ -0,0 +1,64 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import vip.xiaonuo.biz.modular.rebaterecord.entity.BizRebateRecord;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordAddParam;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordEditParam;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordIdParam;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordPageParam;
+
+import java.util.List;
+
+/**
+ * 返利记录Service接口
+ *
+ * @author wulei
+ * @date 2025/02/06 17:39
+ **/
+public interface BizRebateRecordService extends IService<BizRebateRecord> {
+
+    /**
+     * 获取返利记录分页
+     *
+     * @author wulei
+     * @date 2025/02/06 17:39
+     */
+    Page<BizRebateRecord> page(BizRebateRecordPageParam bizRebateRecordPageParam);
+
+    /**
+     * 获取用户返利记录分页
+     *
+     * @author wulei
+     * @date 2025/02/06 17:39
+     */
+    Page<BizRebateRecord> userPage(BizRebateRecordPageParam bizRebateRecordPageParam);
+
+    /**
+     * 获取返利记录详情
+     *
+     * @author wulei
+     * @date 2025/02/06 17:39
+     */
+    BizRebateRecord detail(BizRebateRecordIdParam bizRebateRecordIdParam);
+
+    /**
+     * 获取返利记录详情
+     *
+     * @author wulei
+     * @date 2025/02/06 17:39
+     **/
+    BizRebateRecord queryEntity(String id);
+}

+ 100 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rebaterecord/service/impl/BizRebateRecordServiceImpl.java

@@ -0,0 +1,100 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rebaterecord.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
+import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;
+import vip.xiaonuo.common.enums.CommonSortOrderEnum;
+import vip.xiaonuo.common.exception.CommonException;
+import vip.xiaonuo.common.page.CommonPageRequest;
+import vip.xiaonuo.biz.modular.rebaterecord.entity.BizRebateRecord;
+import vip.xiaonuo.biz.modular.rebaterecord.mapper.BizRebateRecordMapper;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordAddParam;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordEditParam;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordIdParam;
+import vip.xiaonuo.biz.modular.rebaterecord.param.BizRebateRecordPageParam;
+import vip.xiaonuo.biz.modular.rebaterecord.service.BizRebateRecordService;
+
+import java.util.List;
+
+/**
+ * 返利记录Service接口实现类
+ *
+ * @author wulei
+ * @date 2025/02/06 17:39
+ **/
+@Service
+public class BizRebateRecordServiceImpl extends ServiceImpl<BizRebateRecordMapper, BizRebateRecord> implements BizRebateRecordService {
+
+    @Override
+    public Page<BizRebateRecord> page(BizRebateRecordPageParam bizRebateRecordPageParam) {
+        QueryWrapper<BizRebateRecord> queryWrapper = new QueryWrapper<BizRebateRecord>().checkSqlInjection();
+        if (ObjectUtil.isNotEmpty(bizRebateRecordPageParam.getRecommendSearchKey())) {
+            queryWrapper.and(s -> s.like("u2.NAME", bizRebateRecordPageParam.getRecommendSearchKey())
+                    .or().like("u2.ACCOUNT", bizRebateRecordPageParam.getRecommendSearchKey()));
+        }
+        if (ObjectUtil.isNotEmpty(bizRebateRecordPageParam.getRechargeSearchKey())) {
+            queryWrapper.and(s -> s.like("u1.NAME", bizRebateRecordPageParam.getRechargeSearchKey())
+                    .or().like("u1.ACCOUNT", bizRebateRecordPageParam.getRechargeSearchKey()));
+        }
+        if (ObjectUtil.isNotEmpty(bizRebateRecordPageParam.getRebateStatus())) {
+            queryWrapper.eq("t.rebate_status", bizRebateRecordPageParam.getRebateStatus());
+        }
+        queryWrapper.eq("t.delete_flag", CommonDeleteFlagEnum.NOT_DELETE);
+        queryWrapper.orderByDesc("t.create_time");
+        return baseMapper.page(CommonPageRequest.defaultPage(), queryWrapper);
+    }
+
+    @Override
+    public Page<BizRebateRecord> userPage(BizRebateRecordPageParam bizRebateRecordPageParam) {
+        QueryWrapper<BizRebateRecord> queryWrapper = new QueryWrapper<BizRebateRecord>().checkSqlInjection();
+        if (ObjectUtil.isNotEmpty(bizRebateRecordPageParam.getRecommendSearchKey())) {
+            queryWrapper.and(s -> s.like("u2.NAME", bizRebateRecordPageParam.getRecommendSearchKey())
+                    .or().like("u2.ACCOUNT", bizRebateRecordPageParam.getRecommendSearchKey()));
+        }
+        if (ObjectUtil.isNotEmpty(bizRebateRecordPageParam.getRechargeSearchKey())) {
+            queryWrapper.and(s -> s.like("u1.NAME", bizRebateRecordPageParam.getRechargeSearchKey())
+                    .or().like("u1.ACCOUNT", bizRebateRecordPageParam.getRechargeSearchKey()));
+        }
+        if (ObjectUtil.isNotEmpty(bizRebateRecordPageParam.getRebateStatus())) {
+            queryWrapper.eq("t.rebate_status", bizRebateRecordPageParam.getRebateStatus());
+        }
+        queryWrapper.eq("t.recommend_user_id", StpLoginUserUtil.getLoginUser().getId());
+        queryWrapper.eq("t.delete_flag", CommonDeleteFlagEnum.NOT_DELETE);
+        queryWrapper.orderByDesc("t.create_time");
+        return baseMapper.page(CommonPageRequest.defaultPage(), queryWrapper);
+    }
+
+    @Override
+    public BizRebateRecord detail(BizRebateRecordIdParam bizRebateRecordIdParam) {
+        return this.queryEntity(bizRebateRecordIdParam.getId());
+    }
+
+    @Override
+    public BizRebateRecord queryEntity(String id) {
+        BizRebateRecord bizRebateRecord = this.getById(id);
+        if (ObjectUtil.isEmpty(bizRebateRecord)) {
+            throw new CommonException("返利记录不存在,id值为:{}", id);
+        }
+        return bizRebateRecord;
+    }
+}

+ 17 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargeplanconfig/controller/BizRechargePlanConfigController.java

@@ -13,6 +13,7 @@
 package vip.xiaonuo.biz.modular.rechargeplanconfig.controller;
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.Operation;
@@ -23,6 +24,7 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import vip.xiaonuo.common.annotation.CommonLog;
 import vip.xiaonuo.common.annotation.CommonNoRepeat;
+import vip.xiaonuo.common.pojo.CommonEntity;
 import vip.xiaonuo.common.pojo.CommonResult;
 import vip.xiaonuo.biz.modular.rechargeplanconfig.entity.BizRechargePlanConfig;
 import vip.xiaonuo.biz.modular.rechargeplanconfig.param.BizRechargePlanConfigAddParam;
@@ -156,5 +158,20 @@ public class BizRechargePlanConfigController {
         return CommonResult.ok();
     }
 
+    /**
+     * 获取充值方案配置分页
+     *
+     * @author wulei
+     * @date 2025/02/04 16:32
+     */
+    @Operation(summary = "获取充值方案配置分页")
+    @GetMapping("/biz/rechargeplanconfig/list")
+    public CommonResult<List<BizRechargePlanConfig>> list() {
+        List<BizRechargePlanConfig> planConfigs = bizRechargePlanConfigService.list(new LambdaQueryWrapper<BizRechargePlanConfig>()
+                .eq(BizRechargePlanConfig::getStatus, "ENABLE")
+                .orderByDesc(CommonEntity::getCreateTime));
+        return CommonResult.data(planConfigs);
+    }
+
 
 }

+ 136 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/controller/BizRechargeRecordController.java

@@ -0,0 +1,136 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.common.annotation.CommonLog;
+import vip.xiaonuo.common.annotation.CommonNoRepeat;
+import vip.xiaonuo.common.pojo.CommonResult;
+import vip.xiaonuo.biz.modular.rechargerecord.entity.BizRechargeRecord;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordAddParam;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordIdParam;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordPageParam;
+import vip.xiaonuo.biz.modular.rechargerecord.service.BizRechargeRecordService;
+
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 充值记录表控制器
+ *
+ * @author wulei
+ * @date 2025/02/06 17:41
+ */
+@Tag(name = "充值记录表控制器")
+@RestController
+@Validated
+public class BizRechargeRecordController {
+
+    @Resource
+    private BizRechargeRecordService bizRechargeRecordService;
+
+    /**
+     * 获取充值记录表分页
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    @Operation(summary = "获取充值记录分页")
+    @SaCheckPermission("/biz/rechargerecord/page")
+    @GetMapping("/biz/rechargerecord/page")
+    public CommonResult<Page<BizRechargeRecord>> page(BizRechargeRecordPageParam bizRechargeRecordPageParam) {
+        return CommonResult.data(bizRechargeRecordService.page(bizRechargeRecordPageParam));
+    }
+
+
+    /**
+     * 获取用户充值记录表分页
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    @Operation(summary = "获取用户充值记录分页")
+    @GetMapping("/biz/rechargerecord/userPage")
+    public CommonResult<Page<BizRechargeRecord>> userPage(BizRechargeRecordPageParam bizRechargeRecordPageParam) {
+        return CommonResult.data(bizRechargeRecordService.userPage(bizRechargeRecordPageParam));
+    }
+
+
+    /**
+     * 添加充值记录表
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    @Operation(summary = "添加充值记录表")
+    @CommonLog("添加充值记录表")
+    @PostMapping("/biz/rechargerecord/add")
+    @CommonNoRepeat
+    public CommonResult<Map<String, Object>> add(@RequestBody @Valid BizRechargeRecordAddParam bizRechargeRecordAddParam) {
+        return CommonResult.data(bizRechargeRecordService.add(bizRechargeRecordAddParam));
+    }
+
+//    /**
+//     * 编辑充值记录表
+//     *
+//     * @author wulei
+//     * @date  2025/02/06 17:41
+//     */
+//    @Operation(summary = "编辑充值记录表")
+//    @CommonLog("编辑充值记录表")
+//    @SaCheckPermission("/biz/rechargerecord/edit")
+//    @PostMapping("/biz/rechargerecord/edit")
+//    public CommonResult<String> edit(@RequestBody @Valid BizRechargeRecordEditParam bizRechargeRecordEditParam) {
+//        bizRechargeRecordService.edit(bizRechargeRecordEditParam);
+//        return CommonResult.ok();
+//    }
+
+    /**
+     * 删除充值记录表
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    @Operation(summary = "删除充值记录表")
+    @CommonLog("删除充值记录表")
+    @PostMapping("/biz/rechargerecord/delete")
+    public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
+                                       List<BizRechargeRecordIdParam> bizRechargeRecordIdParamList) {
+        bizRechargeRecordService.delete(bizRechargeRecordIdParamList);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 获取充值记录表详情
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    @Operation(summary = "获取充值记录表详情")
+    @GetMapping("/biz/rechargerecord/detail")
+    public CommonResult<BizRechargeRecord> detail(@Valid BizRechargeRecordIdParam bizRechargeRecordIdParam) {
+        return CommonResult.data(bizRechargeRecordService.detail(bizRechargeRecordIdParam));
+    }
+}

+ 126 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/entity/BizRechargeRecord.java

@@ -0,0 +1,126 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import vip.xiaonuo.common.handler.CommonSm4CbcTypeHandler;
+import vip.xiaonuo.common.pojo.CommonEntity;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 充值记录表实体
+ *
+ * @author wulei
+ * @date 2025/02/06 17:41
+ **/
+@Getter
+@Setter
+@TableName(value = "biz_recharge_record")
+public class BizRechargeRecord extends CommonEntity {
+
+    /** 充值记录表id */
+    @TableId
+    @Schema(description = "充值记录表id")
+    private String id;
+
+    /** 用户id */
+    @Schema(description = "用户id")
+    private String userId;
+
+    /** 充值方案id */
+    @Schema(description = "充值方案id")
+    private String rechargePlanId;
+
+    /** 充值方案中账户需要增加的金额 */
+    @Schema(description = "充值方案中账户需要增加的金额")
+    private BigDecimal planAccountBalance;
+
+    /** 充值方案内容 */
+    @Schema(description = "充值方案内容")
+    private String rechargePlanDescribe;
+
+    /** 充值金额 */
+    @Schema(description = "充值金额")
+    private BigDecimal rechargeAmount;
+
+    /** 充值时间 */
+    @Schema(description = "充值时间")
+    private Date rechargeTime;
+
+    /** 原账户余额 */
+    @Schema(description = "原账户余额")
+    private BigDecimal oldAccountBalance;
+
+    /** 原代金券金额 */
+    @Schema(description = "原代金券金额")
+    private BigDecimal oldVoucherBalance;
+
+    /** 新账户余额 */
+    @Schema(description = "新账户余额")
+    private BigDecimal newAccountBalance;
+
+    /** 新代金券金额 */
+    @Schema(description = "新代金券金额")
+    private BigDecimal newVoucherBalance;
+
+    /** 推荐人的返点比例 */
+    @Schema(description = "推荐人的返点比例")
+    private BigDecimal rebateRatio;
+
+    /** 推荐人具体返点金额 */
+    @Schema(description = "推荐人具体返点金额")
+    private BigDecimal rebateAmount;
+
+    /** 优惠券(蛋糕券)数量 */
+    @Schema(description = "优惠券(蛋糕券)数量")
+    private Integer couponNum;
+
+    /** 优惠券金额 */
+    @Schema(description = "优惠券金额")
+    private BigDecimal couponAmount;
+
+    /** 系统订单号 */
+    @Schema(description = "系统订单号")
+    private String orderNo;
+
+    /** 微信订单编号 */
+    @Schema(description = "微信订单编号")
+    private String wxOrderNo;
+
+    /** 实际支付金额 */
+    @Schema(description = "实际支付金额")
+    private BigDecimal wxPayAmount;
+
+    /** 是否支付 0.未支付 1.已支付 */
+    @Schema(description = "是否支付 0.未支付 1.已支付")
+    private Boolean isPay;
+
+    /** 支付时间 */
+    @Schema(description = "支付时间")
+    private Date payTime;
+
+    /** 用户姓名 */
+    @Schema(description = "用户姓名")
+    @TableField(exist = false)
+    private String name;
+
+    /** 手机号 */
+    @Schema(description = "手机号")
+    @TableField(exist = false)
+    private String phone;
+}

+ 34 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/enums/BizRechargeRecordEnum.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.enums;
+
+import lombok.Getter;
+
+/**
+ * 充值记录表枚举
+ *
+ * @author wulei
+ * @date  2025/02/06 17:41
+ **/
+@Getter
+public enum BizRechargeRecordEnum {
+
+    /** 测试 */
+    TEST("TEST");
+
+    private final String value;
+
+    BizRechargeRecordEnum(String value) {
+        this.value = value;
+    }
+}

+ 38 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/mapper/BizRechargeRecordMapper.java

@@ -0,0 +1,38 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import vip.xiaonuo.biz.modular.rechargerecord.entity.BizRechargeRecord;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordPageParam;
+
+/**
+ * 充值记录表Mapper接口
+ *
+ * @author wulei
+ * @date 2025/02/06 17:41
+ **/
+public interface BizRechargeRecordMapper extends BaseMapper<BizRechargeRecord> {
+    /**
+     * 查询分页
+     * @param page
+     * @param queryWrapper
+     * @return
+     */
+    Page<BizRechargeRecord> pageList(@Param("page") Page page, @Param("ew") QueryWrapper<BizRechargeRecord> queryWrapper);
+
+
+}

+ 30 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/mapper/mapping/BizRechargeRecordMapper.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="vip.xiaonuo.biz.modular.rechargerecord.mapper.BizRechargeRecordMapper">
+
+    <select id="pageList" resultType="vip.xiaonuo.biz.modular.rechargerecord.entity.BizRechargeRecord">
+        SELECT
+            t.id,
+            t.user_id,
+            su.NAME,
+            su.PHONE,
+            t.recharge_plan_id,
+            t.plan_account_balance,
+            t.recharge_amount,
+            t.recharge_time,
+            t.old_account_balance,
+            t.old_voucher_balance,
+            t.new_account_balance,
+            t.new_voucher_balance,
+            t.recharge_plan_describe,
+            t.order_no,
+            t.wx_pay_amount,
+            t.is_pay,
+            t.pay_time
+        FROM biz_recharge_record t
+        LEFT JOIN SYS_USER su ON t.user_id = su.id
+        <where>
+            ${ew.sqlSegment}
+        </where>
+    </select>
+</mapper>

+ 47 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/param/BizRechargeRecordAddParam.java

@@ -0,0 +1,47 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 充值记录表添加参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:41
+ **/
+@Getter
+@Setter
+public class BizRechargeRecordAddParam {
+    /** 微信Code */
+    @Schema(description = "微信Code")
+    @NotBlank(message = "微信Code不能为空")
+    private String code;
+
+    /** 充值方案id */
+    @Schema(description = "充值方案id")
+    private String rechargePlanId;
+
+    /** 充值金额 */
+    @Schema(description = "充值金额")
+    @NotNull(message = "充值金额不能为空")
+    private BigDecimal rechargeAmount;
+
+}

+ 103 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/param/BizRechargeRecordEditParam.java

@@ -0,0 +1,103 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 充值记录表编辑参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:41
+ **/
+@Getter
+@Setter
+public class BizRechargeRecordEditParam {
+
+    /** 充值记录表id */
+    @Schema(description = "充值记录表id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+
+    /** 用户id */
+    @Schema(description = "用户id")
+    private String userId;
+
+    /** 充值方案id */
+    @Schema(description = "充值方案id")
+    private String rechargePlanId;
+
+    /** 充值金额 */
+    @Schema(description = "充值金额")
+    private BigDecimal rechargeAmount;
+
+    /** 充值时间 */
+    @Schema(description = "充值时间")
+    private Date rechargeTime;
+
+    /** 原账户余额 */
+    @Schema(description = "原账户余额")
+    private BigDecimal oldAccountBalance;
+
+    /** 原代金券金额 */
+    @Schema(description = "原代金券金额")
+    private BigDecimal oldVoucherBalance;
+
+    /** 新账户余额 */
+    @Schema(description = "新账户余额")
+    private BigDecimal newAccountBalance;
+
+    /** 新代金券金额 */
+    @Schema(description = "新代金券金额")
+    private BigDecimal newVoucherBalance;
+
+    /** 推荐人的返点比例 */
+    @Schema(description = "推荐人的返点比例")
+    private BigDecimal rebateRatio;
+
+    /** 推荐人具体返点金额 */
+    @Schema(description = "推荐人具体返点金额")
+    private BigDecimal rebateAmount;
+
+    /** 优惠券(蛋糕券)数量 */
+    @Schema(description = "优惠券(蛋糕券)数量")
+    private Integer couponNum;
+
+    /** 优惠券金额 */
+    @Schema(description = "优惠券金额")
+    private BigDecimal couponAmount;
+
+    /** 系统订单号 */
+    @Schema(description = "系统订单号")
+    private String orderNo;
+
+    /** 微信订单编号 */
+    @Schema(description = "微信订单编号")
+    private String wxOrderNo;
+
+    /** 是否支付 0.未支付 1.已支付 */
+    @Schema(description = "是否支付 0.未支付 1.已支付")
+    private Boolean isPay;
+
+    /** 支付时间 */
+    @Schema(description = "支付时间")
+    private Date payTime;
+
+}

+ 35 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/param/BizRechargeRecordIdParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+
+/**
+ * 充值记录表Id参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:41
+ **/
+@Getter
+@Setter
+public class BizRechargeRecordIdParam {
+
+    /** 充值记录表id */
+    @Schema(description = "充值记录表id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+}

+ 63 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/param/BizRechargeRecordPageParam.java

@@ -0,0 +1,63 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 充值记录表查询参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:41
+ **/
+@Getter
+@Setter
+public class BizRechargeRecordPageParam {
+
+    /** 当前页 */
+    @Schema(description = "当前页码")
+    private Integer current;
+
+    /** 每页条数 */
+    @Schema(description = "每页条数")
+    private Integer size;
+
+    /** 排序字段 */
+    @Schema(description = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @Schema(description = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+
+    /** 关键词 */
+    @Schema(description = "关键词")
+    private String searchKey;
+
+    /** 用户id */
+    @Schema(description = "用户id")
+    private String userId;
+
+    /** 充值时间开始 */
+    @Schema(description = "充值时间开始")
+    private String startRechargeTime;
+
+    /** 充值时间结束 */
+    @Schema(description = "充值时间结束")
+    private String endRechargeTime;
+
+}

+ 89 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/service/BizRechargeRecordService.java

@@ -0,0 +1,89 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import vip.xiaonuo.biz.modular.rechargerecord.entity.BizRechargeRecord;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordAddParam;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordEditParam;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordIdParam;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordPageParam;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 充值记录表Service接口
+ *
+ * @author wulei
+ * @date 2025/02/06 17:41
+ **/
+public interface BizRechargeRecordService extends IService<BizRechargeRecord> {
+
+    /**
+     * 获取充值记录表分页
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    Page<BizRechargeRecord> page(BizRechargeRecordPageParam bizRechargeRecordPageParam);
+
+    /**
+     * 获取用户充值记录表分页
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    Page<BizRechargeRecord> userPage(BizRechargeRecordPageParam bizRechargeRecordPageParam);
+
+    /**
+     * 添加充值记录表
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    Map<String, Object> add(BizRechargeRecordAddParam bizRechargeRecordAddParam);
+
+//    /**
+//     * 编辑充值记录表
+//     *
+//     * @author wulei
+//     * @date  2025/02/06 17:41
+//     */
+//    void edit(BizRechargeRecordEditParam bizRechargeRecordEditParam);
+
+    /**
+     * 删除充值记录表
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    void delete(List<BizRechargeRecordIdParam> bizRechargeRecordIdParamList);
+
+    /**
+     * 获取充值记录表详情
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     */
+    BizRechargeRecord detail(BizRechargeRecordIdParam bizRechargeRecordIdParam);
+
+    /**
+     * 获取充值记录表详情
+     *
+     * @author wulei
+     * @date 2025/02/06 17:41
+     **/
+    BizRechargeRecord queryEntity(String id);
+}

+ 258 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/rechargerecord/service/impl/BizRechargeRecordServiceImpl.java

@@ -0,0 +1,258 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.rechargerecord.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.wechat.pay.java.core.RSAAutoCertificateConfig;
+import com.wechat.pay.java.core.exception.HttpException;
+import com.wechat.pay.java.core.exception.MalformedMessageException;
+import com.wechat.pay.java.core.exception.ServiceException;
+import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
+import com.wechat.pay.java.service.payments.jsapi.model.Amount;
+import com.wechat.pay.java.service.payments.jsapi.model.Payer;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
+import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
+import vip.xiaonuo.biz.modular.rechargeplanconfig.entity.BizRechargePlanConfig;
+import vip.xiaonuo.biz.modular.rechargeplanconfig.mapper.BizRechargePlanConfigMapper;
+import vip.xiaonuo.biz.modular.user.entity.BizUser;
+import vip.xiaonuo.biz.modular.user.mapper.BizUserMapper;
+import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;
+import vip.xiaonuo.common.enums.CommonSortOrderEnum;
+import vip.xiaonuo.common.exception.CommonException;
+import vip.xiaonuo.common.page.CommonPageRequest;
+import vip.xiaonuo.biz.modular.rechargerecord.entity.BizRechargeRecord;
+import vip.xiaonuo.biz.modular.rechargerecord.mapper.BizRechargeRecordMapper;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordAddParam;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordEditParam;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordIdParam;
+import vip.xiaonuo.biz.modular.rechargerecord.param.BizRechargeRecordPageParam;
+import vip.xiaonuo.biz.modular.rechargerecord.service.BizRechargeRecordService;
+import vip.xiaonuo.common.pojo.CommonEntity;
+import vip.xiaonuo.common.util.CommonCryptogramUtil;
+import vip.xiaonuo.common.util.CommonWxUtil;
+import vip.xiaonuo.common.wx.WxPayConfig;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 充值记录表Service接口实现类
+ *
+ * @author wulei
+ * @date 2025/02/06 17:41
+ **/
+@Service
+@Slf4j
+public class BizRechargeRecordServiceImpl extends ServiceImpl<BizRechargeRecordMapper, BizRechargeRecord> implements BizRechargeRecordService {
+
+    @Resource
+    private CommonWxUtil commonWxUtil;
+    @Resource
+    private WxPayConfig wxPayConfig;
+    @Resource
+    private RSAAutoCertificateConfig rsaAutoCertificateConfig;
+    @Resource
+    private BizRechargePlanConfigMapper bizRechargePlanConfigMapper;
+    @Resource
+    private BizUserMapper bizUserMapper;
+
+
+    @Override
+    public Page<BizRechargeRecord> page(BizRechargeRecordPageParam bizRechargeRecordPageParam) {
+        QueryWrapper<BizRechargeRecord> queryWrapper = new QueryWrapper<BizRechargeRecord>().checkSqlInjection();
+        if (ObjectUtil.isNotEmpty(bizRechargeRecordPageParam.getSearchKey())) {
+            queryWrapper.and(s -> s.like("u.PHONE", bizRechargeRecordPageParam.getSearchKey())
+                    .or().like("u.NAME", bizRechargeRecordPageParam.getSearchKey()));
+        }
+        if (ObjectUtil.isNotEmpty(bizRechargeRecordPageParam.getStartRechargeTime()) && ObjectUtil.isNotEmpty(bizRechargeRecordPageParam.getEndRechargeTime())) {
+            queryWrapper.between("t.recharge_time", bizRechargeRecordPageParam.getStartRechargeTime(), bizRechargeRecordPageParam.getEndRechargeTime());
+        }
+        queryWrapper.orderByDesc("t.recharge_time");
+        queryWrapper.eq("t.delete_flag", CommonDeleteFlagEnum.NOT_DELETE);
+        Page<BizRechargeRecord> pageList = baseMapper.pageList(CommonPageRequest.defaultPage(), queryWrapper);
+        pageList.getRecords().forEach(bizRechargeRecord -> {
+            if (ObjectUtil.isNotEmpty(bizRechargeRecord.getPhone())) {
+                bizRechargeRecord.setPhone(CommonCryptogramUtil.doSm4CbcDecrypt(bizRechargeRecord.getPhone()));
+            }
+        });
+        return pageList;
+    }
+
+    @Override
+    public Page<BizRechargeRecord> userPage(BizRechargeRecordPageParam bizRechargeRecordPageParam) {
+        QueryWrapper<BizRechargeRecord> queryWrapper = new QueryWrapper<BizRechargeRecord>().checkSqlInjection();
+        if (ObjectUtil.isNotEmpty(bizRechargeRecordPageParam.getStartRechargeTime()) && ObjectUtil.isNotEmpty(bizRechargeRecordPageParam.getEndRechargeTime())) {
+            queryWrapper.lambda().between(BizRechargeRecord::getRechargeTime, bizRechargeRecordPageParam.getStartRechargeTime(), bizRechargeRecordPageParam.getEndRechargeTime());
+        }
+        queryWrapper.lambda().eq(BizRechargeRecord::getUserId, StpLoginUserUtil.getLoginUser().getId());
+        queryWrapper.lambda().orderByDesc(BizRechargeRecord::getRechargeTime);
+        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public synchronized Map<String, Object> add(BizRechargeRecordAddParam bizRechargeRecordAddParam) {
+        Map<String, Object> resultMap = new HashMap<>(5);
+        BizRechargeRecord bizRechargeRecord = new BizRechargeRecord();
+        //充值金额不能为0
+        if (bizRechargeRecordAddParam.getRechargeAmount().compareTo(BigDecimal.ZERO) == 0) {
+            throw new CommonException("充值金额不能为0");
+        }
+        // 查询用户信息
+        BizUser bizUser = bizUserMapper.selectById(StpLoginUserUtil.getLoginUser().getId());
+        if (ObjectUtil.isNull(bizUser)) {
+            throw new CommonException("未查询到该用户信息");
+        }
+        if (ObjectUtil.isNotEmpty(bizRechargeRecordAddParam.getRechargePlanId())) {
+            // 校验充值方案
+            BizRechargePlanConfig bizRechargePlanConfig = bizRechargePlanConfigMapper.selectById(bizRechargeRecordAddParam.getRechargePlanId());
+            if (ObjectUtil.isNull(bizRechargePlanConfig)) {
+                throw new CommonException("未查询到该充值方案");
+            }
+            if (bizRechargeRecordAddParam.getRechargeAmount().compareTo(bizRechargePlanConfig.getRechargeAmount()) < 0) {
+                throw new CommonException("当前充值金额不符合该优惠方案");
+            }
+            //拼接方案内容
+            StringBuffer content = new StringBuffer();
+            content.append("充值方案:").append(bizRechargePlanConfig.getRechargeAmount()).append("元及以上,");
+            if (bizRechargePlanConfig.getCouponAmount().compareTo(BigDecimal.ZERO) != 0) {
+                content.append("赠送蛋糕券 ").append(bizRechargePlanConfig.getCouponAmount())
+                        .append(" x ").append(bizRechargePlanConfig.getCouponNum())
+                        .append("(线下核销领蛋糕)");
+            }
+            content.append(",账户余额到账").append(bizRechargePlanConfig.getAccountBalance())
+                    .append("元,返利").append(bizRechargePlanConfig.getRebateRatio())
+                    .append("%到推荐人代金券");
+            bizRechargeRecord.setRechargePlanDescribe(content.toString());
+            bizRechargeRecord.setRechargePlanId(bizRechargeRecordAddParam.getRechargePlanId());
+            bizRechargeRecord.setPlanAccountBalance(bizRechargePlanConfig.getAccountBalance());
+            bizRechargeRecord.setCouponAmount(bizRechargePlanConfig.getCouponAmount());
+            bizRechargeRecord.setCouponNum(bizRechargePlanConfig.getCouponNum());
+            bizRechargeRecord.setRebateRatio(bizRechargePlanConfig.getRebateRatio());
+
+            //计算返点金额
+            if (ObjectUtil.isNotEmpty(bizUser.getReferralUser())) {
+                BigDecimal rebate = bizRechargePlanConfig.getRebateRatio().divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
+                BigDecimal rebateAmount = bizRechargeRecordAddParam.getRechargeAmount().multiply(rebate);
+                bizRechargeRecord.setRebateAmount(rebateAmount);
+            }
+        }
+        String openId = commonWxUtil.getOpenId(bizRechargeRecordAddParam.getCode(), wxPayConfig.getGetOpenIdUrl(), wxPayConfig.getAppId(), wxPayConfig.getAppSecret());
+        if (ObjectUtil.isEmpty(openId)) {
+            throw new CommonException("openId获取异常,请联系管理员");
+        }
+        log.info("================ 生成基础充值记录内容 =============");
+        bizRechargeRecord.setRechargeAmount(bizRechargeRecordAddParam.getRechargeAmount());
+        // 本系统订单号
+        String orderNumber = "BBT" + DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_MS_PATTERN) + RandomUtil.randomNumbers(3);
+        bizRechargeRecord.setOrderNo(orderNumber);
+        bizRechargeRecord.setRechargeTime(DateUtil.date());
+        bizRechargeRecord.setUserId(bizUser.getId());
+        this.save(bizRechargeRecord);
+        //转换金额为分
+        Integer totalFee = bizRechargeRecordAddParam.getRechargeAmount().multiply(new BigDecimal("100")).intValue();
+
+        //请求微信支付相关配置
+        JsapiServiceExtension service =
+                new JsapiServiceExtension.Builder()
+                        .config(rsaAutoCertificateConfig)
+                        .signType("RSA") // 不填默认为RSA
+                        .build();
+        PrepayWithRequestPaymentResponse response;
+        try {
+            PrepayRequest request = new PrepayRequest();
+            request.setAppid(wxPayConfig.getAppId());
+            request.setMchid(wxPayConfig.getMerchantId());
+            request.setDescription("爸爸糖手工吐司会员账户充值");
+            request.setOutTradeNo(orderNumber);
+            request.setNotifyUrl(wxPayConfig.getPayNotifyUrl());
+            Amount amount = new Amount();
+            amount.setTotal(totalFee);
+            request.setAmount(amount);
+            Payer payer = new Payer();
+            payer.setOpenid(openId);
+            request.setPayer(payer);
+            log.info("请求生成订单,请求参数:{}", JSONObject.toJSONString(request));
+            // 调用预下单接口
+            response = service.prepayWithRequestPayment(request);
+            resultMap.put("package", response.getPackageVal());
+            resultMap.put("nonceStr", response.getNonceStr());
+            resultMap.put("signType", response.getSignType());
+            resultMap.put("timeStamp", response.getTimeStamp());
+            resultMap.put("paySign", response.getPaySign());
+            resultMap.put("dataId", bizRechargeRecord.getId());
+            log.info("订单【{}】生成订单成功,返回信息:{}", orderNumber, response);
+        } catch (HttpException e) {
+            // 发送HTTP请求失败
+            log.error("微信下单发送HTTP请求失败,错误信息:{}", e.getMessage());
+            throw new CommonException("微信下单失败,请联系管理员");
+        } catch (ServiceException e) {
+            // 服务返回状态小于200或大于等于300,例如500
+            log.error("微信下单服务状态错误,错误信息:{}", e.getErrorMessage());
+            throw new CommonException("微信下单失败,请联系管理员");
+        } catch (MalformedMessageException e) {
+            // 服务返回成功,返回体类型不合法,或者解析返回体失败
+            log.error("服务返回成功,返回体类型不合法,或者解析返回体失败,错误信息:{}", e.getMessage());
+            throw new CommonException("微信下单失败,请联系管理员");
+        }
+        //3. 返回微信订单参数,方便小程序唤起支付
+        return resultMap;
+    }
+
+//    @Transactional(rollbackFor = Exception.class)
+//    @Override
+//    public void edit(BizRechargeRecordEditParam bizRechargeRecordEditParam) {
+//        BizRechargeRecord bizRechargeRecord = this.queryEntity(bizRechargeRecordEditParam.getId());
+//        BeanUtil.copyProperties(bizRechargeRecordEditParam, bizRechargeRecord);
+//        this.updateById(bizRechargeRecord);
+//    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void delete(List<BizRechargeRecordIdParam> bizRechargeRecordIdParamList) {
+        // 执行删除
+        this.removeByIds(CollStreamUtil.toList(bizRechargeRecordIdParamList, BizRechargeRecordIdParam::getId));
+    }
+
+    @Override
+    public BizRechargeRecord detail(BizRechargeRecordIdParam bizRechargeRecordIdParam) {
+        return this.queryEntity(bizRechargeRecordIdParam.getId());
+    }
+
+    @Override
+    public BizRechargeRecord queryEntity(String id) {
+        BizRechargeRecord bizRechargeRecord = this.getById(id);
+        if (ObjectUtil.isEmpty(bizRechargeRecord)) {
+            throw new CommonException("充值记录表不存在,id值为:{}", id);
+        }
+        return bizRechargeRecord;
+    }
+}

+ 91 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/controller/BizRecommendRecordController.java

@@ -0,0 +1,91 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.common.annotation.CommonLog;
+import vip.xiaonuo.common.pojo.CommonResult;
+import vip.xiaonuo.biz.modular.recommendrecord.entity.BizRecommendRecord;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordAddParam;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordEditParam;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordIdParam;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordPageParam;
+import vip.xiaonuo.biz.modular.recommendrecord.service.BizRecommendRecordService;
+
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * 推荐记录表控制器
+ *
+ * @author wulei
+ * @date  2025/02/06 17:42
+ */
+@Tag(name = "推荐记录表控制器")
+@RestController
+@Validated
+public class BizRecommendRecordController {
+
+    @Resource
+    private BizRecommendRecordService bizRecommendRecordService;
+
+    /**
+     * 获取推荐记录表分页
+     *
+     * @author wulei
+     * @date  2025/02/06 17:42
+     */
+    @Operation(summary = "获取推荐记录表分页")
+    @SaCheckPermission("/biz/recommendrecord/page")
+    @GetMapping("/biz/recommendrecord/page")
+    public CommonResult<Page<BizRecommendRecord>> page(BizRecommendRecordPageParam bizRecommendRecordPageParam) {
+        return CommonResult.data(bizRecommendRecordService.page(bizRecommendRecordPageParam));
+    }
+
+    /**
+     * 获取用户推荐记录分页
+     *
+     * @author wulei
+     * @date  2025/02/06 17:42
+     */
+    @Operation(summary = "获取用户推荐记录分页")
+    @GetMapping("/biz/recommendrecord/userPage")
+    public CommonResult<Page<BizRecommendRecord>> userPage(BizRecommendRecordPageParam bizRecommendRecordPageParam) {
+        return CommonResult.data(bizRecommendRecordService.userPage(bizRecommendRecordPageParam));
+    }
+
+
+
+
+    /**
+     * 获取推荐记录表详情
+     *
+     * @author wulei
+     * @date  2025/02/06 17:42
+     */
+    @Operation(summary = "获取推荐记录表详情")
+    @GetMapping("/biz/recommendrecord/detail")
+    public CommonResult<BizRecommendRecord> detail(@Valid BizRecommendRecordIdParam bizRecommendRecordIdParam) {
+        return CommonResult.data(bizRecommendRecordService.detail(bizRecommendRecordIdParam));
+    }
+}

+ 58 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/entity/BizRecommendRecord.java

@@ -0,0 +1,58 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import vip.xiaonuo.common.pojo.CommonEntity;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 推荐记录表实体
+ *
+ * @author wulei
+ * @date  2025/02/06 17:42
+ **/
+@Getter
+@Setter
+@TableName("biz_recommend_record")
+public class BizRecommendRecord extends CommonEntity {
+
+    /** 推荐记录id */
+    @TableId
+    @Schema(description = "推荐记录id")
+    private String id;
+
+    /** 推荐人用户id */
+    @Schema(description = "推荐人用户id")
+    private String recommendUserId;
+
+    /** 推荐人 */
+    @Schema(description = "推荐人")
+    @TableField(exist = false)
+    private String recommendUserName;
+
+
+    /** 被推荐人用户id */
+    @Schema(description = "被推荐人用户id")
+    private String acceptUserId;
+
+    /** 被推荐人 */
+    @Schema(description = "被推荐人")
+    @TableField(exist = false)
+    private String acceptUserName;
+}

+ 34 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/enums/BizRecommendRecordEnum.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.enums;
+
+import lombok.Getter;
+
+/**
+ * 推荐记录表枚举
+ *
+ * @author wulei
+ * @date  2025/02/06 17:42
+ **/
+@Getter
+public enum BizRecommendRecordEnum {
+
+    /** 测试 */
+    TEST("TEST");
+
+    private final String value;
+
+    BizRecommendRecordEnum(String value) {
+        this.value = value;
+    }
+}

+ 30 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/mapper/BizRecommendRecordMapper.java

@@ -0,0 +1,30 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import vip.xiaonuo.biz.modular.recommendrecord.entity.BizRecommendRecord;
+
+/**
+ * 推荐记录表Mapper接口
+ *
+ * @author wulei
+ * @date 2025/02/06 17:42
+ **/
+public interface BizRecommendRecordMapper extends BaseMapper<BizRecommendRecord> {
+
+    Page<BizRecommendRecord> page(@Param("page") Page<BizRecommendRecord> page, @Param("ew") QueryWrapper<BizRecommendRecord> queryWrapper);
+}

+ 19 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/mapper/mapping/BizRecommendRecordMapper.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="vip.xiaonuo.biz.modular.recommendrecord.mapper.BizRecommendRecordMapper">
+
+    <select id="page" resultType="vip.xiaonuo.biz.modular.recommendrecord.entity.BizRecommendRecord">
+        SELECT
+            t.id,
+            t.recommend_user_id,
+            t.accept_user_id,
+            t.create_time,
+            u1.`NAME` acceptUserName,
+            u2.`NAME` recommendUserName
+        FROM
+            biz_recommend_record t
+        LEFT JOIN SYS_USER u1 ON u1.ID = t.accept_user_id
+        LEFT JOIN SYS_USER u2 ON u2.ID = t.recommend_user_id
+        ${ew.customSqlSegment}
+    </select>
+</mapper>

+ 42 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/param/BizRecommendRecordAddParam.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 推荐记录表添加参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:42
+ **/
+@Getter
+@Setter
+public class BizRecommendRecordAddParam {
+
+    /** 推荐人用户id */
+    @Schema(description = "推荐人用户id")
+    private String recommendUserId;
+
+    /** 被推荐人用户id */
+    @Schema(description = "被推荐人用户id")
+    private String acceptUserId;
+
+}

+ 47 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/param/BizRecommendRecordEditParam.java

@@ -0,0 +1,47 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 推荐记录表编辑参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:42
+ **/
+@Getter
+@Setter
+public class BizRecommendRecordEditParam {
+
+    /** 推荐记录id */
+    @Schema(description = "推荐记录id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+
+    /** 推荐人用户id */
+    @Schema(description = "推荐人用户id")
+    private String recommendUserId;
+
+    /** 被推荐人用户id */
+    @Schema(description = "被推荐人用户id")
+    private String acceptUserId;
+
+}

+ 35 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/param/BizRecommendRecordIdParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+
+/**
+ * 推荐记录表Id参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:42
+ **/
+@Getter
+@Setter
+public class BizRecommendRecordIdParam {
+
+    /** 推荐记录id */
+    @Schema(description = "推荐记录id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+}

+ 51 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/param/BizRecommendRecordPageParam.java

@@ -0,0 +1,51 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 推荐记录表查询参数
+ *
+ * @author wulei
+ * @date  2025/02/06 17:42
+ **/
+@Getter
+@Setter
+public class BizRecommendRecordPageParam {
+
+    /** 当前页 */
+    @Schema(description = "当前页码")
+    private Integer current;
+
+    /** 每页条数 */
+    @Schema(description = "每页条数")
+    private Integer size;
+
+    /** 排序字段 */
+    @Schema(description = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @Schema(description = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+
+    /** 推荐人关键词 */
+    @Schema(description = "关键词")
+    private String searchKey;
+
+}

+ 64 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/service/BizRecommendRecordService.java

@@ -0,0 +1,64 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import vip.xiaonuo.biz.modular.recommendrecord.entity.BizRecommendRecord;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordAddParam;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordEditParam;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordIdParam;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordPageParam;
+
+import java.util.List;
+
+/**
+ * 推荐记录表Service接口
+ *
+ * @author wulei
+ * @date 2025/02/06 17:42
+ **/
+public interface BizRecommendRecordService extends IService<BizRecommendRecord> {
+
+    /**
+     * 获取推荐记录表分页
+     *
+     * @author wulei
+     * @date 2025/02/06 17:42
+     */
+    Page<BizRecommendRecord> page(BizRecommendRecordPageParam bizRecommendRecordPageParam);
+
+    /**
+     * 获取用户推荐记录表分页
+     *
+     * @author wulei
+     * @date 2025/02/06 17:42
+     */
+    Page<BizRecommendRecord> userPage(BizRecommendRecordPageParam bizRecommendRecordPageParam);
+
+    /**
+     * 获取推荐记录表详情
+     *
+     * @author wulei
+     * @date 2025/02/06 17:42
+     */
+    BizRecommendRecord detail(BizRecommendRecordIdParam bizRecommendRecordIdParam);
+
+    /**
+     * 获取推荐记录表详情
+     *
+     * @author wulei
+     * @date 2025/02/06 17:42
+     **/
+    BizRecommendRecord queryEntity(String id);
+}

+ 86 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/recommendrecord/service/impl/BizRecommendRecordServiceImpl.java

@@ -0,0 +1,86 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.recommendrecord.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
+import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;
+import vip.xiaonuo.common.enums.CommonSortOrderEnum;
+import vip.xiaonuo.common.exception.CommonException;
+import vip.xiaonuo.common.page.CommonPageRequest;
+import vip.xiaonuo.biz.modular.recommendrecord.entity.BizRecommendRecord;
+import vip.xiaonuo.biz.modular.recommendrecord.mapper.BizRecommendRecordMapper;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordAddParam;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordEditParam;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordIdParam;
+import vip.xiaonuo.biz.modular.recommendrecord.param.BizRecommendRecordPageParam;
+import vip.xiaonuo.biz.modular.recommendrecord.service.BizRecommendRecordService;
+
+import java.util.List;
+
+/**
+ * 推荐记录表Service接口实现类
+ *
+ * @author wulei
+ * @date 2025/02/06 17:42
+ **/
+@Service
+public class BizRecommendRecordServiceImpl extends ServiceImpl<BizRecommendRecordMapper, BizRecommendRecord> implements BizRecommendRecordService {
+
+    @Override
+    public Page<BizRecommendRecord> page(BizRecommendRecordPageParam bizRecommendRecordPageParam) {
+        QueryWrapper<BizRecommendRecord> queryWrapper = new QueryWrapper<BizRecommendRecord>().checkSqlInjection();
+        if (ObjectUtil.isNotEmpty(bizRecommendRecordPageParam.getSearchKey())) {
+            queryWrapper.and(s -> s.like("u2.NAME", bizRecommendRecordPageParam.getSearchKey())
+                    .or().like("u2.ACCOUNT", bizRecommendRecordPageParam.getSearchKey()));
+        }
+        queryWrapper.eq("t.delete_flag", CommonDeleteFlagEnum.NOT_DELETE);
+        queryWrapper.orderByAsc("t.create_time");
+        return baseMapper.page(CommonPageRequest.defaultPage(), queryWrapper);
+    }
+
+    @Override
+    public Page<BizRecommendRecord> userPage(BizRecommendRecordPageParam bizRecommendRecordPageParam) {
+        QueryWrapper<BizRecommendRecord> queryWrapper = new QueryWrapper<BizRecommendRecord>().checkSqlInjection();
+        if (ObjectUtil.isNotEmpty(bizRecommendRecordPageParam.getSearchKey())) {
+            queryWrapper.and(s -> s.like("u1.NAME", bizRecommendRecordPageParam.getSearchKey())
+                    .or().like("u1.ACCOUNT", bizRecommendRecordPageParam.getSearchKey()));
+        }
+        queryWrapper.eq("t.recommend_user_id", StpLoginUserUtil.getLoginUser().getId());
+        queryWrapper.eq("t.delete_flag", CommonDeleteFlagEnum.NOT_DELETE);
+        queryWrapper.orderByAsc("t.create_time");
+        return baseMapper.page(CommonPageRequest.defaultPage(), queryWrapper);
+    }
+
+    @Override
+    public BizRecommendRecord detail(BizRecommendRecordIdParam bizRecommendRecordIdParam) {
+        return this.queryEntity(bizRecommendRecordIdParam.getId());
+    }
+
+    @Override
+    public BizRecommendRecord queryEntity(String id) {
+        BizRecommendRecord bizRecommendRecord = this.getById(id);
+        if (ObjectUtil.isEmpty(bizRecommendRecord)) {
+            throw new CommonException("推荐记录表不存在,id值为:{}", id);
+        }
+        return bizRecommendRecord;
+    }
+}

+ 96 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/task/rebateEffectTask.java

@@ -0,0 +1,96 @@
+package vip.xiaonuo.biz.modular.task;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.DefaultTransactionDefinition;
+import vip.xiaonuo.biz.core.enums.FundChangeTypeEnum;
+import vip.xiaonuo.biz.modular.couponrecord.service.BizCouponRecordService;
+import vip.xiaonuo.biz.modular.rebaterecord.entity.BizRebateRecord;
+import vip.xiaonuo.biz.modular.rebaterecord.service.BizRebateRecordService;
+import vip.xiaonuo.biz.modular.user.entity.BizUser;
+import vip.xiaonuo.biz.modular.user.mapper.BizUserMapper;
+import vip.xiaonuo.biz.modular.userfundchangerecord.entity.BizUserFundChangeRecord;
+import vip.xiaonuo.biz.modular.userfundchangerecord.service.BizUserFundChangeRecordService;
+import vip.xiaonuo.common.timer.CommonTimerTaskRunner;
+import vip.xiaonuo.dev.api.DevConfigApi;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * @author wulei
+ * @date 2025/2/8
+ * @Version 1.0
+ * @Description 代金券生效定时任务
+ */
+@Slf4j
+@Component
+public class rebateEffectTask implements CommonTimerTaskRunner {
+
+    @Resource
+    private DevConfigApi devConfigApi;
+
+    @Resource
+    private BizRebateRecordService bizRebateRecordService;
+    @Resource
+    private BizUserMapper bizUserMapper;
+    @Resource
+    private BizUserFundChangeRecordService bizUserFundChangeRecordService;
+    // 代金券生效期限配置
+    private static final String REBATE_EFFECTIVE_DATE = "rebateEffectiveDate";
+    @Resource
+    private PlatformTransactionManager transactionManager;
+
+    @Override
+    public void action(String extJson) {
+        log.info("代金券生效定时任务正在执行==================");
+        TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
+        try {
+            // 获取代金券生效期限配置
+            String date = devConfigApi.getValueByKey(REBATE_EFFECTIVE_DATE);
+            DateTime daysAgo = DateUtil.offsetDay(DateUtil.date(), -Integer.parseInt(date));
+            log.info("代金券生效时间:{}", daysAgo);
+            // 查询未生效且代金券创建时间距离当前生效期限的代金券
+            List<BizRebateRecord> list = bizRebateRecordService.list(new LambdaQueryWrapper<BizRebateRecord>()
+                    .eq(BizRebateRecord::getRebateStatus, "1")
+                    .le(BizRebateRecord::getCreateTime, daysAgo));
+            for (BizRebateRecord bizRebateRecord : list) {
+                bizRebateRecord.setRebateStatus("2");
+                bizRebateRecordService.updateById(bizRebateRecord);
+                // 更新用于代金券余额数据
+                BizUser bizUser = bizUserMapper.selectById(bizRebateRecord.getRecommendUserId());
+                if (ObjectUtil.isNotNull(bizUser)) {
+                    BigDecimal oldVoucherBalance = bizUser.getVoucherBalance();
+                    BigDecimal newVoucherBalance = oldVoucherBalance.add(bizRebateRecord.getRebateAmount());
+                    bizUser.setVoucherBalance(newVoucherBalance);
+                    bizUserMapper.updateById(bizUser);
+                    // 记录用户账户资金变动记录
+                    BizUserFundChangeRecord bizUserFundChangeRecord = new BizUserFundChangeRecord();
+                    bizUserFundChangeRecord.setChangeType(FundChangeTypeEnum.VOUCHER_EFFECT.getValue());
+                    bizUserFundChangeRecord.setUserId(bizRebateRecord.getRecommendUserId());
+                    bizUserFundChangeRecord.setOldAccountBalance(bizUser.getAccountBalance());
+                    bizUserFundChangeRecord.setNewAccountBalance(bizUser.getAccountBalance());
+                    bizUserFundChangeRecord.setOldVoucherBalance(oldVoucherBalance);
+                    bizUserFundChangeRecord.setNewVoucherBalance(newVoucherBalance);
+                    bizUserFundChangeRecordService.save(bizUserFundChangeRecord);
+                }
+            }
+            //手动提交事务
+            transactionManager.commit(transactionStatus);
+            log.info("代金券生效定时任务执行完毕=================");
+        } catch (Exception e) {
+            e.printStackTrace();
+            transactionManager.rollback(transactionStatus);
+            log.error("代金券生效定时任务执行异常=================");
+        }
+    }
+}

+ 6 - 2
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/controller/BizUserController.java

@@ -316,9 +316,9 @@ public class BizUserController {
      * @return
      */
     @Operation(summary = "小程序注册")
-    @GetMapping("/auth/c/wxRegister")
+    @PostMapping("/auth/c/wxRegister")
     @CommonNoRepeat
-    public CommonResult<String> wxRegister(WxUserRegisterParam wxUserRegisterParam) {
+    public CommonResult<String> wxRegister(@RequestBody @Valid WxUserRegisterParam wxUserRegisterParam) {
         bizUserService.wxRegister(wxUserRegisterParam);
         return CommonResult.ok();
     }
@@ -337,4 +337,8 @@ public class BizUserController {
     }
 
 
+
+
+
+
 }

+ 4 - 2
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/mapper/mapping/BizUserMapper.xml

@@ -13,8 +13,10 @@
             USER_TYPE,
             ACCOUNT_BALANCE,
             VOUCHER_BALANCE,
-            CREATE_TIME
+            CREATE_TIME,
+            USER_STATUS,
+            PHONE
         FROM SYS_USER
         ${ew.customSqlSegment}
     </select>
-</mapper>
+</mapper>

+ 1 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/param/WxUserRegisterParam.java

@@ -32,6 +32,7 @@ public class WxUserRegisterParam {
     private String name;
 
     @Schema(description = "短信验证码")
+    @NotBlank(message = "短信验证码不能为空")
     private String messageCode;
 
     @Schema(description = "推荐人编码")

+ 4 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/result/BizMemberUserResult.java

@@ -83,4 +83,8 @@ public class BizMemberUserResult extends CommonEntity {
     @Schema(description = "用户状态")
     private String userStatus;
 
+    /** 手机号 */
+    @Schema(description = "手机号")
+    private String phone;
+
 }

+ 36 - 11
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/user/service/impl/BizUserServiceImpl.java

@@ -52,6 +52,7 @@ import jakarta.annotation.Resource;
 import jakarta.servlet.http.HttpServletResponse;
 import org.apache.poi.ss.usermodel.*;
 import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
@@ -61,6 +62,8 @@ import vip.xiaonuo.biz.modular.org.entity.BizOrg;
 import vip.xiaonuo.biz.modular.org.service.BizOrgService;
 import vip.xiaonuo.biz.modular.position.entity.BizPosition;
 import vip.xiaonuo.biz.modular.position.service.BizPositionService;
+import vip.xiaonuo.biz.modular.recommendrecord.entity.BizRecommendRecord;
+import vip.xiaonuo.biz.modular.recommendrecord.mapper.BizRecommendRecordMapper;
 import vip.xiaonuo.biz.modular.user.entity.BizUser;
 import vip.xiaonuo.biz.modular.user.enums.BizRoleCategoryEnum;
 import vip.xiaonuo.biz.modular.user.enums.BizUserStatusEnum;
@@ -127,6 +130,10 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
     private CommonCacheOperator commonCacheOperator;
     @Resource
     private DevSmsApi devSmsApi;
+    @Value("${aliyun.templateCode}")
+    private String templateCode;
+    @Resource
+    private BizRecommendRecordMapper bizRecommendRecordMapper;
 
 
     @Override
@@ -176,7 +183,13 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
         queryWrapper.lambda().eq(BizUser::getUserType, 3);
         queryWrapper.lambda().eq(CommonEntity::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE);
         queryWrapper.lambda().orderByDesc(CommonEntity::getCreateTime);
-        return baseMapper.memberPage(CommonPageRequest.defaultPage(), queryWrapper);
+        Page<BizMemberUserResult> bizMemberUserResultPage = baseMapper.memberPage(CommonPageRequest.defaultPage(), queryWrapper);
+        for (BizMemberUserResult bizMemberUserResult : bizMemberUserResultPage.getRecords()) {
+            if (ObjectUtil.isNotEmpty(bizMemberUserResult.getPhone())) {
+                bizMemberUserResult.setPhone(CommonCryptogramUtil.doSm4CbcDecrypt(bizMemberUserResult.getPhone()));
+            }
+        }
+        return bizMemberUserResultPage;
     }
 
     @Transactional(rollbackFor = Exception.class)
@@ -772,15 +785,13 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
     @Transactional(rollbackFor = Exception.class)
     public void wxRegister(WxUserRegisterParam wxUserRegisterParam) {
         // 校验短信验证码
-        String messageCode = commonCacheOperator.get(wxUserRegisterParam.getPhone()) + "";
+        Object messageCode = commonCacheOperator.get(wxUserRegisterParam.getPhone());
         if (ObjectUtil.isEmpty(messageCode)) {
-            throw new CommonException("验证码不存在");
+            throw new CommonException("短信验证码已过期");
         }
         if (ObjectUtil.notEqual(messageCode, wxUserRegisterParam.getMessageCode())) {
-            throw new CommonException("验证码错误");
+            throw new CommonException("短信验证码错误");
         }
-//        //校验通过删除缓存
-//        commonCacheOperator.remove(wxUserRegisterParam.getPhone());
 
         String roleId = "";
         // 保存用户信息
@@ -807,16 +818,18 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
             roleId = "1886674709466906625";
         }
         // 校验推荐人
+        String referralUserId = null;
         if (ObjectUtil.isNotEmpty(wxUserRegisterParam.getReferralCode())) {
             BizUser referralUser = baseMapper.selectOne(new LambdaQueryWrapper<BizUser>()
                     .eq(BizUser::getUserReferralCode, wxUserRegisterParam.getReferralCode())
                     .last("limit 1"));
             if (ObjectUtil.isNull(referralUser)) {
-                throw new CommonException("推荐人不存在");
+                throw new CommonException("未查询到该编码的推荐人");
             }
+            referralUserId = referralUser.getId();
         }
         // 校验openId或者手机号是否存在
-        if (ObjectUtil.isNull(baseMapper.selectOne(new LambdaQueryWrapper<BizUser>()
+        if (ObjectUtil.isNotNull(baseMapper.selectOne(new LambdaQueryWrapper<BizUser>()
                 .eq(BizUser::getOpenId, wxUserRegisterParam.getOpenId())
                 .or()
                 .eq(BizUser::getAccount, wxUserRegisterParam.getPhone())
@@ -824,28 +837,40 @@ public class BizUserServiceImpl extends ServiceImpl<BizUserMapper, BizUser> impl
             throw new CommonException("该手机号已注册,请勿重复注册");
         }
         bizUser.setAccount(wxUserRegisterParam.getPhone());
-        bizUser.setPhone(CommonCryptogramUtil.doSm4CbcEncrypt(wxUserRegisterParam.getPhone()));
+        bizUser.setPhone(wxUserRegisterParam.getPhone());
+        bizUser.setAvatar(CommonAvatarUtil.generateImg(bizUser.getName()));
         // 设置默认密码
         bizUser.setPassword(CommonCryptogramUtil.doHashValue(devConfigApi.getValueByKey(SNOWY_SYS_DEFAULT_PASSWORD_KEY)));
         // 设置状态
         bizUser.setUserStatus("ENABLE");
+        bizUser.setOpenId(wxUserRegisterParam.getOpenId());
         //生成推荐码
         bizUser.setUserReferralCode(DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN) + RandomUtil.randomNumbers(4));
         bizUser.setName(wxUserRegisterParam.getName());
         this.save(bizUser);
         sysRoleApi.grantUserRole(bizUser.getId(), roleId);
+        //保存推荐人关系
+        if (ObjectUtil.isNotEmpty(wxUserRegisterParam.getReferralCode())) {
+            BizRecommendRecord bizRecommendRecord = new BizRecommendRecord();
+            bizRecommendRecord.setRecommendUserId(referralUserId);
+            bizRecommendRecord.setAcceptUserId(bizUser.getId());
+            bizRecommendRecordMapper.insert(bizRecommendRecord);
+        }
+        //校验通过删除缓存
+        commonCacheOperator.remove(wxUserRegisterParam.getPhone());
     }
 
     @Override
     public void smsSend(SmsSendParam smsSendParam) {
         // 查询缓存是否存在
-        String messageCode = commonCacheOperator.get(smsSendParam.getPhone()) + "";
+        Object messageCode = commonCacheOperator.get(smsSendParam.getPhone());
         if (ObjectUtil.isNotEmpty(messageCode)) {
             throw new CommonException("请勿重复发送");
         }
         String code = RandomUtil.randomNumbers(5);
         //发送短信
-        devSmsApi.sendSmsAliyun(smsSendParam.getPhone(), null, "SMS_465365543", "{\"code\":\"" + code + "\"}");
+        devSmsApi.sendSmsAliyun(smsSendParam.getPhone(), null, templateCode, "{\"code\":\"" + code + "\"}");
+        //保存5分钟
         commonCacheOperator.put(smsSendParam.getPhone(), code, 300);
     }
 }

+ 75 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/controller/BizUserFundChangeRecordController.java

@@ -0,0 +1,75 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.common.annotation.CommonLog;
+import vip.xiaonuo.common.pojo.CommonResult;
+import vip.xiaonuo.biz.modular.userfundchangerecord.entity.BizUserFundChangeRecord;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordAddParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordEditParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordIdParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordPageParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.service.BizUserFundChangeRecordService;
+
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * 用户账户资金变动记录控制器
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ */
+@Tag(name = "用户账户资金变动记录控制器")
+@RestController
+@Validated
+public class BizUserFundChangeRecordController {
+
+    @Resource
+    private BizUserFundChangeRecordService bizUserFundChangeRecordService;
+
+    /**
+     * 获取用户账户资金变动记录分页
+     *
+     * @author wulei
+     * @date  2025/02/07 11:26
+     */
+    @Operation(summary = "获取用户账户资金变动记录分页")
+    @GetMapping("/biz/userfundchangerecord/page")
+    public CommonResult<Page<BizUserFundChangeRecord>> page(BizUserFundChangeRecordPageParam bizUserFundChangeRecordPageParam) {
+        return CommonResult.data(bizUserFundChangeRecordService.page(bizUserFundChangeRecordPageParam));
+    }
+
+    /**
+     * 获取用户账户资金变动记录详情
+     *
+     * @author wulei
+     * @date  2025/02/07 11:26
+     */
+    @Operation(summary = "获取用户账户资金变动记录详情")
+    @GetMapping("/biz/userfundchangerecord/detail")
+    public CommonResult<BizUserFundChangeRecord> detail(@Valid BizUserFundChangeRecordIdParam bizUserFundChangeRecordIdParam) {
+        return CommonResult.data(bizUserFundChangeRecordService.detail(bizUserFundChangeRecordIdParam));
+    }
+}

+ 65 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/entity/BizUserFundChangeRecord.java

@@ -0,0 +1,65 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import vip.xiaonuo.common.pojo.CommonEntity;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 用户账户资金变动记录实体
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ **/
+@Getter
+@Setter
+@TableName("biz_user_fund_change_record")
+public class BizUserFundChangeRecord extends CommonEntity {
+
+    /** 账户金额变动记录id */
+    @TableId
+    @Schema(description = "账户金额变动记录id")
+    private String id;
+
+    /** 用户id */
+    @Schema(description = "用户id")
+    private String userId;
+
+    /** 变动类别: 1. 主动充值 2.主动消费 3.代金券生效 4.赠送 5.扣减 */
+    @Schema(description = "变动类别: 1. 主动充值 2.主动消费 3.代金券生效 4.赠送 5.扣减")
+    private String changeType;
+
+    /** 原账户余额 */
+    @Schema(description = "原账户余额")
+    private BigDecimal oldAccountBalance;
+
+    /** 原代金券金额 */
+    @Schema(description = "原代金券金额")
+    private BigDecimal oldVoucherBalance;
+
+    /** 现账户余额 */
+    @Schema(description = "现账户余额")
+    private BigDecimal newAccountBalance;
+
+    /** 现代金券金额 */
+    @Schema(description = "现代金券金额")
+    private BigDecimal newVoucherBalance;
+
+
+}

+ 34 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/enums/BizUserFundChangeRecordEnum.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.enums;
+
+import lombok.Getter;
+
+/**
+ * 用户账户资金变动记录枚举
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ **/
+@Getter
+public enum BizUserFundChangeRecordEnum {
+
+    /** 测试 */
+    TEST("TEST");
+
+    private final String value;
+
+    BizUserFundChangeRecordEnum(String value) {
+        this.value = value;
+    }
+}

+ 25 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/mapper/BizUserFundChangeRecordMapper.java

@@ -0,0 +1,25 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import vip.xiaonuo.biz.modular.userfundchangerecord.entity.BizUserFundChangeRecord;
+
+/**
+ * 用户账户资金变动记录Mapper接口
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ **/
+public interface BizUserFundChangeRecordMapper extends BaseMapper<BizUserFundChangeRecord> {
+}

+ 5 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/mapper/mapping/BizUserFundChangeRecordMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="vip.xiaonuo.biz.modular.userfundchangerecord.mapper.BizUserFundChangeRecordMapper">
+
+</mapper>

+ 58 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/param/BizUserFundChangeRecordAddParam.java

@@ -0,0 +1,58 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 用户账户资金变动记录添加参数
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ **/
+@Getter
+@Setter
+public class BizUserFundChangeRecordAddParam {
+
+    /** 用户id */
+    @Schema(description = "用户id")
+    private String userId;
+
+    /** 变动类别: 1. 主动充值 2.主动消费 3.代金券生效 4.赠送 5.扣减 */
+    @Schema(description = "变动类别: 1. 主动充值 2.主动消费 3.代金券生效 4.赠送 5.扣减")
+    private String changeType;
+
+    /** 原账户余额 */
+    @Schema(description = "原账户余额")
+    private BigDecimal oldAccountBalance;
+
+    /** 原代金券金额 */
+    @Schema(description = "原代金券金额")
+    private BigDecimal oldVoucherBalance;
+
+    /** 现账户余额 */
+    @Schema(description = "现账户余额")
+    private BigDecimal newAccountBalance;
+
+    /** 现代金券金额 */
+    @Schema(description = "现代金券金额")
+    private BigDecimal newVoucherBalance;
+
+}

+ 63 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/param/BizUserFundChangeRecordEditParam.java

@@ -0,0 +1,63 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 用户账户资金变动记录编辑参数
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ **/
+@Getter
+@Setter
+public class BizUserFundChangeRecordEditParam {
+
+    /** 账户金额变动记录id */
+    @Schema(description = "账户金额变动记录id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+
+    /** 用户id */
+    @Schema(description = "用户id")
+    private String userId;
+
+    /** 变动类别: 1. 主动充值 2.主动消费 3.代金券生效 4.赠送 5.扣减 */
+    @Schema(description = "变动类别: 1. 主动充值 2.主动消费 3.代金券生效 4.赠送 5.扣减")
+    private String changeType;
+
+    /** 原账户余额 */
+    @Schema(description = "原账户余额")
+    private BigDecimal oldAccountBalance;
+
+    /** 原代金券金额 */
+    @Schema(description = "原代金券金额")
+    private BigDecimal oldVoucherBalance;
+
+    /** 现账户余额 */
+    @Schema(description = "现账户余额")
+    private BigDecimal newAccountBalance;
+
+    /** 现代金券金额 */
+    @Schema(description = "现代金券金额")
+    private BigDecimal newVoucherBalance;
+
+}

+ 35 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/param/BizUserFundChangeRecordIdParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import jakarta.validation.constraints.NotBlank;
+
+/**
+ * 用户账户资金变动记录Id参数
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ **/
+@Getter
+@Setter
+public class BizUserFundChangeRecordIdParam {
+
+    /** 账户金额变动记录id */
+    @Schema(description = "账户金额变动记录id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotBlank(message = "id不能为空")
+    private String id;
+}

+ 51 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/param/BizUserFundChangeRecordPageParam.java

@@ -0,0 +1,51 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.param;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 用户账户资金变动记录查询参数
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ **/
+@Getter
+@Setter
+public class BizUserFundChangeRecordPageParam {
+
+    /** 当前页 */
+    @Schema(description = "当前页码")
+    private Integer current;
+
+    /** 每页条数 */
+    @Schema(description = "每页条数")
+    private Integer size;
+
+    /** 排序字段 */
+    @Schema(description = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @Schema(description = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+
+    /** 关键词 */
+    @Schema(description = "关键词")
+    private String searchKey;
+
+}

+ 80 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/service/BizUserFundChangeRecordService.java

@@ -0,0 +1,80 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import vip.xiaonuo.biz.modular.userfundchangerecord.entity.BizUserFundChangeRecord;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordAddParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordEditParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordIdParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordPageParam;
+
+import java.util.List;
+
+/**
+ * 用户账户资金变动记录Service接口
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ **/
+public interface BizUserFundChangeRecordService extends IService<BizUserFundChangeRecord> {
+
+    /**
+     * 获取用户账户资金变动记录分页
+     *
+     * @author wulei
+     * @date  2025/02/07 11:26
+     */
+    Page<BizUserFundChangeRecord> page(BizUserFundChangeRecordPageParam bizUserFundChangeRecordPageParam);
+
+    /**
+     * 添加用户账户资金变动记录
+     *
+     * @author wulei
+     * @date  2025/02/07 11:26
+     */
+    void add(BizUserFundChangeRecordAddParam bizUserFundChangeRecordAddParam);
+
+    /**
+     * 编辑用户账户资金变动记录
+     *
+     * @author wulei
+     * @date  2025/02/07 11:26
+     */
+    void edit(BizUserFundChangeRecordEditParam bizUserFundChangeRecordEditParam);
+
+    /**
+     * 删除用户账户资金变动记录
+     *
+     * @author wulei
+     * @date  2025/02/07 11:26
+     */
+    void delete(List<BizUserFundChangeRecordIdParam> bizUserFundChangeRecordIdParamList);
+
+    /**
+     * 获取用户账户资金变动记录详情
+     *
+     * @author wulei
+     * @date  2025/02/07 11:26
+     */
+    BizUserFundChangeRecord detail(BizUserFundChangeRecordIdParam bizUserFundChangeRecordIdParam);
+
+    /**
+     * 获取用户账户资金变动记录详情
+     *
+     * @author wulei
+     * @date  2025/02/07 11:26
+     **/
+    BizUserFundChangeRecord queryEntity(String id);
+}

+ 94 - 0
snowy-plugin/snowy-plugin-biz/src/main/java/vip/xiaonuo/biz/modular/userfundchangerecord/service/impl/BizUserFundChangeRecordServiceImpl.java

@@ -0,0 +1,94 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.biz.modular.userfundchangerecord.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.common.enums.CommonSortOrderEnum;
+import vip.xiaonuo.common.exception.CommonException;
+import vip.xiaonuo.common.page.CommonPageRequest;
+import vip.xiaonuo.biz.modular.userfundchangerecord.entity.BizUserFundChangeRecord;
+import vip.xiaonuo.biz.modular.userfundchangerecord.mapper.BizUserFundChangeRecordMapper;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordAddParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordEditParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordIdParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.param.BizUserFundChangeRecordPageParam;
+import vip.xiaonuo.biz.modular.userfundchangerecord.service.BizUserFundChangeRecordService;
+
+import java.util.List;
+
+/**
+ * 用户账户资金变动记录Service接口实现类
+ *
+ * @author wulei
+ * @date  2025/02/07 11:26
+ **/
+@Service
+public class BizUserFundChangeRecordServiceImpl extends ServiceImpl<BizUserFundChangeRecordMapper, BizUserFundChangeRecord> implements BizUserFundChangeRecordService {
+
+    @Override
+    public Page<BizUserFundChangeRecord> page(BizUserFundChangeRecordPageParam bizUserFundChangeRecordPageParam) {
+        QueryWrapper<BizUserFundChangeRecord> queryWrapper = new QueryWrapper<BizUserFundChangeRecord>().checkSqlInjection();
+        if(ObjectUtil.isAllNotEmpty(bizUserFundChangeRecordPageParam.getSortField(), bizUserFundChangeRecordPageParam.getSortOrder())) {
+            CommonSortOrderEnum.validate(bizUserFundChangeRecordPageParam.getSortOrder());
+            queryWrapper.orderBy(true, bizUserFundChangeRecordPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
+                    StrUtil.toUnderlineCase(bizUserFundChangeRecordPageParam.getSortField()));
+        } else {
+            queryWrapper.lambda().orderByAsc(BizUserFundChangeRecord::getId);
+        }
+        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void add(BizUserFundChangeRecordAddParam bizUserFundChangeRecordAddParam) {
+        BizUserFundChangeRecord bizUserFundChangeRecord = BeanUtil.toBean(bizUserFundChangeRecordAddParam, BizUserFundChangeRecord.class);
+        this.save(bizUserFundChangeRecord);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void edit(BizUserFundChangeRecordEditParam bizUserFundChangeRecordEditParam) {
+        BizUserFundChangeRecord bizUserFundChangeRecord = this.queryEntity(bizUserFundChangeRecordEditParam.getId());
+        BeanUtil.copyProperties(bizUserFundChangeRecordEditParam, bizUserFundChangeRecord);
+        this.updateById(bizUserFundChangeRecord);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void delete(List<BizUserFundChangeRecordIdParam> bizUserFundChangeRecordIdParamList) {
+        // 执行删除
+        this.removeByIds(CollStreamUtil.toList(bizUserFundChangeRecordIdParamList, BizUserFundChangeRecordIdParam::getId));
+    }
+
+    @Override
+    public BizUserFundChangeRecord detail(BizUserFundChangeRecordIdParam bizUserFundChangeRecordIdParam) {
+        return this.queryEntity(bizUserFundChangeRecordIdParam.getId());
+    }
+
+    @Override
+    public BizUserFundChangeRecord queryEntity(String id) {
+        BizUserFundChangeRecord bizUserFundChangeRecord = this.getById(id);
+        if(ObjectUtil.isEmpty(bizUserFundChangeRecord)) {
+            throw new CommonException("用户账户资金变动记录不存在,id值为:{}", id);
+        }
+        return bizUserFundChangeRecord;
+    }
+}

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików