ソースを参照

アンケート回答集計結果画面作成

quyx@nextosd.com 5 ヶ月 前
コミット
18f07a75fd

+ 4 - 0
yamada-admin/src/main/resources/i18n/messages.properties

@@ -76,6 +76,7 @@ EM013=\u30AA\u30D7\u30B7\u30E7\u30F3\u8A2D\u554F\u6587{0}\u306E\u9078\u629E\u80A
 EM014=\u30AA\u30D7\u30B7\u30E7\u30F3\u8A2D\u554F\u6587{0}\u306E\u9078\u629E\u80A22\u306F1 ~ 999\u3057\u304B\u5165\u529B\u3067\u304D\u307E\u305B\u3093
 EM015=\u958B\u59CB\u65E5\u306F\u7D42\u4E86\u65E5\u672A\u6E80\u3067\u306A\u3051\u308C\u3070\u306A\u308A\u307E\u305B\u3093
 EM016=\u8A2D\u554F\u6587{0} \u9078\u629E\u80A2{1}\u306F{2}\u6587\u5B57\u4EE5\u4E0B\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044\u3002
+EM017={0}\u3092\u5C11\u306A\u304F\u3068\u30821\u3064\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002
 I0003=\u53D6\u8FBC\u306B\u6210\u529F\u3057\u307E\u3057\u305F\u3002
 I0004=\u53D6\u8FBC\u306B\u5931\u6557\u3057\u307E\u3057\u305F\u3002
 I0008=\u30ED\u30B0\u30A4\u30F3\u3057\u307E\u3057\u305F\u3002
@@ -165,5 +166,8 @@ description=\u8AAC\u660E\u6587
 questionText=\u8A2D\u554F\u6587
 optionText=\u9078\u629E\u80A2\u5185\u5BB9
 questionUnit=\u5358\u4F4D
+brandCode=FC
+businessTypeCode=\u696D\u7A2E
+regions=\u30A8\u30EA\u30A2
 
 

+ 22 - 3
yamada-fcbi/src/main/java/jp/yamada/fcbi/controller/YmdfSurveyController.java

@@ -5,6 +5,8 @@ import java.util.List;
 import java.util.Map;
 
 import jakarta.servlet.http.HttpServletResponse;
+import jp.yamada.common.utils.StringUtils;
+import jp.yamada.fcbi.domain.TBaseOrder;
 import jp.yamada.fcbi.mapper.YmdfFcApplicantMapper;
 import jp.yamada.fcbi.param.YmdfSurveyParam;
 import jp.yamada.fcbi.service.IYmdfFcMemberService;
@@ -49,7 +51,19 @@ public class YmdfSurveyController extends BaseController
     {
         startPage();
         List<YmdfSurvey> list = ymdfSurveyService.selectYmdfSurveyList(ymdfSurvey);
-        ymdfFcMemberService.createMemberAndStore("007fa160-d371-4f3e-9411-a9ced3fc6629");
+//        ymdfFcMemberService.createMemberAndStore("007fa160-d371-4f3e-9411-a9ced3fc6629");
+        return getDataTable(list);
+    }
+
+    /**
+     *  アンケート回答集計結果の取得
+     */
+    @PreAuthorize("@ss.hasPermi('system:survey:list')")
+    @GetMapping("/detailsList")
+    public TableDataInfo detailsList(YmdfSurvey ymdfSurvey)
+    {
+        startPage();
+        List<YmdfSurvey> list = ymdfSurveyService.selectYmdfSurveyDetailsList(ymdfSurvey);
         return getDataTable(list);
     }
 
@@ -74,9 +88,14 @@ public class YmdfSurveyController extends BaseController
     @PostMapping("/export")
     public void export(HttpServletResponse response, YmdfSurvey ymdfSurvey)
     {
-        List<YmdfSurvey> list = ymdfSurveyService.selectYmdfSurveyList(ymdfSurvey);
+        List<YmdfSurvey> list = ymdfSurveyService.selectYmdfSurveyDetailsList(ymdfSurvey);
+        for (YmdfSurvey survey : list) {
+            if (StringUtils.isNotEmpty(survey.getCompletionRate())) {
+                survey.setCompletionRate(survey.getCompletionRate() + "%");
+            }
+        }
         ExcelUtil<YmdfSurvey> util = new ExcelUtil<YmdfSurvey>(YmdfSurvey.class);
-        util.exportExcel(response, list, "調査アンケート主(時間制御と状態管理を含む)数据");
+        util.exportCsv(response, list, "調査アンケート主(時間制御と状態管理を含む)数据");
     }
 
     /**

+ 23 - 9
yamada-fcbi/src/main/java/jp/yamada/fcbi/domain/YmdfSurvey.java

@@ -12,6 +12,7 @@ import lombok.EqualsAndHashCode;
 import lombok.Getter;
 import lombok.Setter;
 import jp.yamada.common.core.domain.BaseEntity;
+import net.sf.jsqlparser.expression.DateTimeLiteralExpression;
 
 
 /**
@@ -40,25 +41,20 @@ public class YmdfSurvey extends BaseEntity
     private String title;
 
     /** アンケート説明 */
-    @Excel(name = "アンケート説明")
     private String description;
 
     /** 公開モード:INSTANT-即時公開,PERIOD-期間指定 */
-    @Excel(name = "公開モード:INSTANT-即時公開,PERIOD-期間指定")
     private String publicMode;
 
     /** 公開開始日(期間指定のみ有効) */
     @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "公開開始日", readConverterExp = "期=間指定のみ有効")
     private Date publicStartTime;
 
     /** 公開終了日(期間指定のみ有効) */
     @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "公開終了日", readConverterExp = "期=間指定のみ有効")
     private Date publicEndTime;
 
     /** 状態:0-下書き,1-公開,2-終了,3-期限切れ */
-    @Excel(name = "状態:0-下書き,1-公開,2-終了,3-期限切れ")
     private Integer status;
 
     /**
@@ -66,6 +62,8 @@ public class YmdfSurvey extends BaseEntity
      */
     private Integer delFlag;
 
+    private Integer answerFlag;
+
     /**
      * リビジョン
      */
@@ -86,8 +84,24 @@ public class YmdfSurvey extends BaseEntity
     private List<QuestionInfoVo> questions;
     private List<String> errors;
 
-    private String relatedFc;           // 関連するFCブランド
-    private String relatedBusinessType; // 関連する業種
-    private String relatedRegion;       // 関連する親地区
-    private Integer questionCount;      // 問題数
+    private String relatedFc;
+    private String relatedBusinessType;
+    private String relatedRegion;
+    private Integer questionCount;
+
+    @Excel(name = "FC会員名")
+    private String fcMemberName;
+    @Excel(name = "回答状態")
+    private String answerStatus;
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "回答日付", dateFormat = "yyyy-MM-dd")
+    private Date answerTime;
+    @Excel(name = "質問総数")
+    private String totalQuestions;
+    @Excel(name = "回答数")
+    private String answeredQuestions;
+    @Excel(name = "未回答数")
+    private String unansweredQuestions;
+    @Excel(name = "回答完成率", suffix = "%")
+    private String completionRate;
 }

+ 39 - 0
yamada-fcbi/src/main/java/jp/yamada/fcbi/enums/AnswerFlagEnum.java

@@ -0,0 +1,39 @@
+package jp.yamada.fcbi.enums;
+
+import lombok.Getter;
+
+/**
+ * に答えるフラグのコード定数
+ *
+ * @author fcbi
+ * @date 2025-07-16
+ */
+@Getter
+public enum AnswerFlagEnum {
+    /**
+     * 0:未に答える
+     */
+    OFF(0),
+    /**
+     * 1:に答える
+     */
+    ON(1);
+
+    private final Integer code;
+
+    AnswerFlagEnum(final Integer code) {
+        this.code = code;
+    }
+
+    public static AnswerFlagEnum fromCode(Integer code) {
+        if (code == null) {
+            return null;
+        }
+        for (AnswerFlagEnum value : values()) {
+            if (value.code.equals(code)) {
+                return value;
+            }
+        }
+        throw new IllegalArgumentException("Invalid code: " + code);
+    }
+}

+ 8 - 0
yamada-fcbi/src/main/java/jp/yamada/fcbi/mapper/YmdfSurveyMapper.java

@@ -33,6 +33,14 @@ public interface YmdfSurveyMapper
      List<YmdfSurvey> selectYmdfSurveyList(YmdfSurvey ymdfSurvey);
 
     /**
+     * アンケート回答集計結果の取得
+     *
+     * @param ymdfSurvey アンケート回答集計結果の取得
+     * @return アンケート回答集計結果の取得
+     */
+    List<YmdfSurvey> selectYmdfSurveyDetailsList(YmdfSurvey ymdfSurvey);
+
+    /**
      * クエリー領域のツリー構造データ
      * @return 地域ツリーを含むMapオブジェクト
      */

+ 9 - 0
yamada-fcbi/src/main/java/jp/yamada/fcbi/service/IYmdfSurveyService.java

@@ -3,6 +3,7 @@ package jp.yamada.fcbi.service;
 import java.util.List;
 import java.util.Map;
 
+import jp.yamada.fcbi.domain.TBaseOrder;
 import jp.yamada.fcbi.domain.YmdfSurvey;
 import jp.yamada.fcbi.param.YmdfSurveyParam;
 
@@ -31,6 +32,14 @@ public interface IYmdfSurveyService
     public List<YmdfSurvey> selectYmdfSurveyList(YmdfSurvey ymdfSurvey);
 
     /**
+     * アンケート回答集計結果の取得
+     *
+     * @param ymdfSurvey アンケート回答集計結果の取得
+     * @return アンケート回答集計結果の取得
+     */
+    public List<YmdfSurvey> selectYmdfSurveyDetailsList(YmdfSurvey ymdfSurvey);
+
+    /**
      * 地域ツリー構造データの取得
      * @return 地域ツリーJSON構造
      */

+ 13 - 1
yamada-fcbi/src/main/java/jp/yamada/fcbi/service/impl/YmdfSurveyServiceImpl.java

@@ -91,6 +91,18 @@ public class YmdfSurveyServiceImpl implements IYmdfSurveyService
     }
 
     /**
+     * アンケート回答集計結果の取得
+     *
+     * @param ymdfSurvey アンケート回答集計結果の取得
+     * @return アンケート回答集計結果の取得
+     */
+    @Override
+    public List<YmdfSurvey> selectYmdfSurveyDetailsList(YmdfSurvey ymdfSurvey)
+    {
+        return ymdfSurveyMapper.selectYmdfSurveyDetailsList(ymdfSurvey);
+    }
+
+    /**
      * 新增調査アンケート主(時間制御と状態管理を含む)
      *
      * @param ymdfSurveyParam 調査アンケート主(時間制御と状態管理を含む)
@@ -108,7 +120,7 @@ public class YmdfSurveyServiceImpl implements IYmdfSurveyService
             return errors;
         }
 
-        if (ymdfSurveyParam.getInsertFlag() != null && ymdfSurveyParam.getInsertFlag() == 1) {
+        if (Integer.valueOf(1).equals(ymdfSurveyParam.getInsertFlag())) {
             // UUIDを生成してマスターテーブルに設定する
             String uuid = IdUtils.nextIdStr(PrefixIdConstants.SURVEY_ID);
             ymdfSurveyParam.setSurveyId(uuid);

+ 80 - 3
yamada-fcbi/src/main/resources/mapper/fcbi/YmdfSurveyMapper.xml

@@ -17,6 +17,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="relatedBusinessType" column="related_business_type"/>
         <result property="relatedRegion" column="related_region"/>
         <result property="questionCount" column="question_count"/>
+        <result property="answerFlag" column="answerFlag"/>
+        <result property="fcMemberName" column="fc_member_name"/>
+        <result property="answerStatus" column="answer_status"/>
+        <result property="answerTime" column="answer_time"/>
+        <result property="totalQuestions" column="total_questions"/>
+        <result property="answeredQuestions" column="answered_questions"/>
+        <result property="unansweredQuestions" column="unanswered_questions"/>
+        <result property="completionRate" column="completion_rate"/>
     </resultMap>
 
     <sql id="selectYmdfSurveyVo">
@@ -34,7 +42,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             GROUP_CONCAT(DISTINCT fc_dict.dict_label ORDER BY fc_dict.dict_sort SEPARATOR '/') AS related_fc,
             GROUP_CONCAT(DISTINCT bt_dict.dict_label ORDER BY bt_dict.dict_sort SEPARATOR '/') AS related_business_type,
             GROUP_CONCAT(DISTINCT parent_region.region_name ORDER BY parent_region.sort_order SEPARATOR '/') AS related_region,
-            COUNT(DISTINCT q.question_id) AS question_count
+            COUNT(DISTINCT q.question_id) AS question_count,
+            CASE
+                WHEN EXISTS (
+                    SELECT 1
+                    FROM ymdf_survey_answer a
+                    WHERE a.survey_id = s.survey_id
+                      AND a.del_flag = 0
+                ) THEN 1
+                ELSE 0
+                END AS answerFlag
         FROM
             ymdf_survey s
                 LEFT JOIN ymdf_survey_brand b ON s.survey_id = b.survey_id AND b.del_flag = 0
@@ -53,6 +70,47 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             s.create_time DESC
     </sql>
 
+    <sql id="selectYmdfSurveyAnswerListVo">
+        SELECT
+            s.survey_code AS survey_code,
+            s.title AS title,
+            m.fc_member_name AS fc_member_name,
+            dict.dict_label AS answer_status,
+            MAX(a.answer_time) AS answer_time,
+            COUNT(DISTINCT q.question_id) AS total_questions,
+            COUNT(DISTINCT CASE WHEN a.question_id IS NOT NULL THEN a.question_id END) AS answered_questions,
+            COUNT(DISTINCT q.question_id) - COUNT(DISTINCT CASE WHEN a.question_id IS NOT NULL THEN a.question_id END) AS unanswered_questions,
+            CASE
+                WHEN COUNT(DISTINCT q.question_id) = 0 THEN 0.00
+                ELSE ROUND(
+                        (COUNT(DISTINCT CASE WHEN a.question_id IS NOT NULL THEN a.question_id END)
+                            / COUNT(DISTINCT q.question_id)) * 100,
+                        2
+                     )
+                END AS completion_rate
+        FROM
+            ymdf_survey s
+                LEFT JOIN ymdf_survey_question q
+                          ON s.survey_id = q.survey_id
+                              AND q.del_flag = 0
+                LEFT JOIN ymdf_survey_answer a
+                          ON s.survey_id = a.survey_id
+                              AND a.del_flag = 0
+                LEFT JOIN ymdf_fc_member m
+                          ON a.fc_member_id = m.fc_member_id
+                              AND m.del_flag = 0
+                LEFT JOIN sys_dict_data dict
+                          ON a.answer_status = dict.dict_value
+                              AND dict.dict_type = 'answer_status'
+        WHERE
+            s.del_flag = 0
+        GROUP BY
+            s.survey_id, s.survey_code, s.title, m.fc_member_name, a.answer_status, dict.dict_label
+        ORDER BY
+            s.create_time DESC,
+            completion_rate DESC
+    </sql>
+
     <select id="selectYmdfSurveyList" parameterType="YmdfSurvey" resultMap="YmdfSurveyResult">
         SELECT * FROM (
         <include refid="selectYmdfSurveyListVo"/>
@@ -65,14 +123,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 AND t.survey_code = #{surveyCode}
             </if>
             <if test="publicStartTime != null">
-                AND t.public_start_time = #{publicStartTime}
+                <![CDATA[ AND t.public_start_time >= #{publicStartTime} ]]>
             </if>
             <if test="publicEndTime != null">
-                AND t.public_end_time = #{publicEndTime}
+                <![CDATA[ AND t.public_end_time <= #{publicEndTime} ]]>
             </if>
         </where>
     </select>
 
+    <select id="selectYmdfSurveyDetailsList" parameterType="YmdfSurvey" resultMap="YmdfSurveyResult">
+        SELECT * FROM (
+        <include refid="selectYmdfSurveyAnswerListVo"/>
+        ) t
+        <where>
+            <if test="fcMemberName != null and fcMemberName != ''">
+                AND t.fc_member_name LIKE CONCAT('%', #{fcMemberName}, '%')
+            </if>
+            <if test="surveyCode != null and surveyCode != ''">
+                AND t.survey_code = #{surveyCode}
+            </if>
+            <if test="publicStartTime != null">
+                <![CDATA[ AND DATE(t.answer_time) >= DATE(#{publicStartTime}) ]]>
+            </if>
+            <if test="publicEndTime != null">
+                <![CDATA[ AND DATE(t.answer_time) <= DATE(#{publicEndTime}) ]]>
+            </if>
+        </where>
+    </select>
     <select id="selectRegionTree" resultType="map">
         SELECT
             JSON_OBJECT(