From 5fdc31c77cc346b89d72b2bfeda6ff964351e9b5 Mon Sep 17 00:00:00 2001 From: ouhaolan Date: Wed, 1 Apr 2026 08:59:38 +0800 Subject: [PATCH] =?UTF-8?q?1.=E8=B0=83=E8=AF=95ai?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- yudao-module-ydoyun/pom.xml | 1 + .../AiAssistantReportController.java | 40 ++++++++++++++ .../vo/AiAssistantReportSaveReqVO.java | 3 ++ .../AiAssistantReportMapper.java | 12 +++++ .../AiAssistantReportService.java | 8 +++ .../AiAssistantReportServiceImpl.java | 53 +++++++++++++++++++ .../service/reportpage/ReportPageService.java | 1 - yudao-server/pom.xml | 10 ++-- .../src/main/resources/application.yaml | 12 +++++ 10 files changed, 135 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 38c656d..7566bd1 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ yudao-module-infra yudao-module-bpm - yudao-module-report + yudao-module-ydoyun diff --git a/yudao-module-ydoyun/pom.xml b/yudao-module-ydoyun/pom.xml index e1a218f..3298c80 100644 --- a/yudao-module-ydoyun/pom.xml +++ b/yudao-module-ydoyun/pom.xml @@ -56,5 +56,6 @@ cn.iocoder.boot yudao-spring-boot-starter-test + \ No newline at end of file diff --git a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/controller/admin/aiassistantreport/AiAssistantReportController.java b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/controller/admin/aiassistantreport/AiAssistantReportController.java index 445da5e..f492415 100644 --- a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/controller/admin/aiassistantreport/AiAssistantReportController.java +++ b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/controller/admin/aiassistantreport/AiAssistantReportController.java @@ -2,11 +2,18 @@ package cn.iocoder.yudao.module.ydoyun.controller.admin.aiassistantreport; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; +import cn.iocoder.yudao.module.ydoyun.controller.admin.aiassistantreport.vo.AiAssistantReportDetailBatchSaveReqVO; +import cn.iocoder.yudao.module.ydoyun.controller.admin.aiassistantreport.vo.AiAssistantReportDetailRespVO; +import cn.iocoder.yudao.module.ydoyun.controller.admin.aiassistantreport.vo.AiAssistantReportDetailSaveItemVO; +import cn.iocoder.yudao.module.ydoyun.controller.admin.aiassistantreport.vo.AiAssistantReportDifyParseReqVO; import cn.iocoder.yudao.module.ydoyun.controller.admin.aiassistantreport.vo.AiAssistantReportPageReqVO; import cn.iocoder.yudao.module.ydoyun.controller.admin.aiassistantreport.vo.AiAssistantReportRespVO; import cn.iocoder.yudao.module.ydoyun.controller.admin.aiassistantreport.vo.AiAssistantReportSaveReqVO; import cn.iocoder.yudao.module.ydoyun.controller.admin.aiassistantreport.vo.ReportCountByDateVO; +import cn.iocoder.yudao.module.ydoyun.service.aiassistantreport.AiAssistantReportDetailService; import cn.iocoder.yudao.module.ydoyun.service.aiassistantreport.AiAssistantReportService; +import cn.iocoder.yudao.module.ydoyun.service.aiassistantreport.DailyReportDifyParseService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -29,6 +36,8 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; public class AiAssistantReportController { private final AiAssistantReportService aiAssistantReportService; + private final AiAssistantReportDetailService aiAssistantReportDetailService; + private final DailyReportDifyParseService dailyReportDifyParseService; @PostMapping("/save") @Operation(summary = "保存报告单据") @@ -78,4 +87,35 @@ public class AiAssistantReportController { @Parameter(description = "结束日期", required = true) @RequestParam("endDate") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate endDate) { return success(aiAssistantReportService.getReportCountByDate(reporterId, moduleCode, startDate, endDate)); } + + @DeleteMapping("/delete") + @Operation(summary = "删除本人「报告日期为当天」的一条记录(历史纠错)") + public CommonResult deleteMyReportToday(@Parameter(description = "主键", required = true) @RequestParam("id") Long id) { + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); + aiAssistantReportService.deleteMyReportToday(id, loginUserId); + return success(true); + } + + @GetMapping("/detail/list") + @Operation(summary = "按每日汇报主键查询详表(仅本人报告)") + public CommonResult> getDetailList( + @Parameter(description = "每日汇报主表 ID", required = true) @RequestParam("reportId") Long reportId) { + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); + return success(aiAssistantReportDetailService.listByReportId(reportId, loginUserId)); + } + + @PostMapping("/detail/save-batch") + @Operation(summary = "批量保存详表(全量替换:先删后插,与主表保存分步调用)") + public CommonResult saveDetailBatch(@Valid @RequestBody AiAssistantReportDetailBatchSaveReqVO reqVO) { + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); + aiAssistantReportDetailService.saveBatch(reqVO, loginUserId); + return success(true); + } + + @PostMapping("/dify-parse-diagnosis") + @Operation(summary = "Dify 智能解析报告正文为「AI经营诊断」详表行(不落库,仅返回列表)") + public CommonResult> difyParseDiagnosis( + @Valid @RequestBody AiAssistantReportDifyParseReqVO reqVO) { + return success(dailyReportDifyParseService.parseReportToDiagnosisRows(reqVO.getText())); + } } diff --git a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/controller/admin/aiassistantreport/vo/AiAssistantReportSaveReqVO.java b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/controller/admin/aiassistantreport/vo/AiAssistantReportSaveReqVO.java index 1995655..ba67480 100644 --- a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/controller/admin/aiassistantreport/vo/AiAssistantReportSaveReqVO.java +++ b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/controller/admin/aiassistantreport/vo/AiAssistantReportSaveReqVO.java @@ -14,6 +14,9 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ @Data public class AiAssistantReportSaveReqVO { + @Schema(description = "主键,传入则更新;不传则按报告人+模块编码+报告日期唯一,存在则更新否则新增") + private Long id; + @Schema(description = "模块名称(当前组件名称)", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank(message = "模块名称不能为空") private String moduleName; diff --git a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/dal/mysql/aiassistantreport/AiAssistantReportMapper.java b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/dal/mysql/aiassistantreport/AiAssistantReportMapper.java index f758301..821684d 100644 --- a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/dal/mysql/aiassistantreport/AiAssistantReportMapper.java +++ b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/dal/mysql/aiassistantreport/AiAssistantReportMapper.java @@ -38,6 +38,18 @@ public interface AiAssistantReportMapper extends BaseMapperX() + .eq(AiAssistantReportDO::getReporterId, reporterId) + .eq(AiAssistantReportDO::getModuleCode, moduleCode) + .eq(AiAssistantReportDO::getReportTime, reportTime) + .orderByDesc(AiAssistantReportDO::getId) + .last("LIMIT 1")); + } + /** * 查询指定范围内有报告的去重日期列表(用于日历展示) */ diff --git a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/aiassistantreport/AiAssistantReportService.java b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/aiassistantreport/AiAssistantReportService.java index c100546..f8783ba 100644 --- a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/aiassistantreport/AiAssistantReportService.java +++ b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/aiassistantreport/AiAssistantReportService.java @@ -73,4 +73,12 @@ public interface AiAssistantReportService { * @return 每日提交数量列表 */ List getReportCountByDate(Long reporterId, String moduleCode, LocalDate startDate, LocalDate endDate); + + /** + * 删除本人「报告日期为当天」的一条记录(用于历史列表纠错) + * + * @param id 主键 + * @param reporterId 当前登录用户 ID,须与记录一致 + */ + void deleteMyReportToday(Long id, Long reporterId); } diff --git a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/aiassistantreport/AiAssistantReportServiceImpl.java b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/aiassistantreport/AiAssistantReportServiceImpl.java index d19e076..1291a58 100644 --- a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/aiassistantreport/AiAssistantReportServiceImpl.java +++ b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/aiassistantreport/AiAssistantReportServiceImpl.java @@ -15,6 +15,10 @@ import javax.annotation.Resource; import java.time.LocalDate; import java.util.List; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.FORBIDDEN; +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; + /** * AI 决策助手报告单据 Service 实现类 * @@ -26,9 +30,38 @@ public class AiAssistantReportServiceImpl implements AiAssistantReportService { @Resource private AiAssistantReportMapper aiAssistantReportMapper; + @Resource + private AiAssistantReportDetailService aiAssistantReportDetailService; @Override public Long saveReport(AiAssistantReportSaveReqVO saveReqVO) { + // 显式指定 id:仅允许更新本人数据 + if (saveReqVO.getId() != null) { + AiAssistantReportDO existing = aiAssistantReportMapper.selectById(saveReqVO.getId()); + if (existing == null) { + throw exception(BAD_REQUEST); + } + if (!existing.getReporterId().equals(saveReqVO.getReporterId())) { + throw exception(BAD_REQUEST); + } + AiAssistantReportDO update = BeanUtils.toBean(saveReqVO, AiAssistantReportDO.class); + aiAssistantReportMapper.updateById(update); + return update.getId(); + } + // 同一报告人 + 模块编码 + 报告日:至多一条,存在则更新 + if (saveReqVO.getModuleCode() == null || saveReqVO.getModuleCode().isEmpty()) { + throw exception(BAD_REQUEST); + } + AiAssistantReportDO sameDay = aiAssistantReportMapper.selectByReporterModuleAndDate( + saveReqVO.getReporterId(), saveReqVO.getModuleCode(), saveReqVO.getReportTime()); + if (sameDay != null) { + sameDay.setModuleName(saveReqVO.getModuleName()); + sameDay.setReporter(saveReqVO.getReporter()); + sameDay.setReportContent(saveReqVO.getReportContent()); + sameDay.setScreenshotUrl(saveReqVO.getScreenshotUrl()); + aiAssistantReportMapper.updateById(sameDay); + return sameDay.getId(); + } AiAssistantReportDO entity = BeanUtils.toBean(saveReqVO, AiAssistantReportDO.class); aiAssistantReportMapper.insert(entity); return entity.getId(); @@ -61,4 +94,24 @@ public class AiAssistantReportServiceImpl implements AiAssistantReportService { public List getReportCountByDate(Long reporterId, String moduleCode, LocalDate startDate, LocalDate endDate) { return aiAssistantReportMapper.selectReportCountByDate(reporterId, moduleCode, startDate, endDate); } + + @Override + public void deleteMyReportToday(Long id, Long reporterId) { + if (id == null || reporterId == null) { + throw exception(BAD_REQUEST); + } + AiAssistantReportDO row = aiAssistantReportMapper.selectById(id); + if (row == null) { + throw exception(BAD_REQUEST); + } + if (!reporterId.equals(row.getReporterId())) { + throw exception(FORBIDDEN); + } + LocalDate today = LocalDate.now(); + if (row.getReportTime() == null || !today.equals(row.getReportTime())) { + throw exception(BAD_REQUEST); + } + aiAssistantReportDetailService.deleteByReportId(id); + aiAssistantReportMapper.deleteById(id); + } } diff --git a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/reportpage/ReportPageService.java b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/reportpage/ReportPageService.java index 4210c7e..c3b9b87 100644 --- a/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/reportpage/ReportPageService.java +++ b/yudao-module-ydoyun/src/main/java/cn/iocoder/yudao/module/ydoyun/service/reportpage/ReportPageService.java @@ -301,7 +301,6 @@ public class ReportPageService { // ---------- admin 直接查全部 ---------- if ("admin".equalsIgnoreCase(username)) { - if ("PINPAI".equals(table)) { sql.append("SELECT PPDM, PPMC FROM ").append(table); } else if ("KEHU".equals(table)) { diff --git a/yudao-server/pom.xml b/yudao-server/pom.xml index 446a958..3de7bf0 100644 --- a/yudao-server/pom.xml +++ b/yudao-server/pom.xml @@ -40,11 +40,11 @@ - - cn.iocoder.boot - yudao-module-report - ${revision} - + + + + + cn.iocoder.boot diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 707c188..e210a1f 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -352,6 +352,14 @@ debug: false # 衣朵云相关配置 ydoyun: + # 高德开放平台 Web 服务:天气查询(须申请「Web 服务」类型 Key) + # https://lbs.amap.com/api/webservice/guide/api/weatherinfo + amap: + weather: + key: 739e8376bc50a3bc182a0918bbaff1f1 + # 天气图标 URL 模板(默认相对路径,图标在「前端」public/weather-icons/*.png,与 OpenWeatherMap 命名一致) + # weather-icon-url-pattern: /weather-icons/{code}.png + # 若需直连外网 CDN,可改为:https://openweathermap.org/img/wn/{code}@2x.png mssqljdbc: report: api: @@ -370,4 +378,8 @@ ydoyun: pic-param: pic # Dify 应用中的图片参数名 pic-format: object # object=单对象 | array=数组 | id=仅 upload_file_id 字符串,若 AI 看不到图可切换尝试 image-payload-mode: both # both=同时传 inputs+files | inputs=只传 inputs.pic | files=只传顶层 files + # 每日汇报:正文解析为经营诊断 JSON(blocking) + daily-report-parse: + base-url: http://118.253.178.8:5001/v1 + api-key: app-aaqeCTv9ywLOIl4WvhD3P9xS