From 79e536aeca52b4960732e5254ed0e9cdf2919650 Mon Sep 17 00:00:00 2001 From: wangyu <823267011@qq.com> Date: Mon, 8 Jun 2026 10:11:33 +0800 Subject: [PATCH] =?UTF-8?q?oa=E6=9B=B4=E6=96=B0=E9=A1=B9=E7=9B=AE=E6=80=BB?= =?UTF-8?q?=E8=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oa/controller/SysOaProjectController.java | 16 + .../oa/service/ISysOaProjectService.java | 11 + .../service/impl/SysOaProjectServiceImpl.java | 54 ++ ruoyi-ui/src/api/oa/project.js | 18 + .../src/views/oa/project/overview/index.vue | 701 ++++++++++++++++++ 5 files changed, 800 insertions(+) create mode 100644 ruoyi-ui/src/views/oa/project/overview/index.vue diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/SysOaProjectController.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/SysOaProjectController.java index 895058b..374dd36 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/SysOaProjectController.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/controller/SysOaProjectController.java @@ -98,6 +98,22 @@ public class SysOaProjectController extends BaseController { return data == null ? R.fail("项目不存在") : R.ok(data); } + /** + * 项目总览统计卡片:总数 / 完成 / 未完成 / 逾期(仅含已绑定进度的项目) + */ + @GetMapping("/overview/stats") + public R> overviewStats(SysOaProjectBo bo) { + return R.ok(iSysOaProjectService.getOverviewStats(bo)); + } + + /** + * 项目总览列表:仅返回已绑定进度的项目 + */ + @GetMapping("/overview/list") + public TableDataInfo overviewList(SysOaProjectBo bo, PageQuery pageQuery) { + return iSysOaProjectService.queryOverviewPageList(bo, pageQuery); + } + /** * 获取项目管理详细信息 * diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/ISysOaProjectService.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/ISysOaProjectService.java index b2a69a9..5730740 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/ISysOaProjectService.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/ISysOaProjectService.java @@ -14,6 +14,7 @@ import java.math.BigDecimal; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Map; /** * 项目管理Service接口 @@ -108,4 +109,14 @@ public interface ISysOaProjectService { * 综合看板:项目详情 + 任务 + 进度主表 + 进度步骤(一次返回) */ OaProjectDashboardVo getProjectDashboard(Long projectId); + + /** + * 项目总览统计:总数 / 完成 / 未完成 / 逾期(仅统计已绑定进度的项目) + */ + Map getOverviewStats(SysOaProjectBo bo); + + /** + * 项目总览列表:仅返回已绑定进度(oa_project_schedule 有记录)的项目,分页 + */ + TableDataInfo queryOverviewPageList(SysOaProjectBo bo, PageQuery pageQuery); } diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/SysOaProjectServiceImpl.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/SysOaProjectServiceImpl.java index 6adc965..ba9ed0b 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/SysOaProjectServiceImpl.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/service/impl/SysOaProjectServiceImpl.java @@ -675,4 +675,58 @@ public class SysOaProjectServiceImpl implements ISysOaProjectService { return vo; } + /** + * 项目总览统计:总数 / 完成 / 未完成 / 逾期 + * 仅统计已绑定进度(oa_project_schedule 有记录)的项目 + */ + @Override + public Map getOverviewStats(SysOaProjectBo bo) { + List raw = queryList(bo == null ? new SysOaProjectBo() : bo); + Set withSchedule = findProjectIdsWithSchedule(); + List all = raw.stream() + .filter(p -> p.getProjectId() != null && withSchedule.contains(p.getProjectId())) + .collect(Collectors.toList()); + long total = all.size(); + long completed = 0L, undone = 0L, overdue = 0L; + Date today = new Date(); + for (SysOaProjectVo p : all) { + boolean done = "1".equals(p.getProjectStatus()); + if (done) { + completed++; + } else { + undone++; + if (p.getFinishTime() != null && p.getFinishTime().before(today)) { + overdue++; + } + } + } + Map r = new LinkedHashMap<>(); + r.put("total", total); + r.put("completed", completed); + r.put("undone", undone); + r.put("overdue", overdue); + return r; + } + + /** + * 项目总览列表:在常规分页查询基础上加 EXISTS 子查询, + * 仅返回已经在 oa_project_schedule 中建立进度的项目。 + */ + @Override + public TableDataInfo queryOverviewPageList(SysOaProjectBo bo, PageQuery pageQuery) { + QueryWrapper qw = buildAliasPQueryWrapper(bo); + qw.exists("SELECT 1 FROM oa_project_schedule sch WHERE sch.project_id = p.project_id AND sch.del_flag = '0'"); + Page result = baseMapper.selectVoPlus(pageQuery.build(), qw); + return TableDataInfo.build(result); + } + + private Set findProjectIdsWithSchedule() { + List all = oaProjectScheduleService.queryList(new OaProjectScheduleBo()); + if (all == null) return Collections.emptySet(); + return all.stream() + .map(OaProjectScheduleVo::getProjectId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + } diff --git a/ruoyi-ui/src/api/oa/project.js b/ruoyi-ui/src/api/oa/project.js index b1ccb1e..9d4f84b 100644 --- a/ruoyi-ui/src/api/oa/project.js +++ b/ruoyi-ui/src/api/oa/project.js @@ -161,4 +161,22 @@ export function getMaxCode (codeType) { url: '/oa/project/maxCode/' + codeType, method: 'get', }) +} + +/** 项目总览:4 项统计卡片(总数/完成/未完成/逾期) */ +export function getProjectOverviewStats (query) { + return request({ + url: '/oa/project/overview/stats', + method: 'get', + params: query + }) +} + +/** 项目总览:仅返回已绑定进度的项目分页列表 */ +export function listOverviewProject (query) { + return request({ + url: '/oa/project/overview/list', + method: 'get', + params: query + }) } \ No newline at end of file diff --git a/ruoyi-ui/src/views/oa/project/overview/index.vue b/ruoyi-ui/src/views/oa/project/overview/index.vue new file mode 100644 index 0000000..3a92ebf --- /dev/null +++ b/ruoyi-ui/src/views/oa/project/overview/index.vue @@ -0,0 +1,701 @@ + + + + +