ai-engineering-init 1.16.2 → 1.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.claude/skills/code-patterns/SKILL.md +0 -119
  2. package/.claude/skills/codex-code-review/SKILL.md +0 -39
  3. package/.claude/skills/fix-bug/SKILL.md +57 -0
  4. package/.claude/skills/leniu-code-patterns/SKILL.md +2 -179
  5. package/.claude/skills/leniu-crud-development/SKILL.md +7 -26
  6. package/.claude/skills/leniu-java-mybatis/SKILL.md +16 -25
  7. package/.claude/skills/leniu-report-scenario/references/amount-handling.md +448 -0
  8. package/.claude/skills/leniu-report-scenario/references/analysis-module.md +64 -0
  9. package/.claude/skills/leniu-report-scenario/references/customization-table-fields.md +93 -0
  10. package/.claude/skills/leniu-report-scenario/references/export.md +553 -0
  11. package/.claude/skills/leniu-report-scenario/references/mealtime.md +197 -0
  12. package/.claude/skills/leniu-report-scenario/references/query-param.md +274 -0
  13. package/.claude/skills/leniu-report-scenario/references/standard-customization.md +112 -0
  14. package/.claude/skills/leniu-report-scenario/references/standard-table-fields.md +113 -0
  15. package/.claude/skills/leniu-report-scenario/references/total-line.md +179 -0
  16. package/.claude/skills/loki-log-query/SKILL.md +30 -33
  17. package/.claude/skills/mysql-debug/SKILL.md +17 -35
  18. package/.codex/skills/code-patterns/SKILL.md +0 -119
  19. package/.codex/skills/fix-bug/SKILL.md +57 -0
  20. package/.codex/skills/leniu-code-patterns/SKILL.md +2 -179
  21. package/.codex/skills/leniu-crud-development/SKILL.md +7 -26
  22. package/.codex/skills/leniu-java-amount-handling/SKILL.md +461 -0
  23. package/.codex/skills/leniu-java-mybatis/SKILL.md +16 -25
  24. package/.codex/skills/leniu-report-scenario/references/amount-handling.md +448 -0
  25. package/.codex/skills/leniu-report-scenario/references/analysis-module.md +64 -0
  26. package/.codex/skills/leniu-report-scenario/references/customization-table-fields.md +93 -0
  27. package/.codex/skills/leniu-report-scenario/references/export.md +553 -0
  28. package/.codex/skills/leniu-report-scenario/references/mealtime.md +197 -0
  29. package/.codex/skills/leniu-report-scenario/references/query-param.md +274 -0
  30. package/.codex/skills/leniu-report-scenario/references/standard-customization.md +112 -0
  31. package/.codex/skills/leniu-report-scenario/references/standard-table-fields.md +113 -0
  32. package/.codex/skills/leniu-report-scenario/references/total-line.md +179 -0
  33. package/.codex/skills/loki-log-query/SKILL.md +55 -25
  34. package/.codex/skills/mysql-debug/SKILL.md +12 -6
  35. package/.cursor/skills/code-patterns/SKILL.md +0 -119
  36. package/.cursor/skills/fix-bug/SKILL.md +57 -0
  37. package/.cursor/skills/leniu-code-patterns/SKILL.md +2 -179
  38. package/.cursor/skills/leniu-crud-development/SKILL.md +7 -26
  39. package/.cursor/skills/leniu-java-amount-handling/SKILL.md +461 -0
  40. package/.cursor/skills/leniu-java-mybatis/SKILL.md +16 -25
  41. package/.cursor/skills/leniu-report-scenario/references/amount-handling.md +448 -0
  42. package/.cursor/skills/leniu-report-scenario/references/analysis-module.md +64 -0
  43. package/.cursor/skills/leniu-report-scenario/references/customization-table-fields.md +93 -0
  44. package/.cursor/skills/leniu-report-scenario/references/export.md +553 -0
  45. package/.cursor/skills/leniu-report-scenario/references/mealtime.md +197 -0
  46. package/.cursor/skills/leniu-report-scenario/references/query-param.md +274 -0
  47. package/.cursor/skills/leniu-report-scenario/references/standard-customization.md +112 -0
  48. package/.cursor/skills/leniu-report-scenario/references/standard-table-fields.md +113 -0
  49. package/.cursor/skills/leniu-report-scenario/references/total-line.md +179 -0
  50. package/.cursor/skills/loki-log-query/SKILL.md +30 -33
  51. package/.cursor/skills/mysql-debug/SKILL.md +20 -36
  52. package/CLAUDE.md +34 -0
  53. package/package.json +1 -1
  54. package/src/skills/fix-bug/SKILL.md +57 -0
@@ -22,7 +22,7 @@ description: |
22
22
  | XML 位置 | **与 Mapper 接口同目录**(非 `resources/mapper/`) |
23
23
  | 分页 | PageHelper → `PageMethod.startPage(PageDTO)` → `PageVO.of(list)` |
24
24
  | 逻辑删除 | **1=删除,2=正常**(与 RuoYi 相反) |
25
- | Service | **两种模式并存**:简单 CRUD 继承 `ServiceImpl`(`this.baseMapper`);业务聚合直接 `@Service`(`@Autowired XxxMapper xxxMapper`) |
25
+ | Service | 无接口,直接 `@Service` 类,Mapper 字段名统一用 `baseMapper` |
26
26
  | 循环依赖 | 跨模块依赖用 `@Autowired @Lazy` |
27
27
 
28
28
  ## Mapper 接口模板
@@ -147,36 +147,28 @@ List<XxxEntity> list = mapper.selectList(
147
147
 
148
148
  ## Service 注入规范
149
149
 
150
- 项目中 Service 有两种模式,Mapper 字段名也不统一——参考周围已有代码的风格即可。
151
-
152
- **模式 A:继承 ServiceImpl(简单 CRUD)**
153
- ```java
154
- @Service
155
- public class XxxServiceImpl extends ServiceImpl<XxxMapper, XxxEntity> implements XxxService {
156
- // 通过 this.baseMapper 访问 Mapper(父类自动注入)
157
- public boolean exists(String macOrderId) {
158
- return this.baseMapper.existsOne(
159
- Wrappers.lambdaQuery(XxxEntity.class)
160
- .eq(XxxEntity::getMacOrderId, macOrderId)
161
- .eq(XxxEntity::getDelFlag, 2)
162
- );
163
- }
164
- }
165
- ```
166
-
167
- **模式 B:直接 @Service(业务聚合)**
168
150
  ```java
169
151
  @Slf4j
170
152
  @Service
153
+ @Validated
171
154
  public class XxxService {
155
+
172
156
  @Autowired
173
- private XxxMapper xxxMapper; // 字段名跟随 Mapper 类名
157
+ private XxxMapper baseMapper; // 统一命名 baseMapper
174
158
 
175
159
  @Autowired @Lazy
176
- private YyyService yyyService; // 跨模块用 @Lazy
160
+ private XxxDetailService xxxDetailService; // 跨模块用 @Lazy
177
161
 
178
162
  public XxxEntity getOne(Long id) {
179
- return xxxMapper.selectById(id);
163
+ return baseMapper.selectById(id);
164
+ }
165
+
166
+ public boolean exists(String macOrderId) {
167
+ return baseMapper.existsOne(
168
+ Wrappers.lambdaQuery(XxxEntity.class)
169
+ .eq(XxxEntity::getMacOrderId, macOrderId)
170
+ .eq(XxxEntity::getDelFlag, 2)
171
+ );
180
172
  }
181
173
  }
182
174
  ```
@@ -258,9 +250,8 @@ wrapper.eq(XxxEntity::getDelFlag, 0);
258
250
  // ❌ MapstructUtils(用 BeanUtil.copyProperties)
259
251
  MapstructUtils.convert(source, Target.class);
260
252
 
261
- // ❌ 业务聚合 Service 不要继承 IService / ServiceImpl(简单 CRUD Service 可以继承)
262
- // 错误:在报表/业务编排 Service 中继承 ServiceImpl
263
- // 正确:简单单表 CRUD 可以继承 ServiceImpl,复杂业务直接 @Service
253
+ // ❌ Service 继承 IService / ServiceImpl
254
+ public interface IXxxService extends IService<XxxEntity> {}
264
255
  ```
265
256
 
266
257
  ## XML 文件位置
@@ -0,0 +1,448 @@
1
+
2
+ # leniu-tengyun-core 金额处理规范
3
+
4
+ ## 两种金额存储模式
5
+
6
+ 项目中存在两种金额存储模式,根据业务模块选择:
7
+
8
+ ### 模式 A:Long(分)→ BigDecimal(元)[钱包/账户模块]
9
+
10
+ 适用于余额、充值、补贴等精度要求高的模块:
11
+
12
+ - **数据库**:存储为 Long(分)
13
+ - **Entity**:使用 Long 类型
14
+ - **VO**:使用 BigDecimal 类型(MyBatis 自动转换分→元)
15
+ - **Excel 导出**:使用 `CustomNumberConverter` 转换器
16
+
17
+ ### 模式 B:BigDecimal(分)[订单/报表模块]
18
+
19
+ 适用于订单金额、报表汇总等复杂计算模块:
20
+
21
+ - **数据库**:存储为 BigDecimal(值为分,如 10000 = 100.00元)
22
+ - **Entity**:直接使用 BigDecimal 类型(以分为单位)
23
+ - **VO**:同样使用 BigDecimal(字段注释需标注单位)
24
+ - **SQL SUM**:直接 `SUM(amount)`,不需要 /100
25
+
26
+ > 参考:`OrderInfo.payableAmount`(BigDecimal,以分为单位)
27
+
28
+ ## 金额类型速查
29
+
30
+ | 类型 | 用途 | 示例 |
31
+ |------|------|------|
32
+ | `Long` | 钱包/账户存储(分) | `private Long orderAmount; // 10000 = 100.00元` |
33
+ | `BigDecimal` | 订单/报表存储(分) | `private BigDecimal payableAmount; // 10000 = 100.00元` |
34
+ | `BigDecimal` | VO 展示(元,模式A) | `private BigDecimal amount; // 100.00` |
35
+
36
+ ## Entity(模式A:Long存储)
37
+
38
+ ```java
39
+ import com.baomidou.mybatisplus.annotation.*;
40
+ import io.swagger.annotations.ApiModel;
41
+ import io.swagger.annotations.ApiModelProperty;
42
+ import lombok.Data;
43
+
44
+ @Data
45
+ @TableName(value = "wallet_table", autoResultMap = true)
46
+ public class WalletEntity {
47
+
48
+ @TableId
49
+ @ApiModelProperty(value = "钱包ID")
50
+ private Long id;
51
+
52
+ @ApiModelProperty(value = "余额(分)")
53
+ private Long balance;
54
+
55
+ @ApiModelProperty(value = "充值金额(分)")
56
+ private Long rechargeAmount;
57
+ }
58
+ ```
59
+
60
+ **要点**:
61
+ - Entity 使用 `Long` 类型存储金额(分)
62
+ - 字段注释明确标注"(分)"
63
+
64
+ ## Entity(模式B:BigDecimal存储,适用订单模块)
65
+
66
+ ```java
67
+ @Data
68
+ @TableName("order_info")
69
+ public class OrderInfo {
70
+
71
+ @ApiModelProperty(value = "应付金额(分)")
72
+ private BigDecimal payableAmount;
73
+
74
+ @ApiModelProperty(value = "实付金额(分)")
75
+ private BigDecimal realAmount;
76
+
77
+ @ApiModelProperty(value = "优惠金额(分)")
78
+ private BigDecimal discountsAmount;
79
+ }
80
+ ```
81
+
82
+ **要点**:
83
+ - 字段类型为 BigDecimal,但值以分为单位存储
84
+ - 不需要 MyBatis 类型转换
85
+
86
+ ## VO(响应层)
87
+
88
+ ```java
89
+ import com.alibaba.excel.annotation.ExcelProperty;
90
+ import io.swagger.annotations.ApiModel;
91
+ import io.swagger.annotations.ApiModelProperty;
92
+ import lombok.Data;
93
+ import lombok.experimental.Accessors;
94
+ import net.xnzn.core.common.export.converter.CustomNumberConverter;
95
+
96
+ import java.math.BigDecimal;
97
+
98
+ @Data
99
+ @Accessors(chain = true)
100
+ @ApiModel("订单信息")
101
+ public class OrderVO {
102
+
103
+ @ApiModelProperty("订单ID")
104
+ private Long id;
105
+
106
+ @ApiModelProperty("订单金额(元)")
107
+ @ExcelProperty(value = "订单金额(元)", converter = CustomNumberConverter.class)
108
+ private BigDecimal orderAmount;
109
+
110
+ @ApiModelProperty("优惠金额(元)")
111
+ @ExcelProperty(value = "优惠金额(元)", converter = CustomNumberConverter.class)
112
+ private BigDecimal discountAmount;
113
+
114
+ @ApiModelProperty("实付金额(元)")
115
+ @ExcelProperty(value = "实付金额(元)", converter = CustomNumberConverter.class)
116
+ private BigDecimal payAmount;
117
+ }
118
+ ```
119
+
120
+ **要点**:
121
+ - VO 使用 `BigDecimal` 类型(元)
122
+ - Excel 导出必须使用 `converter = CustomNumberConverter.class`
123
+ - MyBatis 会自动将 Long 分转换为 BigDecimal 元
124
+
125
+ ## MyBatis XML 查询
126
+
127
+ ### 列表查询
128
+
129
+ ```xml
130
+ <select id="listOrders" resultType="OrderVO">
131
+ SELECT
132
+ order_id,
133
+ order_amount, -- ❌ 不要 /100.0
134
+ discount_amount, -- ❌ 不要 /100.0
135
+ pay_amount -- ❌ 不要 /100.0
136
+ FROM order_table
137
+ <where>...</where>
138
+ ORDER BY crtime DESC
139
+ </select>
140
+ ```
141
+
142
+ ### 合计查询
143
+
144
+ ```xml
145
+ <select id="getOrderTotal" resultType="OrderVO">
146
+ SELECT
147
+ SUM(order_amount) AS order_amount, -- ❌ 不要 /100.0
148
+ SUM(discount_amount) AS discount_amount,-- ❌ 不要 /100.0
149
+ SUM(pay_amount) AS pay_amount -- ❌ 不要 /100.0
150
+ FROM order_table
151
+ <where>...</where>
152
+ </select>
153
+ ```
154
+
155
+ **重要**:
156
+ - 永远不要在 SQL 中使用 `/100.0`
157
+ - 合计查询只返回数值字段,不返回非数值字段(如日期、名称)
158
+
159
+ ## 金额工具类
160
+
161
+ ### AmountUtil(分转元)
162
+
163
+ ```java
164
+ import java.math.BigDecimal;
165
+ import java.math.RoundingMode;
166
+
167
+ /**
168
+ * 分与元金额转换
169
+ */
170
+ public class AmountUtil {
171
+
172
+ /**
173
+ * 分转元(String)
174
+ */
175
+ public static String fen2YuanStr(Integer fen) {
176
+ if (fen == null) {
177
+ return "0.00";
178
+ }
179
+ BigDecimal amountFen = new BigDecimal(fen);
180
+ BigDecimal amountYuan = amountFen.divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
181
+ return amountYuan.toPlainString();
182
+ }
183
+
184
+ /**
185
+ * 分转元(String 重载)
186
+ */
187
+ public static String fen2YuanStr(String fen) {
188
+ if (fen == null || fen.isEmpty()) {
189
+ return "0.00";
190
+ }
191
+ BigDecimal amountFen = new BigDecimal(fen);
192
+ BigDecimal amountYuan = amountFen.divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
193
+ return amountYuan.toPlainString();
194
+ }
195
+
196
+ /**
197
+ * 分转元(BigDecimal)
198
+ */
199
+ public static BigDecimal fen2Yuan(Integer fen) {
200
+ if (fen == null) {
201
+ return BigDecimal.ZERO;
202
+ }
203
+ BigDecimal amountFen = new BigDecimal(fen);
204
+ return amountFen.divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
205
+ }
206
+
207
+ /**
208
+ * 分转元(Long)
209
+ */
210
+ public static BigDecimal fen2Yuan(Long fen) {
211
+ if (fen == null) {
212
+ return BigDecimal.ZERO;
213
+ }
214
+ BigDecimal amountFen = new BigDecimal(fen);
215
+ return amountFen.divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
216
+ }
217
+
218
+ /**
219
+ * 元转分
220
+ */
221
+ public static Integer yuan2Fen(String yuan) {
222
+ if (yuan == null || yuan.isEmpty()) {
223
+ return 0;
224
+ }
225
+ BigDecimal balance = new BigDecimal(yuan);
226
+ return Integer.parseInt(balance.multiply(new BigDecimal("100"))
227
+ .setScale(0, RoundingMode.HALF_UP)
228
+ .toPlainString());
229
+ }
230
+
231
+ /**
232
+ * 元转分(BigDecimal)
233
+ */
234
+ public static Integer yuan2Fen(BigDecimal yuan) {
235
+ if (yuan == null) {
236
+ return 0;
237
+ }
238
+ return yuan.multiply(new BigDecimal("100"))
239
+ .setScale(0, RoundingMode.HALF_UP)
240
+ .intValue();
241
+ }
242
+ }
243
+ ```
244
+
245
+ ### 使用示例
246
+
247
+ ```java
248
+ // 分转元
249
+ Integer fenAmount = 10000; // 10000分
250
+ BigDecimal yuanAmount = AmountUtil.fen2Yuan(fenAmount); // 100.00元
251
+
252
+ // 元转分
253
+ BigDecimal yuan = new BigDecimal("99.99");
254
+ Integer fenAmount = AmountUtil.yuan2Fen(yuan); // 9999分
255
+ ```
256
+
257
+ ## 常见场景
258
+
259
+ ### 场景1:订单报表 VO
260
+
261
+ ```java
262
+ @Data
263
+ @Accessors(chain = true)
264
+ @ApiModel("订单报表")
265
+ public class OrderReportVO {
266
+
267
+ @ExcelProperty(value = "月度", order = 1)
268
+ @ApiModelProperty("月度")
269
+ private String dateMonth;
270
+
271
+ @ExcelProperty(value = "订单总额(元)", order = 2, converter = CustomNumberConverter.class)
272
+ @ApiModelProperty("订单总额(元)")
273
+ private BigDecimal totalAmount;
274
+
275
+ @ExcelProperty(value = "订单数量", order = 3)
276
+ @ApiModelProperty("订单数量")
277
+ private Integer totalCount;
278
+
279
+ @ExcelProperty(value = "平均金额(元)", order = 4, converter = CustomNumberConverter.class)
280
+ @ApiModelProperty("平均金额(元)")
281
+ private BigDecimal avgAmount;
282
+ }
283
+ ```
284
+
285
+ ### 场景2:工资汇总 VO
286
+
287
+ ```java
288
+ @Data
289
+ @Accessors(chain = true)
290
+ @ApiModel("工资汇总")
291
+ public class SalarySummaryVO {
292
+
293
+ @ExcelProperty(value = "月度", order = 1)
294
+ @ApiModelProperty("月度")
295
+ private String dateMonth;
296
+
297
+ @ExcelProperty(value = "基本工资(元)", order = 2, converter = CustomNumberConverter.class)
298
+ @ApiModelProperty("基本工资(元)")
299
+ private BigDecimal basicSalary;
300
+
301
+ @ExcelProperty(value = "绩效工资(元)", order = 3, converter = CustomNumberConverter.class)
302
+ @ApiModelProperty("绩效工资(元)")
303
+ private BigDecimal performanceSalary;
304
+
305
+ @ExcelProperty(value = "应发工资(元)", order = 4, converter = CustomNumberConverter.class)
306
+ @ApiModelProperty("应发工资(元)")
307
+ private BigDecimal totalSalary;
308
+ }
309
+ ```
310
+
311
+ ### 场景3:合计行 SQL
312
+
313
+ ```xml
314
+ <!-- 列表查询 -->
315
+ <select id="pageSalary" resultType="SalarySummaryVO">
316
+ SELECT
317
+ date_month,
318
+ staff_count,
319
+ basic_salary,
320
+ performance_salary,
321
+ total_salary
322
+ FROM salary_summary
323
+ <where>...</where>
324
+ ORDER BY date_month DESC
325
+ </select>
326
+
327
+ <!-- 合计查询:只返回数值字段 -->
328
+ <select id="getSalaryTotal" resultType="SalarySummaryVO">
329
+ SELECT
330
+ SUM(staff_count) AS staff_count,
331
+ SUM(basic_salary) AS basic_salary,
332
+ SUM(performance_salary) AS performance_salary,
333
+ SUM(total_salary) AS total_salary
334
+ FROM salary_summary
335
+ <where>...</where>
336
+ </select>
337
+ ```
338
+
339
+ ### 场景4:平均值计算
340
+
341
+ ```xml
342
+ <!-- 平均值计算(除零处理) -->
343
+ CASE
344
+ WHEN SUM(staff_count) = 0 THEN 0
345
+ ELSE SUM(total_salary) / SUM(staff_count)
346
+ END AS avgSalary
347
+
348
+ <!-- 按维度平均 -->
349
+ CASE
350
+ WHEN SUM(staff_count) = 0 THEN 0
351
+ ELSE SUM(total_salary) / COUNT(DISTINCT tenant_id)
352
+ END AS avgSalary
353
+ ```
354
+
355
+ ## 数据流
356
+
357
+ ```
358
+ 数据库(Long/分) → MyBatis → VO(BigDecimal/元) → 前端(自动 /100)
359
+
360
+ Excel(converter /100)
361
+ ```
362
+
363
+ ## Excel 导出
364
+
365
+ ### 转换器
366
+
367
+ ```java
368
+ @ExcelProperty(value = "订单金额(元)", converter = CustomNumberConverter.class)
369
+ private BigDecimal orderAmount;
370
+ ```
371
+
372
+ ### 必要的导入
373
+
374
+ ```java
375
+ import com.alibaba.excel.annotation.ExcelProperty;
376
+ import net.xnzn.core.common.export.converter.CustomNumberConverter;
377
+ ```
378
+
379
+ ## 常见错误
380
+
381
+ ### 错误1:在 SQL 中使用 /100.0
382
+
383
+ ```xml
384
+ <!-- ❌ 错误:在 SQL 中除以 100 -->
385
+ SELECT
386
+ order_amount / 100.0 AS order_amount
387
+ FROM order_table
388
+
389
+ <!-- ✅ 正确:不进行除法,MyBatis 自动转换 -->
390
+ SELECT
391
+ order_amount AS order_amount
392
+ FROM order_table
393
+ ```
394
+
395
+ ### 错误2:钱包模块 Entity 使用 BigDecimal(模式A适用)
396
+
397
+ ```java
398
+ // ❌ 错误:钱包/账户模块 Entity 使用 BigDecimal(应用 Long)
399
+ @Data
400
+ public class WalletEntity {
401
+ @ApiModelProperty("余额(元)")
402
+ private BigDecimal balance;
403
+ }
404
+
405
+ // ✅ 正确:钱包/账户模块 Entity 使用 Long(分)
406
+ @Data
407
+ public class WalletEntity {
408
+ @ApiModelProperty("余额(分)")
409
+ private Long balance;
410
+ }
411
+ ```
412
+
413
+ > **注意**:订单模块(OrderInfo)使用 BigDecimal 存储金额(以分为单位),这是模式B,属于正确用法,不是错误。
414
+
415
+ ### 错误3:VO 不使用转换器
416
+
417
+ ```java
418
+ // ❌ 错误:Excel 导出不使用转换器
419
+ @ExcelProperty(value = "订单金额(元)")
420
+ private BigDecimal orderAmount;
421
+
422
+ // ✅ 正确:使用 CustomNumberConverter
423
+ @ExcelProperty(value = "订单金额(元)", converter = CustomNumberConverter.class)
424
+ private BigDecimal orderAmount;
425
+ ```
426
+
427
+ ### 错误4:合计查询返回非数值字段
428
+
429
+ ```xml
430
+ <!-- ❌ 错误:合计查询返回非数值字段 -->
431
+ <select id="getOrderTotal" resultType="OrderVO">
432
+ SELECT
433
+ SUM(order_amount) AS order_amount,
434
+ order_date -- ❌ 非数值字段
435
+ FROM order_table
436
+ </select>
437
+
438
+ <!-- ✅ 正确:只返回数值字段 -->
439
+ <select id="getOrderTotal" resultType="OrderVO">
440
+ SELECT
441
+ SUM(order_amount) AS order_amount
442
+ FROM order_table
443
+ </select>
444
+ ```
445
+
446
+ ## 参考文档
447
+
448
+ 详见:[leniu-tengyun-core 源码](/Users/xujiajun/Developer/gongsi_proj/core/leniu-tengyun-core)
@@ -0,0 +1,64 @@
1
+ # 经营分析模块详情
2
+
3
+ ## 分析类型总览
4
+
5
+ | 分析类型 | Service | 接口数 | 路由前缀 |
6
+ |---------|---------|-------|---------|
7
+ | 营业额 | ReportAnalysisTurnoverService | 6 | `/summary/analysis/turnover/` |
8
+ | 用户 | ReportAnalysisCustService (ORDER=50) | 8 | `/summary/analysis/cust/` |
9
+ | 菜品 | ReportAnalysisDishesSaleService (ORDER=51) | 10 | `/summary/analysis/dishes/` |
10
+ | 满意度 | ReportAnalysisEvaluateService | 2 | `/summary/analysis/evaluate/` |
11
+ | 充值 | ReportAnalysisTurnoverService | 4 | `/summary/analysis/recharge/` |
12
+ | 设备 | ReportAnalysisTurnoverService | 2 | `/summary/analysis/device/` |
13
+
14
+ ## 用户活跃度分析
15
+
16
+ ### 分段枚举
17
+
18
+ - `AnalysisConsumeTimesEnum`:消费次数分段(1-10/10-20/20-30/30-40/40-50/>=50)
19
+ - `AnalysisConsumeAmountEnum`:消费金额分段(<200/200-400/400-600/600-800/800-1000/>=1000元)
20
+ - `AnalysisConsumeSlienceEnum`:沉默时长分段
21
+
22
+ ### 活跃度 VO
23
+
24
+ ```java
25
+ // ReportAnalysisActiveVO
26
+ activeNumber/activePercent // 活跃用户(有消费记录)
27
+ keepNumber/keepPercent // 保留用户(持续消费)
28
+ lossNumber/lossPercent // 流失用户(不再消费)
29
+ newNumber/newPercent // 新增用户(首次消费)
30
+ ```
31
+
32
+ ## 公共参数类
33
+
34
+ ```java
35
+ // ReportBaseParam(所有查询参数基类)
36
+ PageDTO page;
37
+ LocalDate startDate/endDate;
38
+ LocalDate startOrderDate/endOrderDate;
39
+ Integer sumType; // 汇总类型(1按时段/2按日期)
40
+ Integer sumDimension; // 汇总维度
41
+ List<Integer> ageTypes;
42
+ List<Integer> holidayTypeList;
43
+ List<String> exportCols;
44
+ LocalDateTime startPayTime/endPayTime;
45
+
46
+ // ReportNotConsumeDTO(未消费数据)
47
+ String statisticDate; // 统计日期(支付日期)
48
+ String orderDate; // 就餐日期(菜品统计专用)
49
+ Long relationId;
50
+
51
+ // 支付信息编码: "支付方式-支付渠道-支付金额" 如 "1-1-1200;2-4-1200"
52
+ // 优惠信息编码: "变动类型,详情类型,金额" 如 "1,1,100;2,11,200"
53
+ ```
54
+
55
+ ## API 路由总览
56
+
57
+ | 模块 | 前缀 | 核心接口 |
58
+ |------|------|---------|
59
+ | 营业收入明细 | `/summary/basic/` | flow/page, cust/page, remote/detail/page, remote/summary/page |
60
+ | 订单汇总 | `/summary/order/` | organization/pay/type/classify/mealtime/dishes |
61
+ | 账户流水 | `/summary/account/` | flow/cust/psn/organization/operator/consume/recharge/wallet/data |
62
+ | 经营分析 | `/summary/analysis/` | turnover(6)/cust(8)/dishes(10)/recharge(4)/device(2)/evaluate(2) |
63
+ | 数据修复 | `/summary/fix/` | order, account (限31天) |
64
+ | 商户 | `/report/merchant/summary/` | consume, recharge |
@@ -0,0 +1,93 @@
1
+ # 报表基础表完整字段说明
2
+
3
+ ## report_order_info(报表订单主表)
4
+
5
+ > v5.29 后,正向下单和逆向退款**都存在这张表中**,通过 `consumeType` 区分。
6
+
7
+ | 字段 | 类型 | 说明 |
8
+ |------|------|------|
9
+ | `orderId` | Long | 主键。正向=订单ID,退款=退款单ID |
10
+ | `relationOrderId` | Long | 关联订单ID(退款记录指向原始订单) |
11
+ | `consumeType` | Integer | **1=消费,2=退款** |
12
+ | `orderRefundState` | Integer | **1=未退单,2=已退单(全退),3=部分退单** |
13
+ | `payableAmount` | BigDecimal | 应付金额(分) |
14
+ | `realAmount` | BigDecimal | 实付金额(分) |
15
+ | `refundAmount` | BigDecimal | 累计退款金额(分) |
16
+ | `realRefundAmount` | BigDecimal | 实际退款金额(分,退款记录为负数) |
17
+ | `walletAmount` | BigDecimal | 个人钱包支付金额(分) |
18
+ | `subsidyAmount` | BigDecimal | 补贴钱包支付金额(分) |
19
+ | `redEnvelopeAmount` | BigDecimal | 红包支付金额(分) |
20
+ | `accPayAmount` | BigDecimal | 账户支付金额(分) |
21
+ | `outPayAmount` | BigDecimal | 外部支付金额(分) |
22
+ | `payTime` | LocalDateTime | 支付时间(退款=审核时间) |
23
+ | `orderTime` | LocalDateTime | 下单时间 |
24
+ | `orderDate` | LocalDate | 就餐日期 |
25
+ | `status` | Integer | 消费状态:0=未消费,1=已消费 |
26
+ | `mealtimeType` | Integer | 餐次类型 |
27
+ | `orderType` | Integer | 订单类型(1当餐/2预订/3报餐/4扫码/5餐桌/6自助/11商城/12超市/21补扣/22外部) |
28
+ | `canteenId/canteenName` | Long/String | 食堂 |
29
+ | `stallId/stallName` | Long/String | 档口 |
30
+ | `areaId/areaName` | Long/String | 区域 |
31
+ | `custId/custName/custNum` | - | 用户信息 |
32
+ | `orgId/orgFullId/orgName/orgFullName` | - | 组织信息 |
33
+ | `payType` | Integer | 支付方式 |
34
+ | `payChannel` | Integer | 支付渠道 |
35
+ | `nuClearMode` | Integer | 核身方式(1刷卡/2刷脸/3扫码) |
36
+ | `sourceType` | Integer | 来源类型 |
37
+ | `ifOnline` | Integer | 是否在线订单(1是/2否) |
38
+ | `psnType/psnTypeName` | Integer/String | 用户类别 |
39
+ | `personType` | Integer | 人员归类(1职工/2患者/3陪护/4其他,医院版) |
40
+
41
+ ## report_order_detail(报表订单菜品明细表)
42
+
43
+ | 字段 | 类型 | 说明 |
44
+ |------|------|------|
45
+ | `detailId` | Long | 明细主键 |
46
+ | `orderId` | Long | 关联订单ID |
47
+ | `goodsDishesId/goodsDishesName` | Long/String | 菜品信息 |
48
+ | `salePrice` | BigDecimal | 售卖价格(分) |
49
+ | `prefPrice` | BigDecimal | 优惠价格(分) |
50
+ | `price` | BigDecimal | 计算价格(分,最终价格) |
51
+ | `quantity` | Integer | 数量/重量 |
52
+ | `totalAmount` | BigDecimal | 订单详情总金额(分) |
53
+ | `realAmount` | BigDecimal | 实际付款金额(分) |
54
+ | `detailState` | Integer | **1=正常,2=已退菜(全退),3=部分退菜** |
55
+ | `goodsRefundNum` | Integer | 商品已退数量 |
56
+ | `refundAmount` | BigDecimal | 商品退款金额(分) |
57
+ | `detailType` | Integer | 明细类别(1菜品/2套餐/3商品/4按键/5补扣/6报餐) |
58
+ | `costPrice` | BigDecimal | 成本价格 |
59
+
60
+ ## report_account_flow(账户变动流水主表)
61
+
62
+ | 字段 | 类型 | 说明 |
63
+ |------|------|------|
64
+ | `flowId` | Long | 主键(雪花ID) |
65
+ | `custId` | Long | 人员ID |
66
+ | `flowType` | Integer | 交易类型(AccTradeTypeEnum) |
67
+ | `flowRealAmount` | BigDecimal | 实际交易金额 |
68
+ | `flowAmount` | BigDecimal | 交易金额 |
69
+ | `accTotalBal` | BigDecimal | 所有钱包可用余额之和(不含冻结) |
70
+ | `accAllBal` | BigDecimal | 所有钱包总余额(含冻结) |
71
+ | `payTime` | LocalDateTime | 支付时间 |
72
+ | `ordTime` | LocalDateTime | 订单时间 |
73
+ | `status` | Integer | 消费状态:0=未消费,1=已消费 |
74
+ | `manageCost` | BigDecimal | 管理费 |
75
+ | `rechargeSource` | Integer | 充值来源 |
76
+ | `payChannel` | Integer | 支付渠道 |
77
+ | `payType` | Integer | 支付方式 |
78
+
79
+ > 注意:`custName`、`mobile`、`mobileSuffix` 使用 SM4 加密存储。
80
+
81
+ ## report_account_flow_detail(账户流水钱包明细表)
82
+
83
+ | 字段 | 类型 | 说明 |
84
+ |------|------|------|
85
+ | `id` | Long | 自增主键 |
86
+ | `flowId` | Long | 关联主流水 |
87
+ | `walletId` | Long | 钱包类型(AccWalletIdEnum) |
88
+ | `flowType` | Integer | 交易类型 |
89
+ | `amount` | BigDecimal | 本钱包支付金额(转出类型取负值) |
90
+ | `walletBal` | BigDecimal | 本钱包可用余额 |
91
+ | `allWalletBal` | BigDecimal | 本钱包总余额(含冻结) |
92
+ | `frozenBalance` | BigDecimal | 冻结余额 |
93
+ | `payTime` | LocalDateTime | 支付时间 |