<?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.satisfaction.mapper.SatisfactionMapper">
|
<!--
|
满意度统计查询(南华 + 同德共用的数据访问层)。
|
原本散落在 smartor 的 ServiceSubtaskMapper.xml 里,满意度模块化后集中到此处。
|
|
注意:
|
1) 这些 SQL 只读 service_subtask / service_subtask_detail / service_task,不做任何写操作;
|
2) 一律使用全限定类名,不依赖 typeAliasesPackage 别名;
|
3) 原本用于承接 ServiceSubtask 实体的 selectSatisfactionSubtaskList 与 querySendCount 已确认
|
为死代码(零调用点)并删除,因此本文件不依赖任何共享 <sql> 片段。
|
-->
|
|
<select id="selectSatisfactionSendCount" parameterType="com.ruoyi.satisfaction.domain.entity.SatisfactionStatQuery"
|
resultType="java.util.Map">
|
select libtemplateid as libtemplateid, count(distinct id) as cnt
|
from service_subtask
|
where del_flag = 0
|
<if test="orgid != null and orgid != ''">
|
and orgid = #{orgid}
|
</if>
|
<if test="campusid != null and campusid != ''">
|
and campusid = #{campusid}
|
</if>
|
<if test="type != null and type != ''">and type = #{type}</if>
|
<if test="startTime != null">
|
and visit_time >= #{startTime}
|
</if>
|
<if test="endTime != null">
|
and visit_time < date_add(#{endTime}, interval 1 day)
|
</if>
|
<if test="libTemplateIds != null and libTemplateIds.size() > 0">
|
and libtemplateid IN
|
<foreach collection="libTemplateIds" item="libTemplateId" open="(" separator="," close=")">
|
#{libTemplateId}
|
</foreach>
|
</if>
|
<if test="(hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0) or (deptcodes != null and deptcodes.size() > 0)">
|
AND (
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0">
|
leavehospitaldistrictcode IN
|
<foreach collection="hospitaldistrictcodes" item="hospitaldistrictcode" open="("
|
separator=","
|
close=")">
|
#{hospitaldistrictcode}
|
</foreach>
|
</if>
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0 and deptcodes != null and deptcodes.size() > 0">
|
OR
|
</if>
|
<if test="deptcodes != null and deptcodes.size() > 0">
|
deptcode IN
|
<foreach collection="deptcodes" item="deptcode" open="(" separator="," close=")">
|
#{deptcode}
|
</foreach>
|
</if>
|
)
|
</if>
|
group by libtemplateid
|
</select>
|
|
<select id="selectSatisfactionSubtaskTypes" parameterType="com.ruoyi.satisfaction.domain.vo.PatSatisfactionReqVO"
|
resultType="java.lang.String">
|
select distinct type
|
from service_subtask
|
where del_flag = 0
|
<if test="questionType != null">and type = #{questionType}</if>
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0">
|
AND leavehospitaldistrictcode IN
|
<foreach collection="hospitaldistrictcodes" item="hospitaldistrictcode" open="(" separator=","
|
close=")">
|
#{hospitaldistrictcode}
|
</foreach>
|
</if>
|
<if test="deptcodes != null and deptcodes.size() > 0">
|
AND deptcode IN
|
<foreach collection="deptcodes" item="deptcode" open="(" separator="," close=")">
|
#{deptcode}
|
</foreach>
|
</if>
|
<if test="serviceTypes != null and serviceTypes.size() > 0">
|
AND service_type IN
|
<foreach collection="serviceTypes" item="serviceType" open="(" separator="," close=")">
|
#{serviceType}
|
</foreach>
|
</if>
|
<if test="startTime != null and endTime != null">
|
AND visit_time >= #{startTime}
|
AND visit_time < date_add(#{endTime}, interval 1 day)
|
</if>
|
</select>
|
|
<select id="mydTrend" resultType="com.ruoyi.satisfaction.domain.dto.MydTrendReqDTO">
|
SELECT CASE #{type}
|
WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
|
WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
|
WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
|
WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
|
ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
|
END AS period,
|
ROUND(avg(d.score), 2) AS totalScore
|
FROM service_subtask_detail d
|
JOIN service_task t ON d.taskid = t.taskid
|
WHERE t.service_type IN (14)
|
AND t.del_flag = 0
|
AND d.del_flag = 0
|
AND d.create_time >= #{startFinishTime}
|
AND d.create_time < DATE_ADD(#{endFinishTime}, INTERVAL 1 DAY)
|
GROUP BY period
|
ORDER BY period;
|
</select>
|
|
<select id="sltdMydTotalByDimension" resultType="com.ruoyi.satisfaction.domain.dto.MydTrendReqDTO">
|
SELECT
|
p.period,
|
dim.dimension,
|
IFNULL(ROUND(SUM(d.score), 2), 0) AS totalScore
|
FROM (
|
<!-- 生成查询范围内实际出现过的时间段 -->
|
SELECT DISTINCT
|
CASE #{type}
|
WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
|
WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
|
WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
|
WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
|
ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
|
END AS period
|
FROM service_subtask_detail d
|
WHERE d.del_flag = 0
|
AND d.create_time >= #{startFinishTime}
|
AND d.create_time < #{endFinishTime}
|
) p
|
CROSS JOIN (
|
<!-- 所有需要展示的 dimension -->
|
SELECT DISTINCT dimension
|
FROM service_subtask_detail
|
WHERE del_flag = 0
|
AND dimension IS NOT NULL
|
) dim
|
LEFT JOIN service_task t
|
ON t.service_type IN (6, 14)
|
AND t.del_flag = 0
|
LEFT JOIN service_subtask_detail d
|
ON d.taskid = t.taskid
|
AND d.del_flag = 0
|
AND d.dimension = dim.dimension
|
AND CASE #{type}
|
WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
|
WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
|
WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
|
WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
|
ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
|
END = p.period
|
AND d.create_time >= #{startFinishTime}
|
AND d.create_time < #{endFinishTime}
|
GROUP BY p.period, dim.dimension
|
ORDER BY p.period, dim.dimension
|
</select>
|
|
<select id="sltdMydTotalByYQ" resultType="com.ruoyi.satisfaction.domain.dto.MydTrendReqDTO">
|
SELECT p.period,
|
c.campusid,
|
IFNULL(ROUND(AVG(d.score), 2), 0) AS totalScore
|
FROM (
|
-- 生成查询范围内实际出现过的时间段
|
SELECT DISTINCT CASE #{type}
|
WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
|
WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
|
WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
|
WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
|
ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
|
END AS period
|
FROM service_subtask_detail d
|
WHERE d.del_flag = 0
|
AND d.create_time >= #{startFinishTime}
|
AND d.create_time < #{endFinishTime}) p
|
CROSS JOIN (
|
-- 所有需要展示的院区
|
SELECT DISTINCT campusid
|
FROM service_task
|
WHERE service_type IN (6, 14)
|
AND del_flag = 0
|
AND campusid IS NOT NULL) c
|
LEFT JOIN service_task t
|
ON t.campusid = c.campusid
|
AND t.service_type IN (6, 14)
|
AND t.del_flag = 0
|
LEFT JOIN service_subtask_detail d
|
ON d.taskid = t.taskid
|
AND d.del_flag = 0
|
AND CASE #{type}
|
WHEN 'year' THEN DATE_FORMAT(d.create_time, '%Y')
|
WHEN 'quarter' THEN CONCAT(YEAR(d.create_time), '-Q', QUARTER(d.create_time))
|
WHEN 'month' THEN DATE_FORMAT(d.create_time, '%Y-%m')
|
WHEN 'week' THEN FLOOR(DATEDIFF(d.create_time, #{startFinishTime}) / 7) + 1
|
ELSE DATE_FORMAT(d.create_time, '%Y-%m-%d')
|
END = p.period
|
AND d.create_time >= #{startFinishTime}
|
AND d.create_time < #{endFinishTime}
|
GROUP BY p.period, c.campusid
|
ORDER BY p.period, c.campusid;
|
</select>
|
|
<select id="statMydQuestionOptionForExport" resultType="com.ruoyi.satisfaction.domain.dto.ServiceSubtaskOptionStatDTO">
|
SELECT
|
t.taskid AS taskid,
|
t.task_name AS taskName,
|
d.questiontext AS questiontext,
|
d.asrtext AS optionresult,
|
d.targetvalue AS targetvalue,
|
d.value_type AS valueType,
|
COUNT(DISTINCT s.id) AS patientCount,
|
SUM(COALESCE(CAST(d.score AS DECIMAL(18,2)), 0)) AS scoreSum
|
FROM
|
service_task t
|
INNER JOIN service_subtask s ON s.taskid = t.taskid
|
INNER JOIN service_subtask_detail d ON d.sub_id = s.id
|
WHERE 1=1
|
AND s.del_flag = '0'
|
AND d.del_flag = 0
|
<if test="subtaskIds != null and subtaskIds.size() > 0">
|
AND s.id IN
|
<foreach collection="subtaskIds" item="subtaskId" open="(" separator="," close=")">
|
#{subtaskId}
|
</foreach>
|
</if>
|
<!-- 不传子任务时直接查不到数据,避免误统计全量 -->
|
<if test="subtaskIds == null or subtaskIds.size() == 0">
|
AND 1 = 0
|
</if>
|
<if test="questiontext != null and questiontext != ''">
|
AND d.questiontext LIKE CONCAT('%', #{questiontext}, '%')
|
</if>
|
<!-- 同一患者同一题目只保留最新一条,重答不重复计入数量 -->
|
AND d.id = (
|
SELECT MAX(d2.id)
|
FROM service_subtask_detail d2
|
WHERE d2.sub_id = d.sub_id
|
AND d2.questiontext <=> d.questiontext
|
AND d2.del_flag = '0'
|
)
|
GROUP BY
|
t.taskid,
|
t.task_name,
|
d.questiontext,
|
d.asrtext,
|
d.targetvalue,
|
d.value_type
|
<!-- 按任务名称分组展示:先任务名称、再任务编号,同一任务的题目/选项连续排列 -->
|
ORDER BY
|
t.task_name,
|
t.taskid,
|
d.questiontext
|
</select>
|
|
<select id="statQuestionOption" resultType="com.ruoyi.satisfaction.domain.ServiceSubtaskDetailRatioExport">
|
SELECT
|
d.questiontext AS questiontext,
|
t.taskid AS taskid,
|
t.task_name AS taskName,
|
d.asrtext AS optionresult,
|
d.score AS score,
|
d.targetvalue AS targetvalue,
|
d.value_type AS valueType,
|
COUNT(*) AS count,
|
CONCAT(ROUND(COUNT(*) * 100.0 / t2.total_count, 2), '%') AS ratio
|
FROM
|
service_task t
|
INNER JOIN service_subtask s ON s.taskid = t.taskid
|
INNER JOIN service_subtask_detail d ON d.sub_id = s.id
|
INNER JOIN (
|
SELECT
|
t.taskid,
|
d.questiontext,
|
COUNT(*) AS total_count
|
FROM
|
service_task t
|
INNER JOIN service_subtask s ON s.taskid = t.taskid
|
INNER JOIN service_subtask_detail d ON d.sub_id = s.id
|
WHERE 1=1
|
<if test="taskIds != null and taskIds.size() > 0">
|
AND t.taskid IN
|
<foreach collection="taskIds" item="taskId" open="(" separator="," close=")">
|
#{taskId}
|
</foreach>
|
</if>
|
<!-- 传了 subtaskIds 只统计这批子任务(本次导出的患者) -->
|
<if test="subtaskIds != null and subtaskIds.size() > 0">
|
AND s.id IN
|
<foreach collection="subtaskIds" item="subtaskId" open="(" separator="," close=")">
|
#{subtaskId}
|
</foreach>
|
</if>
|
<if test="valueType != null">AND d.value_type = #{valueType}</if>
|
<if test="scoreStart != null">AND d.score >= #{scoreStart}</if>
|
<if test="scoreEnd != null">AND d.score <= #{scoreEnd}</if>
|
<if test="questiontext != null and questiontext != ''">and d.questiontext like concat('%', #{questiontext},
|
'%')
|
</if>
|
and s.sendstate=6
|
and d.del_flag=0
|
<!-- 分母必须和明细用同一套时间条件,否则选了时间范围后比例会按全量历史被稀释 -->
|
<if test="startOutHospTime != null">
|
AND date_format(s.endtime,'%y%m%d') >= date_format(#{startOutHospTime},'%y%m%d')
|
</if>
|
<if test="endOutHospTime != null">
|
AND date_format(s.endtime,'%y%m%d') <= date_format(#{endOutHospTime},'%y%m%d')
|
</if>
|
<if test="startFinishTime != null">
|
AND date_format(s.finishtime,'%y%m%d') >= date_format(#{startFinishTime},'%y%m%d')
|
</if>
|
<if test="endFinishTime != null">
|
AND date_format(s.finishtime,'%y%m%d') <= date_format(#{endFinishTime},'%y%m%d')
|
</if>
|
GROUP BY
|
t.taskid,
|
d.questiontext
|
) t2 ON t2.taskid = t.taskid AND t2.questiontext = d.questiontext
|
WHERE 1=1
|
<if test="taskIds != null and taskIds.size() > 0">
|
AND t.taskid IN
|
<foreach collection="taskIds" item="taskId" open="(" separator="," close=")">
|
#{taskId}
|
</foreach>
|
</if>
|
<if test="subtaskIds != null and subtaskIds.size() > 0">
|
AND s.id IN
|
<foreach collection="subtaskIds" item="subtaskId" open="(" separator="," close=")">
|
#{subtaskId}
|
</foreach>
|
</if>
|
<if test="valueType != null">AND d.value_type = #{valueType}</if>
|
<if test="scoreStart != null">AND d.score >= #{scoreStart}</if>
|
<if test="scoreEnd != null">AND d.score <= #{scoreEnd}</if>
|
<if test="questiontext != null and questiontext != ''">and d.questiontext like concat('%', #{questiontext},
|
'%')
|
</if>
|
AND s.sendstate = 6
|
and d.del_flag=0
|
<if test="startOutHospTime != null">
|
AND date_format(s.endtime,'%y%m%d') >= date_format(#{startOutHospTime},'%y%m%d')
|
</if>
|
<if test="endOutHospTime != null">
|
AND date_format(s.endtime,'%y%m%d') <= date_format(#{endOutHospTime},'%y%m%d')
|
</if>
|
<if test="startFinishTime != null">
|
AND date_format(s.finishtime,'%y%m%d') >= date_format(#{startFinishTime},'%y%m%d')
|
</if>
|
<if test="endFinishTime != null">
|
AND date_format(s.finishtime,'%y%m%d') <= date_format(#{endFinishTime},'%y%m%d')
|
</if>
|
GROUP BY
|
t.taskid,
|
d.questiontext,
|
d.score,
|
d.targetvalue,
|
d.asrtext,
|
d.value_type
|
ORDER BY
|
d.questiontext,
|
t.taskid
|
</select>
|
|
<select id="statQuestionOptionBySubtaskIds" resultType="com.ruoyi.satisfaction.domain.ServiceSubtaskDetailRatioExport">
|
SELECT
|
d.questiontext AS questiontext,
|
<!-- 明细已按「题目 + 选项」汇总,任务/科室/病区只是附带信息,必须用聚合函数取值(MySQL ONLY_FULL_GROUP_BY) -->
|
MAX(t.taskid) AS taskid,
|
MAX(t.task_name) AS taskName,
|
d.asrtext AS optionresult,
|
d.score AS score,
|
MAX(s.deptcode) AS deptcode,
|
MAX(s.deptname) AS deptname,
|
MAX(s.leavehospitaldistrictcode) AS leavehospitaldistrictcode,
|
MAX(s.leavehospitaldistrictname) AS leavehospitaldistrictname,
|
d.targetvalue AS targetvalue,
|
d.value_type AS valueType,
|
COUNT(*) AS count,
|
CONCAT(ROUND(COUNT(*) * 100.0 / t2.total_count, 2), '%') AS ratio
|
FROM
|
service_task t
|
INNER JOIN service_subtask s ON s.taskid = t.taskid
|
INNER JOIN service_subtask_detail d ON d.sub_id = s.id
|
<!-- 去重:同一子任务同一题目只保留最新一条,避免重答/重复回调把同一道题重复计入项数(与 mzMydScoreRank 口径一致) -->
|
AND d.id = (
|
SELECT MAX(d2.id)
|
FROM service_subtask_detail d2
|
WHERE d2.sub_id = d.sub_id
|
AND d2.questiontext <=> d.questiontext
|
AND d2.del_flag = '0'
|
)
|
INNER JOIN (
|
<!-- 分母 = 该题各选项项数之和(未作答的空 asrtext 不进分母),这样一道题各选项比例合计才是 100% -->
|
SELECT
|
x.questiontext AS questiontext,
|
SUM(x.option_count) AS total_count
|
FROM (
|
SELECT
|
d.questiontext,
|
d.asrtext,
|
COUNT(*) AS option_count
|
FROM
|
service_task t
|
INNER JOIN service_subtask s ON s.taskid = t.taskid
|
INNER JOIN service_subtask_detail d ON d.sub_id = s.id
|
<!-- 去重:分母(该题有效答卷总数)与明细口径保持一致,保证各选项比例合计 100% -->
|
AND d.id = (
|
SELECT MAX(d4.id)
|
FROM service_subtask_detail d4
|
WHERE d4.sub_id = d.sub_id
|
AND d4.questiontext <=> d.questiontext
|
AND d4.del_flag = '0'
|
)
|
WHERE 1=1
|
<if test="subtaskIds != null and subtaskIds.size() > 0">
|
AND s.id IN
|
<foreach collection="subtaskIds" item="subtaskId" open="(" separator="," close=")">
|
#{subtaskId}
|
</foreach>
|
</if>
|
<if test="valueType != null">AND d.value_type >= #{valueType}</if>
|
<if test="scoreStart != null">AND d.score >= #{scoreStart}</if>
|
<if test="scoreEnd != null">AND d.score <= #{scoreEnd}</if>
|
<if test="questiontext != null and questiontext != ''">and d.questiontext like concat('%', #{questiontext},
|
'%')
|
</if>
|
AND s.sendstate = 6
|
AND d.del_flag=0
|
<!-- 分母与明细用同一套时间条件,否则选了日期区间后各选项比例合计不到 100% -->
|
<if test="startOutHospTime != null">
|
AND date_format(s.endtime,'%y%m%d') >= date_format(#{startOutHospTime},'%y%m%d')
|
</if>
|
<if test="endOutHospTime != null">
|
AND date_format(s.endtime,'%y%m%d') <= date_format(#{endOutHospTime},'%y%m%d')
|
</if>
|
<if test="startFinishTime != null">
|
AND date_format(s.finishtime,'%y%m%d') >= date_format(#{startFinishTime},'%y%m%d')
|
</if>
|
<if test="endFinishTime != null">
|
AND date_format(s.finishtime,'%y%m%d') <= date_format(#{endFinishTime},'%y%m%d')
|
</if>
|
<!-- 未作答(asrtext 为空)的明细不计入分母 -->
|
AND d.asrtext IS NOT NULL AND TRIM(d.asrtext) <> ''
|
GROUP BY d.questiontext, d.asrtext
|
) x
|
GROUP BY x.questiontext
|
) t2 ON t2.questiontext = d.questiontext
|
WHERE 1=1
|
<!-- 去重:明细行同一子任务同一题目只保留最新一条,重答不重复计入项数 -->
|
AND d.id = (
|
SELECT MAX(d3.id)
|
FROM service_subtask_detail d3
|
WHERE d3.sub_id = d.sub_id
|
AND d3.questiontext <=> d.questiontext
|
AND d3.del_flag = '0'
|
)
|
<if test="subtaskIds != null and subtaskIds.size() > 0">
|
AND s.id IN
|
<foreach collection="subtaskIds" item="subtaskId" open="(" separator="," close=")">
|
#{subtaskId}
|
</foreach>
|
</if>
|
AND s.sendstate = 6
|
AND d.del_flag=0
|
<!-- 未作答(asrtext 为空)不算任何选项,明细里直接排除,避免出现空选项行 -->
|
AND d.asrtext IS NOT NULL AND TRIM(d.asrtext) <> ''
|
<if test="valueType != null">AND d.value_type >= #{valueType}</if>
|
<if test="scoreStart != null">AND d.score >= #{scoreStart}</if>
|
<if test="scoreEnd != null">AND d.score <= #{scoreEnd}</if>
|
<if test="questiontext != null and questiontext != ''">and d.questiontext like concat('%', #{questiontext},
|
'%')
|
</if>
|
<if test="startOutHospTime != null">
|
AND date_format(s.endtime,'%y%m%d') >= date_format(#{startOutHospTime},'%y%m%d')
|
</if>
|
<if test="endOutHospTime != null">
|
AND date_format(s.endtime,'%y%m%d') <= date_format(#{endOutHospTime},'%y%m%d')
|
</if>
|
<if test="startFinishTime != null">
|
AND date_format(s.finishtime,'%y%m%d') >= date_format(#{startFinishTime},'%y%m%d')
|
</if>
|
<if test="endFinishTime != null">
|
AND date_format(s.finishtime,'%y%m%d') <= date_format(#{endFinishTime},'%y%m%d')
|
</if>
|
<!-- 只按「题目 + 选项」汇总:原来 GROUP BY 带上 taskid/科室/病区,同一个选项被拆成多行、每行数量都是 1,
|
前端/导出拿到的「数量」就永远做不了累加 -->
|
GROUP BY
|
d.questiontext,
|
d.asrtext,
|
d.score,
|
d.targetvalue,
|
d.value_type
|
ORDER BY
|
d.questiontext,
|
MIN(t.taskid)
|
</select>
|
|
<select id="statQuestionOptionByKsOrBq" resultType="com.ruoyi.satisfaction.domain.dto.QuestionCountKsOrBqDTO"
|
parameterType="com.ruoyi.satisfaction.domain.vo.QuestionCountKsOrBqVO">
|
SELECT
|
s.deptname AS deptname,
|
s.leavehospitaldistrictname AS leavehospitaldistrictname,
|
d.questiontext AS questionText,
|
d.targetvalue AS targetvalue, -- 所有选项拼接
|
d.asrtext AS asrtext, -- 用户实际选中的选项
|
d.score AS singleScore -- 单条记录的分数
|
FROM service_subtask_detail d
|
JOIN service_subtask s ON d.sub_id = s.id
|
WHERE s.del_flag = 0
|
AND d.del_flag = 0
|
AND s.service_type IN ('6', '14')
|
<if test="taskTemplateid != null">
|
AND s.templateid = #{taskTemplateid}
|
</if>
|
<if test="endFinishTime != null">
|
AND d.create_time < #{endFinishTime}
|
</if>
|
<if test="startFinishTime != null">
|
AND d.create_time >= #{startFinishTime}
|
</if>
|
<if test="deptOrDistrict ==1">
|
<if test="leavehospitaldistrictcodes != null and leavehospitaldistrictcodes.size() > 0">
|
AND leavehospitaldistrictcode IN
|
<foreach collection="leavehospitaldistrictcodes" item="leavehospitaldistrictcode" open="("
|
separator=","
|
close=")">
|
#{leavehospitaldistrictcode}
|
</foreach>
|
</if>
|
<if test=" leaveldeptcodes != null and leaveldeptcodes.size()>0">
|
AND deptcode IN
|
<foreach collection="leaveldeptcodes" item="leaveldeptcode" open="(" separator=","
|
close=")">
|
#{leaveldeptcode}
|
</foreach>
|
</if>
|
</if>
|
<if test="deptOrDistrict ==2">
|
<if test="leavehospitaldistrictcodes != null and leavehospitaldistrictcodes.size() > 0">
|
AND leavehospitaldistrictcode IN
|
<foreach collection="leavehospitaldistrictcodes" item="leavehospitaldistrictcode" open="("
|
separator=","
|
close=")">
|
#{leavehospitaldistrictcode}
|
</foreach>
|
</if>
|
<if test=" leaveldeptcodes != null and leaveldeptcodes.size()>0">
|
OR deptcode IN
|
<foreach collection="leaveldeptcodes" item="leaveldeptcode" open="(" separator=","
|
close=")">
|
#{leaveldeptcode}
|
</foreach>
|
</if>
|
</if>
|
</select>
|
|
<select id="selectMzMydScoreRank" parameterType="com.ruoyi.satisfaction.domain.vo.MzMydScoreRankVO"
|
resultType="com.ruoyi.satisfaction.domain.dto.MzMydScoreRankDTO">
|
SELECT
|
t.code AS code,
|
t.name AS name,
|
ROUND(AVG(t.w) * 100, 2) AS score,
|
COUNT(*) AS itemCount
|
FROM (
|
SELECT
|
<choose>
|
<when test='dimensionType == "2"'>
|
s.leavehospitaldistrictcode AS code,
|
s.leavehospitaldistrictname AS name,
|
</when>
|
<otherwise>
|
s.deptcode AS code,
|
s.deptname AS name,
|
</otherwise>
|
</choose>
|
CAST(d.score AS DECIMAL(10,4)) AS w
|
FROM service_subtask s
|
INNER JOIN service_subtask_detail d ON d.sub_id = s.id
|
WHERE s.del_flag = '0'
|
AND d.del_flag = '0'
|
AND s.sendstate = 6
|
<if test="serviceTypes != null and serviceTypes.size() > 0">
|
AND service_type IN
|
<foreach collection="serviceTypes" item="serviceType" open="(" separator=","
|
close=")">
|
#{serviceType}
|
</foreach>
|
</if>
|
<!-- <!– 只取公式里的五档权重,空值/0/未答等既不进分子也不进分母 –>-->
|
<!-- AND CAST(d.score AS DECIMAL(10,4)) IN (1, 0.8, 0.6, 0.4, 0.2)-->
|
<!-- 同一子任务同一题目只保留最新一条,避免重答被重复计入项数 -->
|
AND d.id = (
|
SELECT MAX(d2.id)
|
FROM service_subtask_detail d2
|
WHERE d2.sub_id = d.sub_id
|
AND d2.questiontext <=> d.questiontext
|
AND d2.del_flag = '0'
|
)
|
<if test="orgid != null and orgid != ''">
|
AND s.orgid = #{orgid}
|
</if>
|
<if test="campusid != null and campusid != ''">
|
AND s.campusid = #{campusid}
|
</if>
|
<if test="startFinishTime != null">
|
AND s.finishtime >= #{startFinishTime}
|
</if>
|
<if test="endFinishTime != null">
|
AND s.finishtime < DATE_ADD(#{endFinishTime}, INTERVAL 1 DAY)
|
</if>
|
<if test="questionText != null and questionText != ''">and d.questiontext like concat('%', #{questionText},
|
'%')
|
</if>
|
<choose>
|
<when test='dimensionType == "2"'>
|
AND s.leavehospitaldistrictcode IS NOT NULL AND s.leavehospitaldistrictcode <> ''
|
AND s.leavehospitaldistrictname IS NOT NULL AND s.leavehospitaldistrictname <> ''
|
<if test="districtCodes != null and districtCodes.size() > 0">
|
AND s.leavehospitaldistrictcode IN
|
<foreach collection="districtCodes" item="districtCode" open="(" separator="," close=")">
|
#{districtCode}
|
</foreach>
|
</if>
|
</when>
|
<otherwise>
|
AND s.deptcode IS NOT NULL AND s.deptcode <> ''
|
AND s.deptname IS NOT NULL AND s.deptname <> ''
|
<if test="deptCodes != null and deptCodes.size() > 0">
|
AND s.deptcode IN
|
<foreach collection="deptCodes" item="deptCode" open="(" separator="," close=")">
|
#{deptCode}
|
</foreach>
|
</if>
|
</otherwise>
|
</choose>
|
) t
|
GROUP BY t.code, t.name
|
ORDER BY AVG(t.w) DESC, COUNT(*) DESC
|
<if test="limit != null and limit > 0">
|
LIMIT #{limit}
|
</if>
|
</select>
|
|
<select id="selectSatisfactionFillStat" parameterType="com.ruoyi.satisfaction.domain.entity.SatisfactionStatQuery"
|
resultType="java.util.Map">
|
select ss.libtemplateid as libtemplateid,
|
ssd.questiontext as questiontext,
|
ssd.score as score,
|
count(*) as cnt
|
from service_subtask_detail ssd
|
join service_subtask ss on ss.id = ssd.sub_id
|
where ssd.del_flag = 0
|
and ss.del_flag = 0
|
<if test="orgid != null and orgid != ''">
|
and ss.orgid = #{orgid}
|
</if>
|
<if test="campusid != null and campusid != ''">
|
and ss.campusid = #{campusid}
|
</if>
|
<if test="type != null and type != ''">and ss.type = #{type}</if>
|
<if test="startTime != null">
|
and ss.visit_time >= #{startTime}
|
</if>
|
<if test="endTime != null">
|
and ss.visit_time < date_add(#{endTime}, interval 1 day)
|
</if>
|
<if test="libTemplateIds != null and libTemplateIds.size() > 0">
|
and ss.libtemplateid IN
|
<foreach collection="libTemplateIds" item="libTemplateId" open="(" separator="," close=")">
|
#{libTemplateId}
|
</foreach>
|
</if>
|
<if test="(hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0) or (deptcodes != null and deptcodes.size() > 0)">
|
AND (
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0">
|
ss.leavehospitaldistrictcode IN
|
<foreach collection="hospitaldistrictcodes" item="hospitaldistrictcode" open="("
|
separator=","
|
close=")">
|
#{hospitaldistrictcode}
|
</foreach>
|
</if>
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0 and deptcodes != null and deptcodes.size() > 0">
|
OR
|
</if>
|
<if test="deptcodes != null and deptcodes.size() > 0">
|
ss.deptcode IN
|
<foreach collection="deptcodes" item="deptcode" open="(" separator="," close=")">
|
#{deptcode}
|
</foreach>
|
</if>
|
)
|
</if>
|
group by ss.libtemplateid, ssd.questiontext, ssd.score
|
</select>
|
|
<select id="selectSatisfactionFillStatByMatchedtext" parameterType="com.ruoyi.satisfaction.domain.entity.SatisfactionStatQuery"
|
resultType="java.util.Map">
|
select ss.libtemplateid as libtemplateid,
|
ssd.questiontext as questiontext,
|
ssd.matchedtext as matchedtext,
|
ssd.score as score,
|
count(*) as cnt,
|
min(ssd.targetvalue) as targetvalue
|
from service_subtask_detail ssd
|
join service_subtask ss on ss.id = ssd.sub_id
|
where ssd.del_flag = 0
|
and ss.del_flag = 0
|
<if test="orgid != null and orgid != ''">
|
and ss.orgid = #{orgid}
|
</if>
|
<if test="campusid != null and campusid != ''">
|
and ss.campusid = #{campusid}
|
</if>
|
<if test="type != null and type != ''">and ss.type = #{type}</if>
|
<if test="startTime != null">
|
and ss.visit_time >= #{startTime}
|
</if>
|
<if test="endTime != null">
|
and ss.visit_time < date_add(#{endTime}, interval 1 day)
|
</if>
|
<if test="libTemplateIds != null and libTemplateIds.size() > 0">
|
and ss.libtemplateid IN
|
<foreach collection="libTemplateIds" item="libTemplateId" open="(" separator="," close=")">
|
#{libTemplateId}
|
</foreach>
|
</if>
|
<if test="(hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0) or (deptcodes != null and deptcodes.size() > 0)">
|
AND (
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0">
|
ss.leavehospitaldistrictcode IN
|
<foreach collection="hospitaldistrictcodes" item="hospitaldistrictcode" open="("
|
separator=","
|
close=")">
|
#{hospitaldistrictcode}
|
</foreach>
|
</if>
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0 and deptcodes != null and deptcodes.size() > 0">
|
OR
|
</if>
|
<if test="deptcodes != null and deptcodes.size() > 0">
|
ss.deptcode IN
|
<foreach collection="deptcodes" item="deptcode" open="(" separator="," close=")">
|
#{deptcode}
|
</foreach>
|
</if>
|
)
|
</if>
|
group by ss.libtemplateid, ssd.questiontext, ssd.matchedtext, ssd.score
|
</select>
|
|
<select id="selectSatisfactionFillPersonCount" parameterType="com.ruoyi.satisfaction.domain.entity.SatisfactionStatQuery"
|
resultType="java.util.Map">
|
select ss.libtemplateid as libtemplateid,
|
count(distinct ssd.sub_id) as cnt
|
from service_subtask_detail ssd
|
join service_subtask ss on ss.id = ssd.sub_id
|
where ssd.del_flag = 0
|
and ss.del_flag = 0
|
<if test="orgid != null and orgid != ''">
|
and ss.orgid = #{orgid}
|
</if>
|
<if test="campusid != null and campusid != ''">
|
and ss.campusid = #{campusid}
|
</if>
|
<if test="type != null and type != ''">and ss.type = #{type}</if>
|
<if test="startTime != null">
|
and ss.visit_time >= #{startTime}
|
</if>
|
<if test="endTime != null">
|
and ss.visit_time < date_add(#{endTime}, interval 1 day)
|
</if>
|
<if test="libTemplateIds != null and libTemplateIds.size() > 0">
|
and ss.libtemplateid IN
|
<foreach collection="libTemplateIds" item="libTemplateId" open="(" separator="," close=")">
|
#{libTemplateId}
|
</foreach>
|
</if>
|
<if test="(hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0) or (deptcodes != null and deptcodes.size() > 0)">
|
AND (
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0">
|
ss.leavehospitaldistrictcode IN
|
<foreach collection="hospitaldistrictcodes" item="hospitaldistrictcode" open="("
|
separator=","
|
close=")">
|
#{hospitaldistrictcode}
|
</foreach>
|
</if>
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0 and deptcodes != null and deptcodes.size() > 0">
|
OR
|
</if>
|
<if test="deptcodes != null and deptcodes.size() > 0">
|
ss.deptcode IN
|
<foreach collection="deptcodes" item="deptcode" open="(" separator="," close=")">
|
#{deptcode}
|
</foreach>
|
</if>
|
)
|
</if>
|
group by ss.libtemplateid
|
</select>
|
|
<!-- ================================================
|
「按 模板 + 问题」的答题【人数】(distinct sub_id)
|
|
为什么需要它:/statistics 的「答题人数 / 未答题人数」必须与「发送人数」同口径(都是【人】)。
|
原实现把「答题人数」取成了 selectSatisfactionFillStatByMatchedtext 的 count(*)(【明细行数】),
|
而同一条 (sub_id, questiontext) 可能对应多行明细(多选项 / 重复明细),
|
于是「未答题人数 = 发送人数 − 明细行数」会算成负数(实测 -120 = 15 − 135)。
|
这里补一条按问题聚合的 distinct 人数查询,专供「答题人数 / 未答题人数 / 答题率」使用;
|
平均分 / 最高分 / 最低分 / 各选项占比仍按明细行数统计(那些口径本来就是按行计,未改动)。
|
除聚合键与 distinct 之外,from/where 与 selectSatisfactionFillStatByMatchedtext 完全一致,
|
保证两者统计的是同一批数据。
|
================================================ -->
|
<select id="selectSatisfactionFillPersonCountByQuestion"
|
parameterType="com.ruoyi.satisfaction.domain.entity.SatisfactionStatQuery"
|
resultType="java.util.Map">
|
select ss.libtemplateid as libtemplateid,
|
ssd.questiontext as questiontext,
|
count(distinct ssd.sub_id) as cnt
|
from service_subtask_detail ssd
|
join service_subtask ss on ss.id = ssd.sub_id
|
where ssd.del_flag = 0
|
and ss.del_flag = 0
|
<if test="orgid != null and orgid != ''">
|
and ss.orgid = #{orgid}
|
</if>
|
<if test="campusid != null and campusid != ''">
|
and ss.campusid = #{campusid}
|
</if>
|
<if test="type != null and type != ''">and ss.type = #{type}</if>
|
<if test="startTime != null">
|
and ss.visit_time >= #{startTime}
|
</if>
|
<if test="endTime != null">
|
and ss.visit_time < date_add(#{endTime}, interval 1 day)
|
</if>
|
<if test="libTemplateIds != null and libTemplateIds.size() > 0">
|
and ss.libtemplateid IN
|
<foreach collection="libTemplateIds" item="libTemplateId" open="(" separator="," close=")">
|
#{libTemplateId}
|
</foreach>
|
</if>
|
<if test="(hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0) or (deptcodes != null and deptcodes.size() > 0)">
|
AND (
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0">
|
ss.leavehospitaldistrictcode IN
|
<foreach collection="hospitaldistrictcodes" item="hospitaldistrictcode" open="("
|
separator=","
|
close=")">
|
#{hospitaldistrictcode}
|
</foreach>
|
</if>
|
<if test="hospitaldistrictcodes != null and hospitaldistrictcodes.size() > 0 and deptcodes != null and deptcodes.size() > 0">
|
OR
|
</if>
|
<if test="deptcodes != null and deptcodes.size() > 0">
|
ss.deptcode IN
|
<foreach collection="deptcodes" item="deptcode" open="(" separator="," close=")">
|
#{deptcode}
|
</foreach>
|
</if>
|
)
|
</if>
|
group by ss.libtemplateid, ssd.questiontext
|
</select>
|
|
<!-- ================================================ 重复明细清理(满意度统计前置)
|
原属 ServiceSubtaskDetailMapper.xml,只有满意度统计调用(已核实),故一并搬入。
|
注意 deleteRepeatDetailByIds 是【写操作】:按 id 逻辑删除重复明细(del_flag=1)。 -->
|
|
<select id="selectRepeatDetailIds" resultType="Long">
|
SELECT d1.id
|
FROM service_subtask_detail d1
|
INNER JOIN (
|
SELECT sub_id, questiontext,
|
MAX(create_time) AS max_create_time,
|
MAX(id) AS keep_id
|
FROM service_subtask_detail
|
WHERE del_flag = 0
|
GROUP BY sub_id, questiontext
|
HAVING COUNT(*) > 1
|
) d2 ON d1.sub_id = d2.sub_id
|
AND d1.questiontext = d2.questiontext
|
AND (
|
d1.create_time < d2.max_create_time
|
OR (d1.create_time = d2.max_create_time AND d1.id < d2.keep_id)
|
)
|
WHERE d1.del_flag = 0
|
</select>
|
|
<update id="deleteRepeatDetailByIds">
|
UPDATE service_subtask_detail
|
SET del_flag = 1
|
WHERE del_flag = 0
|
AND id IN
|
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
#{id}
|
</foreach>
|
</update>
|
<!-- ================================================ 子任务(满意度统计取数)
|
对应原 getServiceSubtasks → selectServiceSubtaskList 中满意度实际用到的口径。
|
原文无默认排序/分页,这里同样不加。仅取 id、taskid 两列。 -->
|
<select id="selectMydSubtaskRefs"
|
resultType="com.ruoyi.satisfaction.domain.row.SatisfactionSubtaskRef">
|
SELECT id, taskid
|
FROM service_subtask
|
WHERE del_flag = 0
|
<if test="q.orgid != null and q.orgid != ''">
|
AND orgid = #{q.orgid}
|
</if>
|
<if test="q.campusid != null and q.campusid != ''">
|
AND campusid = #{q.campusid}
|
</if>
|
<if test="q.serviceType != null">
|
AND service_type = #{q.serviceType}
|
</if>
|
<if test="q.startOutHospTime != null">
|
AND date_format(endtime,'%y%m%d') >= date_format(#{q.startOutHospTime},'%y%m%d')
|
</if>
|
<if test="q.endOutHospTime != null">
|
AND date_format(endtime,'%y%m%d') <= date_format(#{q.endOutHospTime},'%y%m%d')
|
</if>
|
<if test="q.deptOrDistrict==1">
|
<if test="q.leavehospitaldistrictcodes != null and q.leavehospitaldistrictcodes.size() > 0">
|
AND leavehospitaldistrictcode IN
|
<foreach collection="q.leavehospitaldistrictcodes" item="districtcode" open="(" separator="," close=")">
|
#{districtcode}
|
</foreach>
|
</if>
|
</if>
|
<if test="q.leaveldeptcodes != null and q.leaveldeptcodes.size() > 0">
|
AND deptcode IN
|
<foreach collection="q.leaveldeptcodes" item="deptcode" open="(" separator="," close=")">
|
#{deptcode}
|
</foreach>
|
</if>
|
</select>
|
|
<!-- ================================================================
|
随访「满意度指数」取数(原 ServiceSubtaskServiceImpl#getSatisfactionIndex 用到的 5 条查询)
|
|
原实现依次调用了 5 个不同模块的 statement:
|
ServiceTaskMapper.selectServiceTaskList
|
IvrTaskTemplateScriptMapper.selectIvrTaskTemplateScriptList
|
SvyTaskTemplateScriptMapper.selectSvyTaskTemplateScriptList
|
ServiceSubtaskMapper.selectServiceSubtaskBySendstate
|
ServiceSubtaskDetailMapper.selectServiceSubtaskDetailList
|
调用方只用到它们的 size()/若干字段,因此这里各写一条【等价且精简】的查询:
|
- 只保留调用方真正设置过的条件(逐条对照原 statement 的 <if>);
|
- 计数场景直接用 count(*)(与 Java 侧 .size() 完全等价);
|
- 用到的 service_task / ivr_task_template_script / svy_task_template_script
|
是「随访任务与模板」表,本模块对它们只做【只读】查询,不写。
|
================================================================ -->
|
|
<!-- 原:ServiceTaskMapper.selectServiceTaskList
|
调用方只设了 (deptcode + orgid) 或 (leavehospitaldistrictcode + orgid),
|
两者互斥,所以一条 SQL 覆盖原来的两个分支。
|
注意 REGEXP 的写法与原 statement 逐字一致(匹配逗号分隔的编码串)。 -->
|
<select id="selectSatisfactionServiceTasks"
|
resultType="com.ruoyi.satisfaction.domain.row.SatisfactionTaskRow">
|
select taskid,
|
templateid,
|
type,
|
orgid
|
from service_task
|
where 1=1
|
and del_flag = 0
|
<if test="deptcode != null and deptcode != ''">
|
and deptcode REGEXP CONCAT('(^|,)', #{deptcode}, '(,|$)')
|
</if>
|
<if test="leavehospitaldistrictcode != null and leavehospitaldistrictcode != ''">
|
and leavehospitaldistrictcode REGEXP CONCAT('(^|,)', #{leavehospitaldistrictcode}, '(,|$)')
|
</if>
|
<if test="orgid != null and orgid != ''">
|
and orgid = #{orgid}
|
</if>
|
order by update_time desc, taskid desc
|
</select>
|
|
<!-- 原:IvrTaskTemplateScriptMapper.selectIvrTaskTemplateScriptList(只用到 3 个条件) -->
|
<select id="countIvrTaskTemplateScripts" resultType="int">
|
select count(*)
|
from ivr_task_template_script
|
where 1=1
|
and del_flag = 0
|
<if test="templateID != null">
|
and templateID = #{templateID}
|
</if>
|
<if test="orgid != null and orgid != ''">
|
and orgid = #{orgid}
|
</if>
|
<if test="scriptAssortid != null">
|
and script_assortid = #{scriptAssortid}
|
</if>
|
</select>
|
|
<!-- 原:SvyTaskTemplateScriptMapper.selectSvyTaskTemplateScriptList(只用到 3 个条件) -->
|
<select id="countSvyTaskTemplateScripts" resultType="int">
|
select count(*)
|
from svy_task_template_script
|
where del_flag = 0
|
<if test="templateID != null">
|
and templateID = #{templateID}
|
</if>
|
<if test="orgid != null and orgid != ''">
|
and orgid = #{orgid}
|
</if>
|
<if test="categoryid != null">
|
and categoryid = #{categoryid}
|
</if>
|
</select>
|
|
<!-- 原:ServiceSubtaskMapper.selectServiceSubtaskBySendstate
|
调用方只设了 taskid 与 sendstates(3,5,6);orgid 未设置,故这里不含该条件。 -->
|
<select id="countSubtaskBySendstates" resultType="int">
|
select count(*)
|
from service_subtask
|
where 1=1
|
and del_flag = 0
|
<if test="taskid != null">
|
and taskid = #{taskid}
|
</if>
|
<if test="sendstates != null">
|
AND sendstate IN
|
<foreach collection="sendstates" item="sendstate" open="(" separator="," close=")">
|
#{sendstate}
|
</foreach>
|
</if>
|
</select>
|
|
<!-- 原:ServiceSubtaskDetailMapper.selectServiceSubtaskDetailList
|
⚠️ 原文【没有】 del_flag 条件,这里同样不加,避免口径变化。
|
categoryid 仅在任务类型为语音/问卷时才被原实现设置,故用 <if> 保住"不设即不过滤"。 -->
|
<select id="countSubtaskDetail" resultType="int">
|
select count(*)
|
from service_subtask_detail
|
where 1=1
|
<if test="taskid != null">
|
and taskid = #{taskid}
|
</if>
|
<if test="categoryid != null">
|
and categoryid = #{categoryid}
|
</if>
|
<if test="orgid != null and orgid != ''">
|
and orgid = #{orgid}
|
</if>
|
</select>
|
|
</mapper>
|