Files
fad_oa/ruoyi-oa/src/main/resources/mapper/oa/SysOaTaskMapper.xml
王文昊 50f3f15f48 feat(项目看板): 新增项目综合看板功能
新增项目综合看板功能,聚合展示项目、任务、进度主表和步骤数据
- 新增后端聚合接口 GET /oa/project/dashboard/{projectId}
- 新增前端看板页面,包含项目列表、任务表格和进度导图
- 优化思维导图组件,支持看板模式下的紧凑展示
- 新增进度明细表格视图和状态图例
- 实现任务与进度步骤的关联展示
- 添加项目模糊搜索功能
2026-04-15 17:19:56 +08:00

549 lines
22 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.oa.mapper.SysOaTaskMapper">
<resultMap type="com.ruoyi.oa.domain.vo.SysOaTaskVo" id="SysOaTaskResult">
<result property="taskId" column="task_id"/>
<result property="projectId" column="project_id"/>
<result property="taskTitle" column="task_title"/>
<result property="taskType" column="task_type"/>
<result property="taskGrade" column="task_grade"/>
<result property="collaborator" column="collaborator"/>
<result property="beginTime" column="begin_time"/>
<result property="finishTime" column="finish_time"/>
<result property="content" column="content"/>
<result property="remark" column="remark"/>
<result property="state" column="state"/>
<result property="status" column="status"/>
<result property="taskRank" column="task_rank"/>
<result property="ownRank" column="own_rank"/>
<result property="timeGap" column="time_gap"/>
<result property="tempTime" column="temp_time"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="completedTime" column="completed_time"/>
<result property="createUserNickName" column="createUserNickName"/>
<result property="workerNickName" column="workerNickName"/>
<result property="postponements" column="postponements"/>
<result property="accessory" column="accessory"/>
<result property="projectName" column="project_name"/>
<result property="projectNum" column="project_num"/>
<result property="overDays" column="overDays"/>
<result property="itemId" column="item_id"/>
<result property="files" column="files"/>
<result property="trackId" column="track_id"/>
<collection property="taskItemVoList"
ofType="com.ruoyi.oa.domain.vo.SysOaTaskItemVo"
javaType="list"
select="selectTaskItemsByTaskId"
column="task_id"/>
</resultMap>
<!--先删除数据-->
<delete id="deleteSysOaTaskByProjectId" parameterType="Long">
delete from sys_oa_task where project_id = #{projectId}
</delete>
<select id="selectListVoPage" resultType="com.ruoyi.oa.domain.vo.SysOaTaskVo">
SELECT sot.task_id,
sot.project_id,
sot.create_user_id,
sot.worker_id,
sot.task_title,
sot.task_type,
sot.task_grade,
sot.collaborator,
sot.finish_time,
sot.temp_time,
sot.begin_time,
sot.origin_finish_time,
sot.postponements,
sot.completed_time,
sot.rank_number,
sot.remark,
sot.task_rank,
sot.state,
sot.time_gap,
sot.status,
sot.accessory,
sot.create_by,
sot.create_time,
sot.update_by,
sot.update_time,
sot.del_flag,
sot.own_rank,
sot.track_id,
stepAgg.tab_node AS tabNode,
stepAgg.first_level_node AS firstLevelNode,
stepAgg.second_level_node AS secondLevelNode,
sop.project_name,
sop.project_num,
sop.project_code,
su1.nick_name AS createUserNickName,
su2.nick_name AS workerNickName,
sd.dept_name AS deptName,
IF(
sot.completed_time IS NULL,
IF(
-- 子查询取第一个未完成 item 的 end_time
(
SELECT a.end_time
FROM sys_oa_task_item a
WHERE a.task_id = sot.task_id
AND a.completed_time IS NULL
LIMIT 1
) IS NOT NULL,
-- 如果子查询有值,就用它来算超期天数
DATEDIFF(
NOW(),
(
SELECT a.end_time
FROM sys_oa_task_item a
WHERE a.task_id = sot.task_id
AND a.completed_time IS NULL
LIMIT 1
)
),
-- 否则就退回到 sot.finish_time如果它也可能为 NULL可再加一层 IF 或 COALESCE
DATEDIFF(NOW(), sot.finish_time)
),
0
) AS overDays
FROM sys_oa_task sot
LEFT JOIN sys_user su1 ON su1.user_id = sot.create_user_id
LEFT JOIN sys_user su2 ON su2.user_id = sot.worker_id
LEFT JOIN sys_oa_project sop ON sop.project_id = sot.project_id
LEFT JOIN sys_dept sd ON sd.dept_id = su2.dept_id
LEFT JOIN oa_project_schedule_step stepAgg ON stepAgg.track_id = sot.track_id
${ew.getCustomSqlSegment}
</select>
<select id="selectDetailVoById" resultMap="SysOaTaskResult">
SELECT sot.task_id,
sot.project_id,
sot.create_user_id,
sot.worker_id,
sot.task_title,
sot.task_type,
sot.task_grade,
sot.accessory,
sot.track_id,
COALESCE(
sot.finish_time,
(SELECT a.end_time
FROM sys_oa_task_item a
WHERE a.task_id = sot.task_id
AND a.completed_time IS NULL
LIMIT 1)
) AS finish_time,
COALESCE(
sot.temp_time,
(SELECT a.temp_time
FROM sys_oa_task_item a
WHERE a.task_id = sot.task_id
AND a.completed_time IS NULL
LIMIT 1)
) AS temp_time,
sot.begin_time,
sot.origin_finish_time,
sot.postponements,
sot.completed_time,
sot.content,
su1.nick_name AS createUserNickName,
su2.nick_name AS workerNickName,
sot.rank_number,
sot.remark,
sot.task_rank,
sot.state,
sot.time_gap,
sot.status,
sot.create_by,
sot.create_time,
sot.update_by,
sot.update_time,
sot.del_flag,
sot.own_rank,
sop.project_name,
sop.project_num,
CASE
WHEN sot.completed_time IS NULL
THEN DATEDIFF(
NOW(),
COALESCE(
sot.finish_time,
(SELECT a.end_time
FROM sys_oa_task_item a
WHERE a.task_id = sot.task_id
AND a.completed_time IS NULL
LIMIT 1)
)
)
ELSE 0
END AS overDays
FROM sys_oa_task sot
LEFT JOIN sys_user su1 ON su1.user_id = sot.create_user_id
LEFT JOIN sys_user su2 ON su2.user_id = sot.worker_id
LEFT JOIN sys_oa_project sop ON sop.project_id = sot.project_id
WHERE sot.task_id = #{taskId}
AND sot.del_flag = '0'
</select>
<!-- 嵌套查询根据任务ID获取报工单元列表 -->
<select id="selectTaskItemsByTaskId" resultType="com.ruoyi.oa.domain.vo.SysOaTaskItemVo">
SELECT soti.item_id,
soti.content,
soti.sign_time,
soti.status,
soti.begin_time,
soti.completed_time,
soti.end_time,
soti.remark,
soti.files
FROM sys_oa_task_item soti
WHERE soti.task_id = #{task_id}
AND soti.del_flag = '0'
ORDER BY soti.create_time DESC
</select>
<!-- 绩效报告:按用户 + 时间范围查询任务明细(包含 task_item 子项) -->
<select id="selectPerformanceTaskList" resultMap="SysOaTaskResult">
SELECT sot.task_id,
sot.project_id,
sot.create_user_id,
sot.worker_id,
sot.task_title,
sot.task_type,
sot.task_grade,
sot.collaborator,
sot.finish_time,
sot.temp_time,
sot.begin_time,
sot.origin_finish_time,
sot.postponements,
sot.completed_time,
sot.rank_number,
sot.remark,
sot.task_rank,
sot.state,
sot.time_gap,
sot.status,
sot.accessory,
sot.create_by,
sot.create_time,
sot.update_by,
sot.update_time,
sot.del_flag,
sot.own_rank,
sot.track_id,
stepAgg.tab_node AS tabNode,
stepAgg.first_level_node AS firstLevelNode,
stepAgg.second_level_node AS secondLevelNode,
sop.project_name,
sop.project_num,
sop.project_code,
su1.nick_name AS createUserNickName,
su2.nick_name AS workerNickName,
sd.dept_name AS deptName,
IF(
sot.completed_time IS NULL,
IF(
(
SELECT a.end_time
FROM sys_oa_task_item a
WHERE a.task_id = sot.task_id
AND a.completed_time IS NULL
LIMIT 1
) IS NOT NULL,
DATEDIFF(
NOW(),
(
SELECT a.end_time
FROM sys_oa_task_item a
WHERE a.task_id = sot.task_id
AND a.completed_time IS NULL
LIMIT 1
)
),
DATEDIFF(NOW(), sot.finish_time)
),
0
) AS overDays
FROM sys_oa_task sot
LEFT JOIN sys_user su1 ON su1.user_id = sot.create_user_id
LEFT JOIN sys_user su2 ON su2.user_id = sot.worker_id
LEFT JOIN sys_oa_project sop ON sop.project_id = sot.project_id
LEFT JOIN sys_dept sd ON sd.dept_id = su2.dept_id
LEFT JOIN oa_project_schedule_step stepAgg ON stepAgg.track_id = sot.track_id
WHERE sot.del_flag = '0'
AND (
sot.create_user_id = #{userId}
OR sot.worker_id = #{userId}
OR EXISTS (
SELECT 1 FROM sys_oa_task_user sotu
WHERE sotu.task_id = sot.task_id
AND sotu.user_id = #{userId}
AND sotu.del_flag = 0
)
)
AND (
(COALESCE(sot.begin_time, sot.create_time) &lt;= #{endDate}
AND COALESCE(sot.finish_time, sot.temp_time, sot.completed_time, sot.create_time) &gt;= #{startDate})
OR (sot.create_time BETWEEN #{startDate} AND #{endDate})
OR (sot.completed_time BETWEEN #{startDate} AND #{endDate})
)
ORDER BY sot.create_time DESC
</select>
<select id="getMonthlyData"
parameterType="java.lang.String"
resultType="com.ruoyi.oa.domain.UserMonthlyData">
SELECT
-- 员工昵称
su.nick_name AS nickName,
-- 拼接多个项目名称
GROUP_CONCAT(DISTINCT sop.project_name SEPARATOR ',') AS projectName,
-- 计算 totalTasks
(
-- 1) status=0 属于当月 => 加1
SUM(
CASE
WHEN sot.status = 0
AND DATE_FORMAT(sot.begin_time, '%Y-%m') = #{month}
THEN 1
ELSE 0
END
)
+
-- 2) status=1 => 统计符合当月的子记录数量
COUNT(
CASE
WHEN sot.status = 1
AND DATE_FORMAT(soti.begin_time, '%Y-%m') = #{month}
THEN soti.item_id
END
)
) AS totalTasks,
-- 计算 completedTasks
(
-- status=0 当月 completed_time非空 => +1
SUM(
CASE
WHEN sot.status = 0
AND DATE_FORMAT(sot.begin_time, '%Y-%m') = #{month}
AND sot.completed_time IS NOT NULL
THEN 1
ELSE 0
END
)
+
-- status=1 => 统计子记录当月 且 sign_time非空
COUNT(
CASE
WHEN sot.status = 1
AND DATE_FORMAT(soti.begin_time, '%Y-%m') = #{month}
AND soti.sign_time IS NOT NULL
THEN soti.item_id
END
)
) AS completedTasks,
-- 计算 delayedTimes
(
-- status=0 当月 => 累加 sot.postponements
SUM(
CASE
WHEN sot.status = 0
AND DATE_FORMAT(sot.begin_time, '%Y-%m') = #{month}
THEN sot.postponements
ELSE 0
END
)
+
-- status=1 当月(子记录) => 同样加上 sot.postponements
SUM(
CASE
WHEN sot.status = 1
AND DATE_FORMAT(soti.begin_time, '%Y-%m') = #{month}
THEN sot.postponements
ELSE 0
END
)
) AS delayedTimes
FROM sys_oa_task sot
LEFT JOIN sys_oa_task_item soti
ON soti.task_id = sot.task_id
LEFT JOIN sys_user su
ON su.user_id = sot.worker_id
LEFT JOIN sys_oa_project sop
ON sop.project_id = sot.project_id
-- 只按用户分组 => 每个nickName合并为一行
GROUP BY su.user_id
</select>
<select id="queryPageListDocument" resultType="com.ruoyi.oa.domain.vo.SysOaTaskVo">
SELECT
sot.task_id,
sot.project_id,
sot.create_user_id,
sot.worker_id,
sot.task_title,
sot.task_type,
sot.task_grade,
sot.collaborator,
COALESCE(sot.finish_time, soti.end_time) AS finish_time,
COALESCE(sot.temp_time, soti.temp_time) AS temp_time,
sot.begin_time,
sot.origin_finish_time,
sot.postponements,
sot.completed_time,
sot.content,
sot.accessory,
sot.rank_number,
sot.remark,
sot.task_rank,
sot.state,
sot.time_gap,
sot.status,
sot.create_by,
sot.create_time,
sot.update_by,
sot.update_time,
sot.del_flag,
sot.own_rank,
sop.project_name,
soti.item_id,
sop.project_num,
su1.nick_name AS createUserNickName,
su2.nick_name AS workerNickName,
CASE
WHEN sot.completed_time IS NULL
THEN DATEDIFF(NOW(), COALESCE(sot.finish_time, soti.end_time))
ELSE 0
END AS overDays,
soti.files
FROM sys_oa_task_user sotu
left join sys_oa_task sot on sot.task_id = sotu.task_id
LEFT JOIN sys_user su1 ON su1.user_id = sot.create_user_id
LEFT JOIN sys_user su2 ON su2.user_id = sot.worker_id
LEFT JOIN sys_oa_project sop ON sop.project_id = sot.project_id
LEFT JOIN sys_oa_task_item soti
ON soti.task_id = sot.task_id
AND soti.completed_time IS NULL
${ew.getCustomSqlSegment}
</select>
<select id="listDocumentProject" resultType="com.ruoyi.oa.domain.vo.SysOaTaskVo">
SELECT
sot.create_user_id,
sot.worker_id,
sop.accessory,
su1.nick_name AS createUserNickName,
su2.nick_name AS workerNickName,
soti.files
FROM sys_oa_task sot
LEFT JOIN sys_user su1 ON su1.user_id = sot.create_user_id
LEFT JOIN sys_user su2 ON su2.user_id = sot.worker_id
LEFT JOIN sys_oa_project sop ON sop.project_id = sot.project_id
LEFT JOIN sys_oa_task_item soti ON soti.task_id = sot.task_id
WHERE
sot.project_id = #{projectId}
AND sot.del_flag = '0'
</select>
<!-- 综合看板LEFT JOIN 进度步骤 del_flag=0、use_flag=1与步骤表一致即可展示不再依赖进度主表 project 联表) -->
<select id="selectDashboardTasksByProjectId" resultType="com.ruoyi.oa.domain.vo.SysOaTaskVo">
SELECT
sot.task_id AS taskId,
sot.project_id AS projectId,
sop.project_code AS projectCode,
sot.task_title AS taskTitle,
sot.task_type AS taskType,
sot.task_grade AS taskGrade,
su1.nick_name AS createUserNickName,
su2.nick_name AS workerNickName,
sot.state AS state,
sot.finish_time AS finishTime,
sot.track_id AS trackId,
opss.tab_node AS tabNode,
opss.first_level_node AS firstLevelNode,
opss.second_level_node AS secondLevelNode,
opss.step_name AS scheduleStepName,
opss.status AS scheduleStatus,
opss.plan_start AS schedulePlanStart,
opss.plan_end AS schedulePlanEnd,
opss.header AS scheduleHeader
FROM sys_oa_task sot
LEFT JOIN sys_user su1 ON su1.user_id = sot.create_user_id
LEFT JOIN sys_user su2 ON su2.user_id = sot.worker_id
LEFT JOIN sys_oa_project sop ON sop.project_id = sot.project_id
LEFT JOIN oa_project_schedule_step opss
ON opss.track_id = sot.track_id
AND opss.del_flag = '0'
AND opss.use_flag = 1
WHERE sot.project_id = #{projectId}
AND sot.del_flag = '0'
ORDER BY sot.create_time DESC
</select>
<select id="queryListPlus" parameterType="com.ruoyi.oa.domain.bo.SysOaTaskBo" resultType="com.ruoyi.oa.domain.vo.SysOaTaskVo">
SELECT
task_id AS taskId,
project_id AS projectId,
task_title AS taskTitle,
task_type AS taskType,
task_grade AS taskGrade,
collaborator AS collaborator,
begin_time AS beginTime,
finish_time AS finishTime,
content AS content,
accessory AS accessory,
remark AS remark,
create_by AS createBy,
create_time AS createTime,
create_user_id AS createUserId,
worker_id AS workerId,
origin_finish_time AS originFinishTime,
postponements AS postponements,
rank_number AS rankNumber,
completed_time AS completedTime,
state AS state,
task_rank AS taskRank,
own_rank AS ownRank,
status AS status,
time_gap AS timeGap,
temp_time AS tempTime
FROM sys_oa_task
<where>
<if test="state != null">
state = #{state}
</if>
</where>
</select>
</mapper>