Procházet zdrojové kódy

新增
1、新增须知模块
2、新增公章管理模块
BUGFIX
1、解决月度费用赠送部分计算错误问题

liangwenxuan před 2 týdny
rodič
revize
f38a320cf2
22 změnil soubory, kde provedl 871 přidání a 6 odebrání
  1. 9 0
      sql/mysql/notice.sql
  2. 12 0
      sql/mysql/system_common_seal.sql
  3. 3 0
      yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java
  4. 85 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/CommonSealController.java
  5. 104 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/JiashuNoticeController.java
  6. 23 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/JiashuNoticePageReqVO.java
  7. 27 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/JiashuNoticeRespVO.java
  8. 33 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/JiashuNoticeSaveReqVO.java
  9. 21 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/seal/CommonSealListReqVO.java
  10. 41 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/seal/CommonSealRespVO.java
  11. 32 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/seal/CommonSealSaveReqVO.java
  12. 51 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/biz/CommonSealDO.java
  13. 40 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/miniapp/JiashuNoticeDO.java
  14. 32 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/biz/CommonSealMapper.java
  15. 43 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/miniapp/JiashuNoticeMapper.java
  16. 55 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/CommonSealService.java
  17. 80 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/CommonSealServiceImpl.java
  18. 3 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyConsumerVouchersServiceImpl.java
  19. 27 5
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ExpenseOrderServiceImpl.java
  20. 64 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/miniapp/JiashuNoticeService.java
  21. 82 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/miniapp/JiashuNoticeServiceImpl.java
  22. 4 0
      yudao-server/src/main/resources/application.yaml

+ 9 - 0
sql/mysql/notice.sql

@@ -0,0 +1,9 @@
+DROP TABLE IF EXISTS `notice`;
+CREATE TABLE `notice`  (
+  `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `type` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '须知类型:APPOINTMENT或者VISIT',
+  `content` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '须知内容',
+  `tenant_id` bigint(20) NULL DEFAULT NULL COMMENT '机构id',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_type`(`type`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '须知表' ROW_FORMAT = Dynamic;

+ 12 - 0
sql/mysql/system_common_seal.sql

@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS `system_common_seal`;
+CREATE TABLE `system_common_seal`  (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
+  `type` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '类型',
+  `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '公章url',
+  `tenant_id` bigint(20) NULL DEFAULT NULL COMMENT '机构id',
+  `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
+  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+  `updater` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人',
+  `creator` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '公章管理' ROW_FORMAT = Dynamic;

+ 3 - 0
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java

@@ -330,6 +330,9 @@ public interface ErrorCodeConstants {
     ErrorCode VISIT_APPOINTMENT_NOT_FOUND = new ErrorCode(1_002_041_000, "探访预约记录不存在");
     ErrorCode VISIT_APPOINTMENT_CANCELED = new ErrorCode(1_002_041_001, "该预约已取消或已删除,无法重复取消");
 
+    // ========== 须知(家属小程序) 1-002-042-000 ==========
+    ErrorCode JIASHU_NOTICE_NOT_FOUND = new ErrorCode(1_002_042_000, "须知不存在");
+
     // ========== 建行支付相关 1-008-025-000 ==========
     ErrorCode EXPENSE_ORDER_PAY_AMOUNT_INVALID = new ErrorCode(1_008_025_000, "账单金额异常,无法发起支付,请联系院方核对账单!");
 

+ 85 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/CommonSealController.java

@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal.CommonSealListReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal.CommonSealRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal.CommonSealSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.biz.CommonSealDO;
+import cn.iocoder.yudao.module.system.service.biz.CommonSealService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * 管理后台 - 公章管理
+ *
+ * @author system
+ */
+@Tag(name = "管理后台 - 公章管理")
+@RestController
+@RequestMapping("/system/common-seal")
+@Validated
+public class CommonSealController {
+
+    @Resource
+    private CommonSealService commonSealService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建公章")
+    @TenantIgnore // 机构id 由前端传入
+    public CommonResult<Long> createSeal(@Valid @RequestBody CommonSealSaveReqVO createReqVO) {
+        return success(commonSealService.createSeal(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新公章")
+    @TenantIgnore
+    public CommonResult<Boolean> updateSeal(@Valid @RequestBody CommonSealSaveReqVO updateReqVO) {
+        commonSealService.updateSeal(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除公章")
+    @Parameter(name = "id", description = "公章编号", required = true, example = "1024")
+    @TenantIgnore
+    public CommonResult<Boolean> deleteSeal(@RequestParam("id") Long id) {
+        commonSealService.deleteSeal(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得公章")
+    @Parameter(name = "id", description = "公章编号", required = true, example = "1024")
+    @TenantIgnore
+    public CommonResult<CommonSealRespVO> getSeal(@RequestParam("id") Long id) {
+        CommonSealDO seal = commonSealService.getSeal(id);
+        return success(BeanUtils.toBean(seal, CommonSealRespVO.class));
+    }
+
+    @GetMapping("/list")
+    @Operation(summary = "获得公章列表")
+    @TenantIgnore // 机构id 前端可传,不传则默认当前租户
+    public CommonResult<List<CommonSealRespVO>> getSealList(@Valid CommonSealListReqVO listReqVO) {
+        List<CommonSealDO> list = commonSealService.getSealList(listReqVO);
+        return success(BeanUtils.toBean(list, CommonSealRespVO.class));
+    }
+
+}

+ 104 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/JiashuNoticeController.java

@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.JiashuNoticePageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.JiashuNoticeRespVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.JiashuNoticeSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.miniapp.JiashuNoticeDO;
+import cn.iocoder.yudao.module.system.service.miniapp.JiashuNoticeService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.annotation.security.PermitAll;
+import javax.validation.Valid;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+/**
+ * 管理后台 - 须知(yanglao-jiashu 数据源)
+ *
+ * @author system
+ */
+@Tag(name = "管理后台 - 须知")
+@RestController
+@RequestMapping("/jiashu/notice")
+@Validated
+public class JiashuNoticeController {
+
+    @Resource
+    private JiashuNoticeService jiashuNoticeService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建须知")
+    @PermitAll
+    @TenantIgnore
+    public CommonResult<Long> createNotice(@Valid @RequestBody JiashuNoticeSaveReqVO createReqVO) {
+        return success(jiashuNoticeService.createNotice(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新须知")
+    @PermitAll
+    @TenantIgnore
+    public CommonResult<Boolean> updateNotice(@Valid @RequestBody JiashuNoticeSaveReqVO updateReqVO) {
+        jiashuNoticeService.updateNotice(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除须知")
+    @Parameter(name = "id", description = "须知编号", required = true, example = "1024")
+    @PermitAll
+    @TenantIgnore
+    public CommonResult<Boolean> deleteNotice(@RequestParam("id") Long id) {
+        jiashuNoticeService.deleteNotice(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得须知")
+    @Parameter(name = "id", description = "须知编号", required = true, example = "1024")
+    @PermitAll
+    @TenantIgnore
+    public CommonResult<JiashuNoticeRespVO> getNotice(@RequestParam("id") Long id) {
+        JiashuNoticeDO notice = jiashuNoticeService.getNotice(id);
+        return success(BeanUtils.toBean(notice, JiashuNoticeRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得须知分页")
+    @PermitAll
+    @TenantIgnore
+    public CommonResult<PageResult<JiashuNoticeRespVO>> getNoticePage(@Valid JiashuNoticePageReqVO pageReqVO) {
+        PageResult<JiashuNoticeDO> pageResult = jiashuNoticeService.getNoticePage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, JiashuNoticeRespVO.class));
+    }
+
+    @GetMapping("/listByType")
+    @Operation(summary = "根据须知类型 + 机构id 查询须知列表")
+    @Parameter(name = "type", description = "须知类型:APPOINTMENT 或者 VISIT", required = true, example = "APPOINTMENT")
+    @Parameter(name = "tenantId", description = "机构id", required = true, example = "1024")
+    @PermitAll
+    @TenantIgnore
+    public CommonResult<List<JiashuNoticeRespVO>> getNoticeListByType(@RequestParam("type") String type,
+                                                                     @RequestParam("tenantId") Long tenantId) {
+        List<JiashuNoticeDO> list = jiashuNoticeService.getNoticeListByType(type, tenantId);
+        return success(BeanUtils.toBean(list, JiashuNoticeRespVO.class));
+    }
+
+}

+ 23 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/JiashuNoticePageReqVO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+/**
+ * 管理后台 - 须知分页 Request VO
+ *
+ * @author system
+ */
+@Schema(description = "管理后台 - 须知分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class JiashuNoticePageReqVO extends PageParam {
+
+    @Schema(description = "须知类型:APPOINTMENT 或者 VISIT", example = "APPOINTMENT")
+    private String type;
+
+}

+ 27 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/JiashuNoticeRespVO.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 管理后台 - 须知 Response VO
+ *
+ * @author system
+ */
+@Schema(description = "管理后台 - 须知 Response VO")
+@Data
+public class JiashuNoticeRespVO {
+
+    @Schema(description = "须知编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long id;
+
+    @Schema(description = "须知类型:APPOINTMENT 或者 VISIT", requiredMode = Schema.RequiredMode.REQUIRED, example = "APPOINTMENT")
+    private String type;
+
+    @Schema(description = "须知内容", requiredMode = Schema.RequiredMode.REQUIRED)
+    private String content;
+
+    @Schema(description = "机构id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long tenantId;
+
+}

+ 33 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/JiashuNoticeSaveReqVO.java

@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 管理后台 - 须知新增/修改 Request VO
+ *
+ * @author system
+ */
+@Schema(description = "管理后台 - 须知新增/修改 Request VO")
+@Data
+public class JiashuNoticeSaveReqVO {
+
+    @Schema(description = "须知编号,修改时必传", example = "1024")
+    private Long id;
+
+    @Schema(description = "须知类型:APPOINTMENT 或者 VISIT", requiredMode = Schema.RequiredMode.REQUIRED, example = "APPOINTMENT")
+    @NotEmpty(message = "须知类型不能为空")
+    private String type;
+
+    @Schema(description = "须知内容", requiredMode = Schema.RequiredMode.REQUIRED)
+    @NotEmpty(message = "须知内容不能为空")
+    private String content;
+
+    @Schema(description = "机构id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "机构id不能为空")
+    private Long tenantId;
+
+}

+ 21 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/seal/CommonSealListReqVO.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+/**
+ * 管理后台 - 公章列表 Request VO
+ *
+ * @author system
+ */
+@Schema(description = "管理后台 - 公章列表 Request VO")
+@Data
+public class CommonSealListReqVO {
+
+    @Schema(description = "类型", example = "CONTRACT")
+    private String type;
+
+    @Schema(description = "机构id,不传则默认当前登录租户", example = "1024")
+    private Long tenantId;
+
+}

+ 41 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/seal/CommonSealRespVO.java

@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 管理后台 - 公章 Response VO
+ *
+ * @author system
+ */
+@Schema(description = "管理后台 - 公章 Response VO")
+@Data
+public class CommonSealRespVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long id;
+
+    @Schema(description = "类型", example = "CONTRACT")
+    private String type;
+
+    @Schema(description = "公章url", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://xxx.com/seal.png")
+    private String url;
+
+    @Schema(description = "机构id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long tenantId;
+
+    @Schema(description = "创建时间")
+    private LocalDateTime createTime;
+
+    @Schema(description = "更新时间")
+    private LocalDateTime updateTime;
+
+    @Schema(description = "创建人")
+    private String creator;
+
+    @Schema(description = "更新人")
+    private String updater;
+
+}

+ 32 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/seal/CommonSealSaveReqVO.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * 管理后台 - 公章新增/修改 Request VO
+ *
+ * @author system
+ */
+@Schema(description = "管理后台 - 公章新增/修改 Request VO")
+@Data
+public class CommonSealSaveReqVO {
+
+    @Schema(description = "id,修改时必传", example = "1024")
+    private Long id;
+
+    @Schema(description = "类型", example = "CONTRACT")
+    private String type;
+
+    @Schema(description = "公章url", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://xxx.com/seal.png")
+    @NotEmpty(message = "公章url不能为空")
+    private String url;
+
+    @Schema(description = "机构id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    @NotNull(message = "机构id不能为空")
+    private Long tenantId;
+
+}

+ 51 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/biz/CommonSealDO.java

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.system.dal.dataobject.biz;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseNoDeleteDO;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+/**
+ * 公章管理 DO
+ *
+ * 对应 system_common_seal 表(无 deleted 字段,因此继承 {@link BaseNoDeleteDO})
+ *
+ * @author system
+ */
+@TableName("system_common_seal")
+@KeySequence("system_common_seal_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class CommonSealDO extends BaseNoDeleteDO {
+
+    /**
+     * id
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 类型
+     */
+    private String type;
+
+    /**
+     * 公章url
+     */
+    private String url;
+
+    /**
+     * 机构id
+     */
+    private Long tenantId;
+
+}

+ 40 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/miniapp/JiashuNoticeDO.java

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.system.dal.dataobject.miniapp;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 须知 DO(yanglao-jiashu 数据源)
+ *
+ * 对应 yanglao-jiashu 库中的 notice 表
+ *
+ * @author system
+ */
+@TableName("notice")
+@Data
+public class JiashuNoticeDO {
+
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 须知类型:APPOINTMENT 或者 VISIT
+     */
+    private String type;
+
+    /**
+     * 须知内容
+     */
+    private String content;
+
+    /**
+     * 机构id
+     */
+    private Long tenantId;
+
+}

+ 32 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/biz/CommonSealMapper.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.system.dal.mysql.biz;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal.CommonSealListReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.biz.CommonSealDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 公章管理 Mapper
+ *
+ * @author system
+ */
+@Mapper
+public interface CommonSealMapper extends BaseMapperX<CommonSealDO> {
+
+    /**
+     * 查询公章列表
+     *
+     * @param reqVO 查询条件
+     * @return 公章列表
+     */
+    default List<CommonSealDO> selectSealList(CommonSealListReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<CommonSealDO>()
+                .eqIfPresent(CommonSealDO::getType, reqVO.getType())
+                .eqIfPresent(CommonSealDO::getTenantId, reqVO.getTenantId())
+                .orderByDesc(CommonSealDO::getId));
+    }
+
+}

+ 43 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/miniapp/JiashuNoticeMapper.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.system.dal.mysql.miniapp;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.JiashuNoticePageReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.miniapp.JiashuNoticeDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 须知 Mapper(yanglao-jiashu 数据源)
+ *
+ * 注意:notice 位于 yanglao-jiashu 数据源,调用方需自行切换 @DS("miniapp")
+ *
+ * @author system
+ */
+@Mapper
+public interface JiashuNoticeMapper extends BaseMapperX<JiashuNoticeDO> {
+
+    default PageResult<JiashuNoticeDO> selectPage(JiashuNoticePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<JiashuNoticeDO>()
+                .eqIfPresent(JiashuNoticeDO::getType, reqVO.getType())
+                .eqIfPresent(JiashuNoticeDO::getTenantId, reqVO.getTenantId())
+                .orderByDesc(JiashuNoticeDO::getId));
+    }
+
+    /**
+     * 根据须知类型 + 机构id 查询须知列表
+     *
+     * @param type     须知类型:APPOINTMENT 或者 VISIT
+     * @param tenantId 机构id
+     * @return 须知列表
+     */
+    default List<JiashuNoticeDO> selectListByTypeAndTenantId(String type, Long tenantId) {
+        return selectList(new LambdaQueryWrapperX<JiashuNoticeDO>()
+                .eq(JiashuNoticeDO::getType, type)
+                .eq(JiashuNoticeDO::getTenantId, tenantId)
+                .orderByDesc(JiashuNoticeDO::getId));
+    }
+
+}

+ 55 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/CommonSealService.java

@@ -0,0 +1,55 @@
+package cn.iocoder.yudao.module.system.service.biz;
+
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal.CommonSealListReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal.CommonSealSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.biz.CommonSealDO;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 公章管理 Service 接口
+ *
+ * @author system
+ */
+public interface CommonSealService {
+
+    /**
+     * 创建公章
+     *
+     * @param createReqVO 创建信息
+     * @return 公章编号
+     */
+    Long createSeal(@Valid CommonSealSaveReqVO createReqVO);
+
+    /**
+     * 更新公章
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateSeal(@Valid CommonSealSaveReqVO updateReqVO);
+
+    /**
+     * 删除公章
+     *
+     * @param id 公章编号
+     */
+    void deleteSeal(Long id);
+
+    /**
+     * 获得公章
+     *
+     * @param id 公章编号
+     * @return 公章
+     */
+    CommonSealDO getSeal(Long id);
+
+    /**
+     * 获得公章列表
+     *
+     * @param listReqVO 查询条件
+     * @return 公章列表
+     */
+    List<CommonSealDO> getSealList(CommonSealListReqVO listReqVO);
+
+}

+ 80 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/CommonSealServiceImpl.java

@@ -0,0 +1,80 @@
+package cn.iocoder.yudao.module.system.service.biz;
+
+import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal.CommonSealListReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.seal.CommonSealSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.biz.CommonSealDO;
+import cn.iocoder.yudao.module.system.dal.mysql.biz.CommonSealMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.COMMON_NOT_FOUND;
+
+/**
+ * 公章管理 Service 实现类
+ *
+ * @author system
+ */
+@Service
+@Validated
+public class CommonSealServiceImpl implements CommonSealService {
+
+    @Resource
+    private CommonSealMapper commonSealMapper;
+
+    @Override
+    public Long createSeal(CommonSealSaveReqVO createReqVO) {
+        // 插入
+        CommonSealDO seal = BeanUtils.toBean(createReqVO, CommonSealDO.class);
+        if (seal.getTenantId() == null) {
+            seal.setTenantId(TenantContextHolder.getTenantId());
+        }
+        seal.setId(null);
+        commonSealMapper.insert(seal);
+        // 返回
+        return seal.getId();
+    }
+
+    @Override
+    public void updateSeal(CommonSealSaveReqVO updateReqVO) {
+        // 校验存在
+        validateSealExists(updateReqVO.getId());
+        // 更新
+        CommonSealDO updateObj = BeanUtils.toBean(updateReqVO, CommonSealDO.class);
+        commonSealMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteSeal(Long id) {
+        // 校验存在
+        validateSealExists(id);
+        // 删除
+        commonSealMapper.deleteById(id);
+    }
+
+    @Override
+    public CommonSealDO getSeal(Long id) {
+        return commonSealMapper.selectById(id);
+    }
+
+    @Override
+    public List<CommonSealDO> getSealList(CommonSealListReqVO listReqVO) {
+        // 机构id 前端可传,不传则默认当前租户
+        if (listReqVO.getTenantId() == null) {
+            listReqVO.setTenantId(TenantContextHolder.getTenantId());
+        }
+        return commonSealMapper.selectSealList(listReqVO);
+    }
+
+    private void validateSealExists(Long id) {
+        if (commonSealMapper.selectById(id) == null) {
+            throw ServiceExceptionUtil.exception(COMMON_NOT_FOUND);
+        }
+    }
+
+}

+ 3 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyConsumerVouchersServiceImpl.java

@@ -79,7 +79,9 @@ public class ElderlyConsumerVouchersServiceImpl implements ElderlyConsumerVouche
     @Transactional
     public void delete(Long id) {
         validateExists(id);
-        ExpenseOrderItemDO expenseOrderItemDO = expenseOrderItemMapper.selectOne(new LambdaQueryWrapperX<ExpenseOrderItemDO>().eq(ExpenseOrderItemDO::getSourceExpenseItemId, id));
+        ExpenseOrderItemDO expenseOrderItemDO = expenseOrderItemMapper.selectOne(new LambdaQueryWrapperX<ExpenseOrderItemDO>()
+                .eq(ExpenseOrderItemDO::getSourceExpenseItemId, id)
+                .eq(ExpenseOrderItemDO::getExpenseSource,BusinessConstants.CONSUMER_VOUCHER));
         if(expenseOrderItemDO != null){
             ExpenseOrderDO expenseOrderDO = expenseOrderMapper.selectById(expenseOrderItemDO.getExpenseOrderId());
             if(expenseOrderDO != null){

+ 27 - 5
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ExpenseOrderServiceImpl.java

@@ -4048,12 +4048,34 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
                 respVO.setExpenseSource(BusinessConstants.EXPENSE_ITEM);
                 respVO.setSourceExpenseItemId(item.getId());
                 long monthDays = ChronoUnit.DAYS.between(monthStart, monthEnd) + 1;
-                // 按次(inSequence)收费且仅限月度费用项:固定月金额,不乘天数、不按实际在住区间比例折算
-                if ("inSequence".equals(chargeTypeMap.get(item.getItemId()))
-                        && item.getIsMonthlyExpense() != null && item.getIsMonthlyExpense() == 1) {
+                // 赠送(阶段)费用:与月度费用一样按 chargeType 处理,金额统一使用实际金额 actualAmount
+                boolean isFreeGiftItem = BooleanEnum.TRUE.getValue().equals(item.getIsFreeGift());
+                String chargeType = chargeTypeMap.get(item.getItemId());
+                // 按次(inSequence)收费:月度费用项与赠送费用项均为固定月金额,不乘天数、不按实际在住区间比例折算
+                if ("inSequence".equals(chargeType)
+                        && (isFreeGiftItem || (item.getIsMonthlyExpense() != null && item.getIsMonthlyExpense() == 1))) {
                     respVO.setPrice(item.getActualAmount());
-                    respVO.setTotalAmount(item.getTotalAmount());
-                } else if (item.getIsDayCalculate() == 1){
+                    respVO.setTotalAmount(isFreeGiftItem ? item.getActualAmount() : item.getTotalAmount());
+                } else if (isFreeGiftItem) {
+                    BigDecimal giftAmount = item.getActualAmount();
+                    if (Integer.valueOf(1).equals(item.getIsDayCalculate())) {
+                        // 按天计费:日价 * 当月天数
+                        respVO.setPrice(giftAmount);
+                        respVO.setTotalAmount(giftAmount.multiply(new BigDecimal(monthDays)));
+                    } else {
+                        // 非整月(离住/返院/合同到期等):按实际在住区间比例折算
+                        if (finalActualStart.isAfter(monthStart) || finalActualEnd.isBefore(monthEnd)) {
+                            long actualDays = ChronoUnit.DAYS.between(finalActualStart, finalActualEnd) + 1;
+                            if (monthDays > 0 && actualDays > 0) {
+                                BigDecimal ratio = BigDecimal.valueOf(actualDays)
+                                        .divide(BigDecimal.valueOf(monthDays), 8, RoundingMode.HALF_UP);
+                                giftAmount = giftAmount.multiply(ratio).setScale(2, RoundingMode.HALF_UP);
+                            }
+                        }
+                        respVO.setPrice(giftAmount);
+                        respVO.setTotalAmount(giftAmount);
+                    }
+                } else if (Integer.valueOf(1).equals(item.getIsDayCalculate())){
                     respVO.setPrice(item.getActualAmount());
                     respVO.setTotalAmount(respVO.getPrice().multiply(new BigDecimal(monthDays)));
                 }else {

+ 64 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/miniapp/JiashuNoticeService.java

@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.system.service.miniapp;
+
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.JiashuNoticePageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.JiashuNoticeSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.miniapp.JiashuNoticeDO;
+
+import java.util.List;
+
+/**
+ * 须知 Service(yanglao-jiashu 数据源)
+ *
+ * @author system
+ */
+public interface JiashuNoticeService {
+
+    /**
+     * 创建须知
+     *
+     * @param createReqVO 创建信息
+     * @return 须知编号
+     */
+    Long createNotice(JiashuNoticeSaveReqVO createReqVO);
+
+    /**
+     * 更新须知
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateNotice(JiashuNoticeSaveReqVO updateReqVO);
+
+    /**
+     * 删除须知
+     *
+     * @param id 须知编号
+     */
+    void deleteNotice(Long id);
+
+    /**
+     * 获得须知
+     *
+     * @param id 须知编号
+     * @return 须知
+     */
+    JiashuNoticeDO getNotice(Long id);
+
+    /**
+     * 获得须知分页
+     *
+     * @param pageReqVO 分页查询条件
+     * @return 须知分页
+     */
+    PageResult<JiashuNoticeDO> getNoticePage(JiashuNoticePageReqVO pageReqVO);
+
+    /**
+     * 根据须知类型 + 机构id 查询须知列表
+     *
+     * @param type     须知类型:APPOINTMENT 或者 VISIT
+     * @param tenantId 机构id
+     * @return 须知列表
+     */
+    List<JiashuNoticeDO> getNoticeListByType(String type, Long tenantId);
+
+}

+ 82 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/miniapp/JiashuNoticeServiceImpl.java

@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.module.system.service.miniapp;
+
+import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.JiashuNoticePageReqVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.JiashuNoticeSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.miniapp.JiashuNoticeDO;
+import cn.iocoder.yudao.module.system.dal.mysql.miniapp.JiashuNoticeMapper;
+import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 须知 Service 实现(yanglao-jiashu 数据源)
+ *
+ * @author system
+ */
+@Service
+@DS("miniapp")
+public class JiashuNoticeServiceImpl implements JiashuNoticeService {
+
+    @Resource
+    private JiashuNoticeMapper jiashuNoticeMapper;
+
+    @Override
+    public Long createNotice(JiashuNoticeSaveReqVO createReqVO) {
+        JiashuNoticeDO notice = BeanUtils.toBean(createReqVO, JiashuNoticeDO.class);
+        jiashuNoticeMapper.insert(notice);
+        return notice.getId();
+    }
+
+    @Override
+    public void updateNotice(JiashuNoticeSaveReqVO updateReqVO) {
+        // 校验是否存在
+        validateNoticeExists(updateReqVO.getId());
+        // 更新须知
+        JiashuNoticeDO updateObj = BeanUtils.toBean(updateReqVO, JiashuNoticeDO.class);
+        if(updateObj.getTenantId() == null){
+            updateObj.setId(null);
+            jiashuNoticeMapper.insert(updateObj);
+        }else {
+            jiashuNoticeMapper.updateById(updateObj);
+        }
+    }
+
+    @Override
+    public void deleteNotice(Long id) {
+        // 校验是否存在
+        validateNoticeExists(id);
+        // 删除须知
+        jiashuNoticeMapper.deleteById(id);
+    }
+
+    @Override
+    public JiashuNoticeDO getNotice(Long id) {
+        return jiashuNoticeMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<JiashuNoticeDO> getNoticePage(JiashuNoticePageReqVO pageReqVO) {
+        return jiashuNoticeMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<JiashuNoticeDO> getNoticeListByType(String type, Long tenantId) {
+        return jiashuNoticeMapper.selectListByTypeAndTenantId(type, tenantId);
+    }
+
+    private void validateNoticeExists(Long id) {
+        if (id == null) {
+            return;
+        }
+        if (jiashuNoticeMapper.selectById(id) == null) {
+            throw new ServiceException(ErrorCodeConstants.JIASHU_NOTICE_NOT_FOUND);
+        }
+    }
+
+}

+ 4 - 0
yudao-server/src/main/resources/application.yaml

@@ -265,6 +265,10 @@ yudao:
       - /admin-api/elderly-build-floor-order-food/page
       - /admin-api/system/tenant/get
       - /admin-api/system/auth/login-by-user-id
+      - /admin-api/jiashu/notice/create
+      - /admin-api/jiashu/notice/update
+      - /admin-api/jiashu/notice/get
+      - /admin-api/jiashu/notice/listByType
     ignore-tables:
       - system_tenant
       - system_groups