Files
education/backend/roomroot-jwgl/target/classes/com/roomroot/jwgl/mapper/NoticeAnnouncementMapper.xml
T
2026-08-21 14:39:03 +08:00

712 lines
27 KiB
XML

<?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.roomroot.jwgl.mapper.NoticeAnnouncementMapper">
<!-- 通知公告后台列表字段映射。 -->
<resultMap id="NoticeAnnouncementResultMap"
type="com.roomroot.jwgl.vo.noticeannouncement.NoticeAnnouncementVO">
<id column="id" property="id"/>
<result column="publishTime" property="publishTime"/>
<result column="title" property="title"/>
<result column="status" property="status"/>
<result column="category" property="category"/>
<result column="priority" property="priority"/>
<result column="readCount" property="readCount"/>
<result column="recipientCount" property="recipientCount"/>
<result column="readerCount" property="readerCount"/>
<result column="remark" property="remark"/>
</resultMap>
<!-- 通知公告后台详情字段映射。 -->
<resultMap id="NoticeAnnouncementDetailResultMap"
type="com.roomroot.jwgl.vo.noticeannouncement.NoticeAnnouncementDetailVO">
<id column="id" property="id"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
<result column="publishTime" property="publishTime"/>
<result column="createTime" property="createTime"/>
<result column="priority" property="priority"/>
<result column="readCount" property="readCount"/>
<result column="status" property="status"/>
<result column="category" property="category"/>
<result column="remark" property="remark"/>
<result column="all" property="all"/>
<result column="recipientCount" property="recipientCount"/>
<result column="readerCount" property="readerCount"/>
</resultMap>
<!-- 公告接收人和阅读明细字段映射。 -->
<resultMap id="NoticeAnnouncementRecipientResultMap"
type="com.roomroot.jwgl.vo.noticeannouncement.NoticeAnnouncementRecipientVO">
<id column="id" property="id"/>
<result column="accountId" property="accountId"/>
<result column="loginName" property="loginName"/>
<result column="userName" property="userName"/>
<result column="received" property="received"/>
<result column="receivedTime" property="receivedTime"/>
<result column="read" property="read"/>
<result column="readTime" property="readTime"/>
</resultMap>
<!-- 公告接收和阅读统计字段映射。 -->
<resultMap id="NoticeAnnouncementStatisticsResultMap"
type="com.roomroot.jwgl.vo.noticeannouncement.NoticeAnnouncementStatisticsVO">
<result column="recipientCount" property="recipientCount"/>
<result column="receivedCount" property="receivedCount"/>
<result column="readerCount" property="readerCount"/>
</resultMap>
<!-- 当前用户公告列表字段映射。 -->
<resultMap id="UserNoticeAnnouncementResultMap"
type="com.roomroot.jwgl.vo.noticeannouncement.UserNoticeAnnouncementVO">
<id column="id" property="id"/>
<result column="title" property="title"/>
<result column="category" property="category"/>
<result column="priority" property="priority"/>
<result column="publishTime" property="publishTime"/>
<result column="read" property="read"/>
<result column="readTime" property="readTime"/>
</resultMap>
<!-- 当前用户公告详情字段映射。 -->
<resultMap id="UserNoticeAnnouncementDetailResultMap"
type="com.roomroot.jwgl.vo.noticeannouncement.UserNoticeAnnouncementDetailVO">
<id column="id" property="id"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
<result column="publishTime" property="publishTime"/>
<result column="category" property="category"/>
<result column="priority" property="priority"/>
<result column="remark" property="remark"/>
<result column="readCount" property="readCount"/>
<result column="read" property="read"/>
<result column="readTime" property="readTime"/>
</resultMap>
<!--
第一步:按账户对历史接收记录去重。
第二步:按公告汇总唯一接收账户数和唯一已读账户数。
第三步:组合后台筛选条件并执行稳定倒序。
-->
<select id="selectNoticeAnnouncementPage"
resultMap="NoticeAnnouncementResultMap">
SELECT
n."编号" AS "id",
n."发布时间" AS "publishTime",
n."标题" AS "title",
n."状态" AS "status",
n."类别" AS "category",
n."优先级" AS "priority",
n."阅读次数" AS "readCount",
NVL(s."recipientCount", 0) AS "recipientCount",
NVL(s."readerCount", 0) AS "readerCount",
n."备注" AS "remark"
FROM "通告表" n
LEFT JOIN (
SELECT
recipient_status."noticeId",
COUNT(1) AS "recipientCount",
SUM(recipient_status."read") AS "readerCount"
FROM (
SELECT
u."通告编号" AS "noticeId",
u."用户编号" AS "accountId",
MAX(
CASE
WHEN u."已阅读" = 1 THEN 1
ELSE 0
END
) AS "read"
FROM "通告用户信息" u
WHERE u."已接收" = 1
GROUP BY u."通告编号", u."用户编号"
) recipient_status
GROUP BY recipient_status."noticeId"
) s
ON s."noticeId" = n."编号"
<where>
<!-- 公告标题使用不区分英文字母大小写的包含查询。 -->
<if test="query.title != null">
AND LOWER(n."标题") LIKE
'%' || LOWER(#{query.title}) || '%'
</if>
<!-- 最低优先级采用包含下限。 -->
<if test="query.minPriority != null">
AND n."优先级" &gt;= #{query.minPriority}
</if>
<!-- 最高优先级采用包含上限。 -->
<if test="query.maxPriority != null">
AND n."优先级" &lt;= #{query.maxPriority}
</if>
<!-- 发布开始时间包含所选日期零点。 -->
<if test="publishStartTime != null">
AND n."发布时间" &gt;= #{publishStartTime}
</if>
<!-- 下一天零点作为排他结束边界。 -->
<if test="publishEndExclusiveTime != null">
AND n."发布时间" &lt; #{publishEndExclusiveTime}
</if>
<!-- 公告类别精确筛选。 -->
<if test="query.category != null">
AND n."类别" = #{query.category}
</if>
<!-- 公告状态精确筛选。 -->
<if test="query.status != null">
AND n."状态" = #{query.status}
</if>
</where>
ORDER BY
n."优先级" DESC,
n."发布时间" DESC,
n."创建时间" DESC,
n."编号" DESC
</select>
<!--
第一步:按账户汇总公告接收和阅读状态,兼容历史重复接收记录。
第二步:按公告预聚合唯一接收人数和已读人数。
第三步:左连接公告主体,保证拟制公告没有接收快照时仍然可以查询详情。
-->
<select id="selectNoticeAnnouncementDetail"
resultMap="NoticeAnnouncementDetailResultMap">
SELECT
n."编号" AS "id",
n."标题" AS "title",
n."内容" AS "content",
n."发布时间" AS "publishTime",
n."创建时间" AS "createTime",
n."优先级" AS "priority",
n."阅读次数" AS "readCount",
n."状态" AS "status",
n."类别" AS "category",
n."备注" AS "remark",
n."全体" AS "all",
NVL(s."recipientCount", 0) AS "recipientCount",
NVL(s."readerCount", 0) AS "readerCount"
FROM "通告表" n
LEFT JOIN (
SELECT
recipient_status."noticeId",
SUM(recipient_status."received")
AS "recipientCount",
SUM(recipient_status."read")
AS "readerCount"
FROM (
SELECT
u."通告编号" AS "noticeId",
u."用户编号" AS "accountId",
MAX(
CASE
WHEN u."已接收" = 1 THEN 1
ELSE 0
END
) AS "received",
MAX(
CASE
WHEN u."已阅读" = 1 THEN 1
ELSE 0
END
) AS "read"
FROM "通告用户信息" u
GROUP BY
u."通告编号",
u."用户编号"
) recipient_status
GROUP BY recipient_status."noticeId"
) s
ON s."noticeId" = n."编号"
WHERE n."编号" = #{id}
</select>
<!-- 锁定公告主体行,确保状态校验和后续状态修改处于同一事务。 -->
<select id="selectNoticeStatusForUpdate"
resultType="string">
SELECT "状态"
FROM "通告表"
WHERE "编号" = #{id}
FOR UPDATE
</select>
<!--
新增公告固定写入拟制状态。
发布时间字段不允许为空,因此拟制阶段暂存本次创建时间。
-->
<insert id="insertNoticeAnnouncement">
INSERT INTO "通告表" (
"编号", "标题", "内容", "发布时间", "创建时间",
"优先级", "阅读次数", "状态", "类别", "备注", "全体"
) VALUES (
#{id}, #{notice.title}, #{notice.content}, #{now}, #{now},
#{notice.priority}, 0, #{status}, #{notice.category},
#{notice.remark}, 0
)
</insert>
<!-- 修改公告可编辑内容,不隐式改变状态、发布时间和接收人快照。 -->
<update id="updateNoticeAnnouncement">
UPDATE "通告表"
SET "标题" = #{notice.title},
"内容" = #{notice.content},
"优先级" = #{notice.priority},
"类别" = #{notice.category},
"备注" = #{notice.remark}
WHERE "编号" = #{notice.id}
</update>
<!-- 发布或重新发布公告,并为本轮发布重置累计阅读次数。 -->
<update id="updateNoticePublishState">
UPDATE "通告表"
SET "状态" = #{status},
"发布时间" = #{publishTime},
"全体" = #{all},
"阅读次数" = 0
WHERE "编号" = #{id}
</update>
<!-- 单独修改公告状态,供下架流程使用。 -->
<update id="updateNoticeStatus">
UPDATE "通告表"
SET "状态" = #{status}
WHERE "编号" = #{id}
</update>
<!-- 单独修改公告优先级,优先级为0时等价于取消置顶。 -->
<update id="updateNoticePriority">
UPDATE "通告表"
SET "优先级" = #{priority}
WHERE "编号" = #{id}
</update>
<!-- 删除公告主体;业务层先校验状态并清除接收人记录。 -->
<delete id="deleteNoticeAnnouncement">
DELETE FROM "通告表"
WHERE "编号" = #{id}
</delete>
<!-- 根据服务端 SessionId 关联在线记录和登录信息表,取得真实账户编号。 -->
<select id="selectAccountIdBySessionId"
resultType="string">
SELECT account."编号"
FROM "MemberOnlineInfo" online
INNER JOIN "登录信息表" account
ON LOWER(TRIM(account."账号"))
= LOWER(TRIM(online."账号"))
WHERE online."SessionId" = #{sessionId}
</select>
<!-- 统计指定编号中存在且未停用的部别数量。 -->
<select id="countActiveDepartments"
resultType="int">
SELECT COUNT(1)
FROM "实施_机关"
WHERE NVL("停用", 0) = 0
AND "编号" IN
<foreach collection="departmentIds"
item="departmentId"
open="("
separator=","
close=")">
#{departmentId}
</foreach>
</select>
<!-- 查询全部未停用、未合并的有效账户。 -->
<select id="selectAllActiveAccountIds"
resultType="string">
SELECT account."编号"
FROM "登录信息表" account
LEFT JOIN "账户状态表" status
ON status."登录信息编号" = account."编号"
WHERE (
status."登录信息编号" IS NULL
OR (
status."启用状态" = 1
AND status."合并目标登录信息编号" IS NULL
)
)
ORDER BY account."编号"
</select>
<!-- 查询仍在职且所属教研室未停用的有效教员账户。 -->
<select id="selectAllActiveTeacherAccountIds"
resultType="string">
SELECT DISTINCT account."编号"
FROM "教员登录表" login_role
INNER JOIN "教员表" teacher
ON teacher."教员编号" = login_role."教员编号"
LEFT JOIN "教研室表" office
ON office."教研室代号" = teacher."教研室代号"
INNER JOIN "登录信息表" account
ON account."编号" = login_role."登录信息编号"
LEFT JOIN "账户状态表" status
ON status."登录信息编号" = account."编号"
WHERE NVL(teacher."离职状态", 0) = 0
AND NVL(office."停用", 0) = 0
AND (
status."登录信息编号" IS NULL
OR (
status."启用状态" = 1
AND status."合并目标登录信息编号" IS NULL
)
)
ORDER BY account."编号"
</select>
<!--
第一步:解析指定部别下机关人员、教员、教研室和教学班次四类账户。
第二步:关联登录信息表,排除已停用或已合并账户。
第三步:使用 DISTINCT 生成唯一接收账户集合。
-->
<select id="selectActiveAccountIdsByDepartments"
resultType="string">
SELECT DISTINCT account."编号"
FROM (
SELECT role_login."登录信息编号" AS "accountId"
FROM "机关人员登录表" role_login
INNER JOIN "实施_机关参谋" personnel
ON personnel."编号" = role_login."机关人员编号"
INNER JOIN "实施_机关" department
ON department."编号" = personnel."实施_机关编号"
WHERE NVL(personnel."离职状态", 0) = 0
AND NVL(department."停用", 0) = 0
AND department."编号" IN
<foreach collection="departmentIds"
item="departmentId"
open="("
separator=","
close=")">
#{departmentId}
</foreach>
UNION ALL
SELECT role_login."登录信息编号" AS "accountId"
FROM "教员登录表" role_login
INNER JOIN "教员表" teacher
ON teacher."教员编号" = role_login."教员编号"
INNER JOIN "教研室表" office
ON office."教研室代号" = teacher."教研室代号"
INNER JOIN "实施_机关_教研室" relation
ON relation."教研室编号" = office."教研室代号"
INNER JOIN "实施_机关" department
ON department."编号" = relation."实施_机关编号"
WHERE NVL(teacher."离职状态", 0) = 0
AND NVL(office."停用", 0) = 0
AND NVL(department."停用", 0) = 0
AND department."编号" IN
<foreach collection="departmentIds"
item="departmentId"
open="("
separator=","
close=")">
#{departmentId}
</foreach>
UNION ALL
SELECT role_login."登录信息编号" AS "accountId"
FROM "教研室登录表" role_login
INNER JOIN "教研室表" office
ON office."教研室代号" = role_login."教研室代号"
INNER JOIN "实施_机关_教研室" relation
ON relation."教研室编号" = office."教研室代号"
INNER JOIN "实施_机关" department
ON department."编号" = relation."实施_机关编号"
WHERE NVL(office."停用", 0) = 0
AND NVL(department."停用", 0) = 0
AND department."编号" IN
<foreach collection="departmentIds"
item="departmentId"
open="("
separator=","
close=")">
#{departmentId}
</foreach>
UNION ALL
SELECT role_login."登录信息编号" AS "accountId"
FROM "学员队登录表" role_login
INNER JOIN "实施_机关_学员队" relation
ON relation."学员队编号" = role_login."学员队编号"
INNER JOIN "实施_机关" department
ON department."编号" = relation."实施_机关编号"
WHERE NVL(department."停用", 0) = 0
AND department."编号" IN
<foreach collection="departmentIds"
item="departmentId"
open="("
separator=","
close=")">
#{departmentId}
</foreach>
) department_accounts
INNER JOIN "登录信息表" account
ON account."编号" = department_accounts."accountId"
LEFT JOIN "账户状态表" status
ON status."登录信息编号" = account."编号"
WHERE (
status."登录信息编号" IS NULL
OR (
status."启用状态" = 1
AND status."合并目标登录信息编号" IS NULL
)
)
ORDER BY account."编号"
</select>
<!-- 删除公告原有接收人快照,供重新发布和删除公告复用。 -->
<delete id="deleteNoticeRecipients">
DELETE FROM "通告用户信息"
WHERE "通告编号" = #{noticeId}
</delete>
<!--
使用一条 INSERT SELECT 语句批量写入当前批次接收账户。
每条记录编号已经由服务端生成,避免依赖数据库厂商专用 UUID 函数。
-->
<insert id="insertNoticeRecipients">
INSERT INTO "通告用户信息" (
"编号", "通告编号", "用户编号",
"已接收", "接收时间", "已阅读", "阅读时间"
)
<foreach collection="recipients"
item="recipient"
separator=" UNION ALL ">
SELECT
#{recipient.id},
#{noticeId},
#{recipient.accountId},
1,
#{receivedTime},
0,
NULL
FROM DUAL
</foreach>
</insert>
<!--
按账户汇总可能存在的历史重复接收记录。
阅读状态取最大值,接收和首次阅读时间取最早有效时间。
-->
<select id="selectNoticeRecipientPage"
resultMap="NoticeAnnouncementRecipientResultMap">
SELECT
MIN(u."编号") AS "id",
u."用户编号" AS "accountId",
account."账号" AS "loginName",
account."用户姓名" AS "userName",
MAX(
CASE WHEN u."已接收" = 1 THEN 1 ELSE 0 END
) AS "received",
MIN(u."接收时间") AS "receivedTime",
MAX(
CASE WHEN u."已阅读" = 1 THEN 1 ELSE 0 END
) AS "read",
MIN(u."阅读时间") AS "readTime"
FROM "通告用户信息" u
LEFT JOIN "登录信息表" account
ON account."编号" = u."用户编号"
WHERE u."通告编号" = #{query.id}
<if test="query.keyword != null">
AND (
LOWER(NVL(account."账号", '')) LIKE
'%' || LOWER(#{query.keyword}) || '%'
OR LOWER(NVL(account."用户姓名", '')) LIKE
'%' || LOWER(#{query.keyword}) || '%'
)
</if>
GROUP BY
u."用户编号",
account."账号",
account."用户姓名"
<if test="query.read != null">
HAVING MAX(
CASE WHEN u."已阅读" = 1 THEN 1 ELSE 0 END
) =
<choose>
<when test="query.read">1</when>
<otherwise>0</otherwise>
</choose>
</if>
ORDER BY
"read" ASC,
"readTime" DESC,
"userName" ASC,
"loginName" ASC,
"accountId" ASC
</select>
<!-- 汇总唯一接收账户的接收和阅读状态。 -->
<select id="selectNoticeStatistics"
resultMap="NoticeAnnouncementStatisticsResultMap">
SELECT
COUNT(1) AS "recipientCount",
NVL(SUM(recipient_status."received"), 0)
AS "receivedCount",
NVL(SUM(recipient_status."read"), 0)
AS "readerCount"
FROM (
SELECT
u."用户编号" AS "accountId",
MAX(
CASE WHEN u."已接收" = 1 THEN 1 ELSE 0 END
) AS "received",
MAX(
CASE WHEN u."已阅读" = 1 THEN 1 ELSE 0 END
) AS "read"
FROM "通告用户信息" u
WHERE u."通告编号" = #{noticeId}
GROUP BY u."用户编号"
) recipient_status
</select>
<!--
只查询当前账户具有接收记录且公告状态为已发布的数据。
阅读状态使用账户维度汇总,避免历史重复记录造成列表重复。
-->
<select id="selectUserNoticePage"
resultMap="UserNoticeAnnouncementResultMap">
SELECT
n."编号" AS "id",
n."标题" AS "title",
n."类别" AS "category",
n."优先级" AS "priority",
n."发布时间" AS "publishTime",
CASE
WHEN EXISTS (
SELECT 1
FROM "通告用户信息" reader
WHERE reader."通告编号" = n."编号"
AND reader."用户编号" = #{accountId}
AND reader."已阅读" = 1
) THEN 1
ELSE 0
END AS "read",
(
SELECT MIN(reader."阅读时间")
FROM "通告用户信息" reader
WHERE reader."通告编号" = n."编号"
AND reader."用户编号" = #{accountId}
AND reader."已阅读" = 1
) AS "readTime"
FROM "通告表" n
WHERE n."状态" = #{publishedStatus}
AND EXISTS (
SELECT 1
FROM "通告用户信息" recipient
WHERE recipient."通告编号" = n."编号"
AND recipient."用户编号" = #{accountId}
AND recipient."已接收" = 1
)
<if test="query.title != null">
AND LOWER(n."标题") LIKE
'%' || LOWER(#{query.title}) || '%'
</if>
<if test="query.category != null">
AND n."类别" = #{query.category}
</if>
<if test="query.unreadOnly">
AND NOT EXISTS (
SELECT 1
FROM "通告用户信息" reader
WHERE reader."通告编号" = n."编号"
AND reader."用户编号" = #{accountId}
AND reader."已阅读" = 1
)
</if>
ORDER BY
n."优先级" DESC,
n."发布时间" DESC,
n."编号" DESC
</select>
<!--
使用 EXISTS 校验当前账户具有接收记录,只锁定唯一公告主体行。
锁定期间下架流程无法并发改变公告状态。
-->
<select id="selectUserNoticeStatusForUpdate"
resultType="string">
SELECT n."状态"
FROM "通告表" n
WHERE n."编号" = #{noticeId}
AND n."状态" = #{publishedStatus}
AND EXISTS (
SELECT 1
FROM "通告用户信息" recipient
WHERE recipient."通告编号" = n."编号"
AND recipient."用户编号" = #{accountId}
AND recipient."已接收" = 1
)
FOR UPDATE
</select>
<!-- 首次阅读时更新当前账户全部历史重复接收记录。 -->
<update id="markNoticeRecipientRead">
UPDATE "通告用户信息"
SET "已接收" = 1,
"接收时间" = NVL("接收时间", #{readTime}),
"已阅读" = 1,
"阅读时间" = NVL("阅读时间", #{readTime})
WHERE "通告编号" = #{noticeId}
AND "用户编号" = #{accountId}
AND NVL("已阅读", 0) = 0
</update>
<!-- 每次有效打开公告都原子增加累计阅读次数。 -->
<update id="incrementNoticeReadCount">
UPDATE "通告表"
SET "阅读次数" = NVL("阅读次数", 0) + 1
WHERE "编号" = #{noticeId}
</update>
<!-- 查询当前账户可见的已发布公告详情和当前账户阅读状态。 -->
<select id="selectUserNoticeDetail"
resultMap="UserNoticeAnnouncementDetailResultMap">
SELECT
n."编号" AS "id",
n."标题" AS "title",
n."内容" AS "content",
n."发布时间" AS "publishTime",
n."类别" AS "category",
n."优先级" AS "priority",
n."备注" AS "remark",
n."阅读次数" AS "readCount",
CASE
WHEN EXISTS (
SELECT 1
FROM "通告用户信息" reader
WHERE reader."通告编号" = n."编号"
AND reader."用户编号" = #{accountId}
AND reader."已阅读" = 1
) THEN 1
ELSE 0
END AS "read",
(
SELECT MIN(reader."阅读时间")
FROM "通告用户信息" reader
WHERE reader."通告编号" = n."编号"
AND reader."用户编号" = #{accountId}
AND reader."已阅读" = 1
) AS "readTime"
FROM "通告表" n
WHERE n."编号" = #{noticeId}
AND n."状态" = #{publishedStatus}
AND EXISTS (
SELECT 1
FROM "通告用户信息" recipient
WHERE recipient."通告编号" = n."编号"
AND recipient."用户编号" = #{accountId}
AND recipient."已接收" = 1
)
</select>
</mapper>