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