commit
This commit is contained in:
+29
-2
@@ -1,6 +1,7 @@
|
|||||||
package com.budwk.app.zhgh.dayofficework.qsv.controller;
|
package com.budwk.app.zhgh.dayofficework.qsv.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import com.budwk.app.base.annotation.SLog;
|
import com.budwk.app.base.annotation.SLog;
|
||||||
@@ -77,8 +78,34 @@ public class QsvSurveyController {
|
|||||||
@SaCheckPermission("qsv.survey")
|
@SaCheckPermission("qsv.survey")
|
||||||
@ApiOperation("选项选择详情")
|
@ApiOperation("选项选择详情")
|
||||||
public Result selectOptionUsers(@Valid String activityId, @Valid String subjectId, @Valid String optionId) {
|
public Result selectOptionUsers(@Valid String activityId, @Valid String subjectId, @Valid String optionId) {
|
||||||
List<QsvUserAnswerRecord> answerRecords = dao.query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId));
|
List<QsvUserAnswerRecord> answerRecords = dao.query(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
|
||||||
List<QsvUserAnswerRecord> selectOptionUsers = answerRecords.stream().filter(ext -> ObjectUtil.isNotNull(ext.getExtJson().get(subjectId, JSONObject.class)) && ext.getExtJson().get(subjectId, JSONObject.class).getJSONArray("optionIds").contains(optionId)).toList();
|
.and("isFinish", "=", true));
|
||||||
|
List<NutMap> selectOptionUsers = answerRecords.stream().map(record -> {
|
||||||
|
JSONObject extJson = record.getExtJson();
|
||||||
|
if (ObjectUtil.isEmpty(extJson)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSONObject subjectAnswer = extJson.get(subjectId, JSONObject.class);
|
||||||
|
if (ObjectUtil.isEmpty(subjectAnswer)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSONArray optionIds = subjectAnswer.getJSONArray("optionIds");
|
||||||
|
if (ObjectUtil.isEmpty(optionIds) || !optionIds.contains(optionId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
JSONObject optionFillContents = subjectAnswer.getJSONObject("optionFillContents");
|
||||||
|
String fillContent = ObjectUtil.isEmpty(optionFillContents) ? "" : optionFillContents.getStr(optionId);
|
||||||
|
return NutMap.NEW()
|
||||||
|
.addv("userName", record.getUserName())
|
||||||
|
.addv("loginName", record.getLoginName())
|
||||||
|
.addv("unionName", record.getUnionName())
|
||||||
|
.addv("unitName", record.getUnitName())
|
||||||
|
.addv("attemptDate", record.getAttemptDate())
|
||||||
|
.addv("submitTime", record.getSubmitTime())
|
||||||
|
.addv("fillContent", fillContent);
|
||||||
|
})
|
||||||
|
.filter(ObjectUtil::isNotNull)
|
||||||
|
.toList();
|
||||||
return Result.success(selectOptionUsers);
|
return Result.success(selectOptionUsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+51
-2
@@ -12,6 +12,8 @@ import com.budwk.app.zhgh.dayofficework.qsv.param.QsvAnswerParam;
|
|||||||
import com.budwk.app.zhgh.dayofficework.qsv.service.QsvUserAnswerRecordService;
|
import com.budwk.app.zhgh.dayofficework.qsv.service.QsvUserAnswerRecordService;
|
||||||
import org.nutz.dao.Cnd;
|
import org.nutz.dao.Cnd;
|
||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
|
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||||
|
import org.nutz.ioc.aop.Aop;
|
||||||
import org.nutz.ioc.loader.annotation.Inject;
|
import org.nutz.ioc.loader.annotation.Inject;
|
||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
import org.nutz.lang.util.NutMap;
|
import org.nutz.lang.util.NutMap;
|
||||||
@@ -23,6 +25,7 @@ import javax.validation.Valid;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@IocBean
|
@IocBean
|
||||||
@At("/platform/h5/qsv/survey")
|
@At("/platform/h5/qsv/survey")
|
||||||
@@ -40,6 +43,7 @@ public class H5QsvSurveyController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Result subjects(String activityId) {
|
public Result subjects(String activityId) {
|
||||||
QsvActivity activity = dao.fetch(QsvActivity.class, activityId);
|
QsvActivity activity = dao.fetch(QsvActivity.class, activityId);
|
||||||
|
|
||||||
@@ -51,16 +55,17 @@ public class H5QsvSurveyController {
|
|||||||
|
|
||||||
String answerRecordId = null;
|
String answerRecordId = null;
|
||||||
|
|
||||||
|
List<QsvSubject> activitySubjects = dao.query(QsvSubject.class, Cnd.where("activityId", "=", activityId).asc("sortNum"));
|
||||||
QsvUserAnswerRecord answerRecord = dao.fetch(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
|
QsvUserAnswerRecord answerRecord = dao.fetch(QsvUserAnswerRecord.class, Cnd.where("activityId", "=", activityId)
|
||||||
.and("userId", "=", SecurityUtil.getUserId()));
|
.and("userId", "=", SecurityUtil.getUserId()));
|
||||||
if (answerRecord == null) {
|
if (answerRecord == null) {
|
||||||
List<QsvSubject> subjects = dao.query(QsvSubject.class, Cnd.where("activityId", "=", activityId).asc("sortNum"));
|
qsvUserAnswerRecordService.insertRecord(activityId, activitySubjects.stream().map(QsvSubject::getId).toList());
|
||||||
qsvUserAnswerRecordService.insertRecord(activityId, subjects.stream().map(QsvSubject::getId).toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QsvUserAnswerRecord answerRecord2 = dao.fetch(QsvUserAnswerRecord.class,
|
QsvUserAnswerRecord answerRecord2 = dao.fetch(QsvUserAnswerRecord.class,
|
||||||
Cnd.where("activityId", "=", activityId)
|
Cnd.where("activityId", "=", activityId)
|
||||||
.and("userId", "=", SecurityUtil.getUserId()));
|
.and("userId", "=", SecurityUtil.getUserId()));
|
||||||
|
syncAnswerRecordSubjects(answerRecord2, activitySubjects);
|
||||||
|
|
||||||
answerRecordId = answerRecord2.getId();
|
answerRecordId = answerRecord2.getId();
|
||||||
|
|
||||||
@@ -77,6 +82,48 @@ public class H5QsvSurveyController {
|
|||||||
return Result.success(result);
|
return Result.success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步问卷当前题目到未完成答题记录。后台新增题目后,已进入过问卷的用户记录里没有新题ID,
|
||||||
|
* 这里补齐 subjectIds 和 extJson,保证手机端能拿到最新题目并正常提交答案。
|
||||||
|
*
|
||||||
|
* @param answerRecord 用户当前问卷答题记录
|
||||||
|
* @param activitySubjects 当前活动下按排序查询出的最新题目列表
|
||||||
|
*/
|
||||||
|
private void syncAnswerRecordSubjects(QsvUserAnswerRecord answerRecord, List<QsvSubject> activitySubjects) {
|
||||||
|
if (answerRecord == null || Boolean.TRUE.equals(answerRecord.getIsFinish())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> currentSubjectIds = activitySubjects.stream().map(QsvSubject::getId).collect(Collectors.toList());
|
||||||
|
List<String> recordSubjectIds = answerRecord.getSubjectIds();
|
||||||
|
if (recordSubjectIds == null) {
|
||||||
|
recordSubjectIds = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject extJson = answerRecord.getExtJson();
|
||||||
|
if (extJson == null) {
|
||||||
|
extJson = new JSONObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean changed = !recordSubjectIds.equals(currentSubjectIds);
|
||||||
|
for (String subjectId : currentSubjectIds) {
|
||||||
|
if (ObjectUtil.isEmpty(extJson.get(subjectId, JSONObject.class))) {
|
||||||
|
JSONObject entry = new JSONObject();
|
||||||
|
entry.set("optionIds", new ArrayList<>());
|
||||||
|
entry.set("text", null);
|
||||||
|
entry.set("optionFillContents", new JSONObject());
|
||||||
|
extJson.set(subjectId, entry);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
answerRecord.setSubjectIds(currentSubjectIds);
|
||||||
|
answerRecord.setExtJson(extJson);
|
||||||
|
dao.update(answerRecord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
public Result answerRecord(@Valid String answerRecordId) {
|
public Result answerRecord(@Valid String answerRecordId) {
|
||||||
QsvUserAnswerRecord record = dao.fetch(QsvUserAnswerRecord.class, answerRecordId);
|
QsvUserAnswerRecord record = dao.fetch(QsvUserAnswerRecord.class, answerRecordId);
|
||||||
@@ -84,6 +131,7 @@ public class H5QsvSurveyController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public Result submitAnswer(@Valid @Param("answer") QsvAnswerParam qsvAnswerParam) {
|
public Result submitAnswer(@Valid @Param("answer") QsvAnswerParam qsvAnswerParam) {
|
||||||
QsvUserAnswerRecord answerRecord = dao.fetch(QsvUserAnswerRecord.class, qsvAnswerParam.getAnswerRecordId());
|
QsvUserAnswerRecord answerRecord = dao.fetch(QsvUserAnswerRecord.class, qsvAnswerParam.getAnswerRecordId());
|
||||||
JSONObject extJson = answerRecord.getExtJson();
|
JSONObject extJson = answerRecord.getExtJson();
|
||||||
@@ -93,6 +141,7 @@ public class H5QsvSurveyController {
|
|||||||
if (ObjectUtil.isNotEmpty(entries)) {
|
if (ObjectUtil.isNotEmpty(entries)) {
|
||||||
entries.set("optionIds", subject.getUserSelectOptionIds());
|
entries.set("optionIds", subject.getUserSelectOptionIds());
|
||||||
entries.set("text", subject.getUserFillContent());
|
entries.set("text", subject.getUserFillContent());
|
||||||
|
entries.set("optionFillContents", subject.getOptionFillContents());
|
||||||
}
|
}
|
||||||
extJson.set(subject.getId(), entries);
|
extJson.set(subject.getId(), entries);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,16 @@ public class QsvOption extends BaseModel implements Serializable {
|
|||||||
@ColDefine(customType = "longtext")
|
@ColDefine(customType = "longtext")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("选中后是否需要填写补充内容")
|
||||||
|
@ColDefine(type = ColType.BOOLEAN)
|
||||||
|
private Boolean fillRequired;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("补充内容输入提示")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 255)
|
||||||
|
private String fillPlaceholder;
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
@Comment("排序")
|
@Comment("排序")
|
||||||
@ColDefine(type = ColType.INT)
|
@ColDefine(type = ColType.INT)
|
||||||
|
|||||||
@@ -63,6 +63,26 @@ public class QsvSubject extends BaseModel implements Serializable {
|
|||||||
@ColDefine(type = ColType.INT, width = 1)
|
@ColDefine(type = ColType.INT, width = 1)
|
||||||
private Integer sortNum;
|
private Integer sortNum;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("是否启用题目隐显逻辑")
|
||||||
|
@ColDefine(type = ColType.BOOLEAN)
|
||||||
|
private Boolean visibleRuleEnabled;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("隐显逻辑处理方式(show显示,hide隐藏)")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
private String visibleRuleAction;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("隐显逻辑条件关系(AND并且,OR或者)")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 20)
|
||||||
|
private String visibleRuleLogic;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("隐显逻辑条件列表")
|
||||||
|
@ColDefine(type = ColType.MYSQL_JSON)
|
||||||
|
private List<VisibleRuleCondition> visibleRuleConditions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选项
|
* 选项
|
||||||
*/
|
*/
|
||||||
@@ -79,4 +99,22 @@ public class QsvSubject extends BaseModel implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String userFillContent;
|
private String userFillContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 题目隐显逻辑条件,一条条件表示选择指定题目的指定选项后参与显示或隐藏判断。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public static class VisibleRuleCondition implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作为触发条件的题目ID。
|
||||||
|
*/
|
||||||
|
private String subjectId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作为触发条件的选项ID。
|
||||||
|
*/
|
||||||
|
private String optionId;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.budwk.app.zhgh.dayofficework.qsv.param;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
//答题参数
|
//答题参数
|
||||||
@@ -21,6 +22,7 @@ public class QsvAnswerParam {
|
|||||||
private String id;
|
private String id;
|
||||||
private List<String> userSelectOptionIds;
|
private List<String> userSelectOptionIds;
|
||||||
private String userFillContent;
|
private String userFillContent;
|
||||||
|
private Map<String, String> optionFillContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+106
-40
@@ -68,47 +68,47 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
|||||||
// 处理每个题目
|
// 处理每个题目
|
||||||
for (NutMap subject : subjects) {
|
for (NutMap subject : subjects) {
|
||||||
// 获取当前题目的选项列表
|
// 获取当前题目的选项列表
|
||||||
List<NutMap> subjectOptions = Lang.collection2list(optionsGroup.get(subject.getString("id")), NutMap.class);
|
List<QsvOption> currentOptions = optionsGroup.get(subject.getString("id"));
|
||||||
|
List<NutMap> subjectOptions = ObjectUtil.isEmpty(currentOptions) ? new ArrayList<>() : Lang.collection2list(currentOptions, NutMap.class);
|
||||||
|
|
||||||
// 获取题目类型
|
// 获取题目类型
|
||||||
String subjectType = subject.getString("type");
|
String subjectType = subject.getString("type");
|
||||||
|
|
||||||
// 处理文本类型题目
|
// 处理文本类型题目
|
||||||
if ("text".equals(subjectType)) {
|
if ("text".equals(subjectType)) {
|
||||||
List<String> texts = answerExtList.stream()
|
List<NutMap> textAnswers = buildTextAnswerDetails(answerRecords, subject.getString("id"));
|
||||||
.filter(ext -> ObjectUtil.isNull(ext.get(subject.getString("id"), JSONObject.class)))
|
List<String> texts = textAnswers.stream()
|
||||||
.map(ext -> ext.get(subject.getString("id"), JSONObject.class).getStr("text"))
|
.map(textAnswer -> textAnswer.getString("text"))
|
||||||
.toList();
|
.toList();
|
||||||
subject.put("texts", texts);
|
subject.put("texts", texts);
|
||||||
|
subject.put("textAnswers", textAnswers);
|
||||||
}
|
}
|
||||||
// 处理单选类型题目 处理多选类型题目
|
// 处理单选类型题目 处理多选类型题目
|
||||||
else if ("radio".equals(subjectType) || "checkbox".equals(subjectType)) {
|
else if ("radio".equals(subjectType) || "checkbox".equals(subjectType)) {
|
||||||
long selectTotal = answerExtList.stream()
|
long selectTotal = answerExtList.stream()
|
||||||
.filter(ext -> ext.containsKey(subject.getString("id")))
|
.filter(ext -> ObjectUtil.isNotEmpty(ext) && ext.containsKey(subject.getString("id")))
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
subjectOptions.forEach(subjectOption -> {
|
subjectOptions.forEach(subjectOption -> {
|
||||||
long selectCount = answerExtList.stream()
|
long selectCount = answerExtList.stream()
|
||||||
.filter(ext ->
|
.filter(ext ->
|
||||||
{
|
{
|
||||||
|
if (ObjectUtil.isEmpty(ext)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
JSONObject jsonObject = ext.get(subject.getString("id"), JSONObject.class);
|
JSONObject jsonObject = ext.get(subject.getString("id"), JSONObject.class);
|
||||||
return jsonObject != null
|
return jsonObject != null
|
||||||
&& jsonObject.getJSONArray("optionIds") != null
|
&& jsonObject.getJSONArray("optionIds") != null
|
||||||
&& jsonObject.getJSONArray("optionIds").contains(subjectOption.getString("id"));
|
&& jsonObject.getJSONArray("optionIds").contains(subjectOption.getString("id"));
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
long round = Math.round((double) selectCount / selectTotal * 100);
|
long round = selectTotal == 0 ? 0 : Math.round((double) selectCount / selectTotal * 100);
|
||||||
subjectOption.put("selectPercent", round + "%");
|
subjectOption.put("selectPercent", round + "%");
|
||||||
subjectOption.put("selectCount", selectCount);
|
subjectOption.put("selectCount", selectCount);
|
||||||
});
|
});
|
||||||
|
|
||||||
subjectOptions.sort((o1, o2) -> {
|
subjectOptions.sort((o1, o2) -> {
|
||||||
int count1 = o1.getInt("selectCount");
|
|
||||||
int count2 = o2.getInt("selectCount");
|
|
||||||
if (count1 == count2) {
|
|
||||||
return Integer.compare(o1.getInt("sortNum"), o2.getInt("sortNum"));
|
return Integer.compare(o1.getInt("sortNum"), o2.getInt("sortNum"));
|
||||||
}
|
|
||||||
return Integer.compare(count2, count1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
subject.put("selectTotal", selectTotal);
|
subject.put("selectTotal", selectTotal);
|
||||||
@@ -134,10 +134,8 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
|||||||
exportEntities.add(new ExcelExportEntity("选择人数", "selectCount", 20));
|
exportEntities.add(new ExcelExportEntity("选择人数", "selectCount", 20));
|
||||||
exportEntities.add(new ExcelExportEntity("选择比例", "selectPercent", 20));
|
exportEntities.add(new ExcelExportEntity("选择比例", "selectPercent", 20));
|
||||||
|
|
||||||
Map<String, List<NutMap>> listMap = report.stream().collect(Collectors.groupingBy(v -> v.getString("id")));
|
|
||||||
Workbook workbook = new XSSFWorkbook();
|
Workbook workbook = new XSSFWorkbook();
|
||||||
listMap.forEach((k, v) -> {
|
report.forEach(nutMap -> {
|
||||||
NutMap nutMap = v.get(0);
|
|
||||||
ExcelExportService service = new ExcelExportService();
|
ExcelExportService service = new ExcelExportService();
|
||||||
ExportParams exportParams = new ExportParams();
|
ExportParams exportParams = new ExportParams();
|
||||||
exportParams.setTitle(nutMap.getString("title"));
|
exportParams.setTitle(nutMap.getString("title"));
|
||||||
@@ -171,7 +169,7 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
|||||||
List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
|
List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
|
||||||
|
|
||||||
// 查询活动题目列表
|
// 查询活动题目列表
|
||||||
List<QsvSubject> subjects = dao().query(QsvSubject.class, Cnd.where("activityId", "=", activityId));
|
List<QsvSubject> subjects = dao().query(QsvSubject.class, Cnd.where("activityId", "=", activityId).asc("sortNum"));
|
||||||
// 将题目列表转换为Map
|
// 将题目列表转换为Map
|
||||||
Map<String, QsvSubject> subjectMap = subjects.stream().collect(Collectors.toMap(QsvSubject::getId, v -> v));
|
Map<String, QsvSubject> subjectMap = subjects.stream().collect(Collectors.toMap(QsvSubject::getId, v -> v));
|
||||||
// 获取题目ID列表
|
// 获取题目ID列表
|
||||||
@@ -185,7 +183,7 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
|||||||
// 构建Excel导出实体
|
// 构建Excel导出实体
|
||||||
List<ExcelExportEntity> excelExportEntities = buildExcelExportEntities(subjects);
|
List<ExcelExportEntity> excelExportEntities = buildExcelExportEntities(subjects);
|
||||||
// 构建答题记录列表
|
// 构建答题记录列表
|
||||||
List<NutMap> list = buildAnswerRecords(answerRecords, subjectMap, options);
|
List<NutMap> list = buildAnswerRecords(answerRecords, subjectMap, optionMap);
|
||||||
|
|
||||||
// 设置导出参数
|
// 设置导出参数
|
||||||
ExportParams exportParams = new ExportParams();
|
ExportParams exportParams = new ExportParams();
|
||||||
@@ -223,7 +221,7 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
|||||||
// List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
|
// List<JSONObject> answerExtList = answerRecords.stream().map(QsvUserAnswerRecord::getExtJson).toList();
|
||||||
|
|
||||||
// 查询活动题目列表
|
// 查询活动题目列表
|
||||||
List<QsvSubject> subjects = dao().query(QsvSubject.class, Cnd.where("activityId", "=", activityId));
|
List<QsvSubject> subjects = dao().query(QsvSubject.class, Cnd.where("activityId", "=", activityId).asc("sortNum"));
|
||||||
// 将题目列表转换为Map
|
// 将题目列表转换为Map
|
||||||
Map<String, QsvSubject> subjectMap = subjects.stream().collect(Collectors.toMap(QsvSubject::getId, v -> v));
|
Map<String, QsvSubject> subjectMap = subjects.stream().collect(Collectors.toMap(QsvSubject::getId, v -> v));
|
||||||
// 获取题目ID列表
|
// 获取题目ID列表
|
||||||
@@ -245,18 +243,15 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
|||||||
.addv("unitName", record.getString("unitName"))
|
.addv("unitName", record.getString("unitName"))
|
||||||
.addv("unionName", record.getString("unionName"));
|
.addv("unionName", record.getString("unionName"));
|
||||||
JSONObject extJson = record.getAs("extJson", JSONObject.class);
|
JSONObject extJson = record.getAs("extJson", JSONObject.class);
|
||||||
extJson.forEach((k, v) -> {
|
if (ObjectUtil.isEmpty(extJson)) {
|
||||||
JSONObject jsonVal = (JSONObject) v;
|
return map;
|
||||||
|
|
||||||
String type = subjectMap.get(k).getType();
|
|
||||||
if (type.equals("text")) {
|
|
||||||
map.addv(k, jsonVal.getStr("text"));
|
|
||||||
} else if (type.equals("radio") || type.equals("checkbox")) {
|
|
||||||
JSONArray optionIds = jsonVal.getJSONArray("optionIds");
|
|
||||||
String selectOptionTexts = options.stream().filter(option -> optionIds.contains(option.getId()))
|
|
||||||
.map(QsvOption::getText).collect(Collectors.joining(";"));
|
|
||||||
map.addv(k, selectOptionTexts);
|
|
||||||
}
|
}
|
||||||
|
extJson.forEach((k, v) -> {
|
||||||
|
QsvSubject subject = subjectMap.get(k);
|
||||||
|
if (subject == null || !(v instanceof JSONObject jsonVal)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
map.addv(k, buildAnswerText(jsonVal, subject, optionMap));
|
||||||
});
|
});
|
||||||
return map;
|
return map;
|
||||||
}).toList();
|
}).toList();
|
||||||
@@ -309,7 +304,37 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
|||||||
return excelExportEntities;
|
return excelExportEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<NutMap> buildAnswerRecords(List<QsvUserAnswerRecord> answerRecords, Map<String, QsvSubject> subjectMap, List<QsvOption> options) {
|
/**
|
||||||
|
* 构建填空题填写详情。分析弹窗需要同时展示填写内容和答题人信息,
|
||||||
|
* 因此这里从已完成答题记录中提取当前题目的文本答案,并携带姓名、工号、所属工会和单位。
|
||||||
|
*
|
||||||
|
* @param answerRecords 当前活动已完成的答题记录
|
||||||
|
* @param subjectId 当前填空题ID,用于从 extJson 中取出该题填写内容
|
||||||
|
* @return 填空题填写详情列表,每条包含 loginName、userName、unionName、unitName、submitTime、text
|
||||||
|
*/
|
||||||
|
private List<NutMap> buildTextAnswerDetails(List<QsvUserAnswerRecord> answerRecords, String subjectId) {
|
||||||
|
List<NutMap> textAnswers = new ArrayList<>();
|
||||||
|
for (QsvUserAnswerRecord answerRecord : answerRecords) {
|
||||||
|
JSONObject extJson = answerRecord.getExtJson();
|
||||||
|
if (ObjectUtil.isEmpty(extJson)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
JSONObject subjectAnswer = extJson.get(subjectId, JSONObject.class);
|
||||||
|
if (ObjectUtil.isEmpty(subjectAnswer) || ObjectUtil.isEmpty(subjectAnswer.getStr("text"))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
textAnswers.add(NutMap.NEW()
|
||||||
|
.addv("loginName", answerRecord.getLoginName())
|
||||||
|
.addv("userName", answerRecord.getUserName())
|
||||||
|
.addv("unionName", answerRecord.getUnionName())
|
||||||
|
.addv("unitName", answerRecord.getUnitName())
|
||||||
|
.addv("submitTime", answerRecord.getSubmitTime())
|
||||||
|
.addv("text", subjectAnswer.getStr("text")));
|
||||||
|
}
|
||||||
|
return textAnswers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<NutMap> buildAnswerRecords(List<QsvUserAnswerRecord> answerRecords, Map<String, QsvSubject> subjectMap, Map<String, QsvOption> optionMap) {
|
||||||
return answerRecords.stream().map(record -> {
|
return answerRecords.stream().map(record -> {
|
||||||
NutMap map = NutMap.NEW()
|
NutMap map = NutMap.NEW()
|
||||||
.addv("id", record.getId())
|
.addv("id", record.getId())
|
||||||
@@ -318,20 +343,61 @@ public class QsvSurveyServiceImpl extends BaseServiceImpl<QsvUserAnswerRecord> i
|
|||||||
.addv("unitName", record.getUnitName())
|
.addv("unitName", record.getUnitName())
|
||||||
.addv("unionName", record.getUnionName());
|
.addv("unionName", record.getUnionName());
|
||||||
JSONObject extJson = record.getExtJson();
|
JSONObject extJson = record.getExtJson();
|
||||||
extJson.forEach((k, v) -> {
|
if (ObjectUtil.isEmpty(extJson)) {
|
||||||
JSONObject jsonVal = (JSONObject) v;
|
return map;
|
||||||
|
|
||||||
String type = subjectMap.get(k).getType();
|
|
||||||
if (type.equals("text")) {
|
|
||||||
map.addv(k, jsonVal.getStr("text"));
|
|
||||||
} else if (type.equals("radio") || type.equals("checkbox")) {
|
|
||||||
JSONArray optionIds = jsonVal.getJSONArray("optionIds");
|
|
||||||
String selectOptionTexts = options.stream().filter(option -> optionIds.contains(option.getId()))
|
|
||||||
.map(QsvOption::getText).collect(Collectors.joining(";"));
|
|
||||||
map.addv(k, selectOptionTexts);
|
|
||||||
}
|
}
|
||||||
|
extJson.forEach((k, v) -> {
|
||||||
|
QsvSubject subject = subjectMap.get(k);
|
||||||
|
if (subject == null || !(v instanceof JSONObject jsonVal)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
map.addv(k, buildAnswerText(jsonVal, subject, optionMap));
|
||||||
});
|
});
|
||||||
return map;
|
return map;
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装单题答案展示内容。填空题返回填写文本;选择题返回选项文本,若选项配置了补充填写,
|
||||||
|
* 则追加对应补充内容,保证后台查看答卷和导出能看到用户填写的说明。
|
||||||
|
*
|
||||||
|
* @param jsonVal 答题记录 extJson 中当前题目的答案对象,包含 optionIds、text、optionFillContents
|
||||||
|
* @param subject 当前题目,用于判断题目类型
|
||||||
|
* @param optionMap 当前活动所有选项,key 为选项ID,value 为选项实体
|
||||||
|
* @return 当前题目的答案展示文本
|
||||||
|
*/
|
||||||
|
private String buildAnswerText(JSONObject jsonVal, QsvSubject subject, Map<String, QsvOption> optionMap) {
|
||||||
|
String type = subject.getType();
|
||||||
|
if ("text".equals(type)) {
|
||||||
|
return jsonVal.getStr("text");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!"radio".equals(type) && !"checkbox".equals(type)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray optionIds = jsonVal.getJSONArray("optionIds");
|
||||||
|
if (ObjectUtil.isEmpty(optionIds)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject optionFillContents = jsonVal.getJSONObject("optionFillContents");
|
||||||
|
List<String> answerTexts = new ArrayList<>();
|
||||||
|
for (Object optionIdObj : optionIds) {
|
||||||
|
String optionId = String.valueOf(optionIdObj);
|
||||||
|
QsvOption option = optionMap.get(optionId);
|
||||||
|
if (option == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String answerText = option.getText();
|
||||||
|
if (ObjectUtil.isNotEmpty(optionFillContents)) {
|
||||||
|
String fillContent = optionFillContents.getStr(optionId);
|
||||||
|
if (ObjectUtil.isNotEmpty(fillContent)) {
|
||||||
|
answerText = answerText + ":" + fillContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
answerTexts.add(answerText);
|
||||||
|
}
|
||||||
|
return String.join(";", answerTexts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,20 @@ const setting = {
|
|||||||
<el-form-item label="详情" prop="description">
|
<el-form-item label="详情" prop="description">
|
||||||
<text-editor v-model="formData.description"></text-editor>
|
<text-editor v-model="formData.description"></text-editor>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="补充填写" prop="fillRequired">
|
||||||
|
<el-switch
|
||||||
|
v-model="formData.fillRequired"
|
||||||
|
active-text="需要填写"
|
||||||
|
inactive-text="无需填写">
|
||||||
|
</el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="填写提示" prop="fillPlaceholder" v-if="formData.fillRequired">
|
||||||
|
<el-input
|
||||||
|
maxlength="255"
|
||||||
|
placeholder="例如:请填写原因"
|
||||||
|
v-model="formData.fillPlaceholder">
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div slot="footer" class="dialog-footer">
|
<div slot="footer" class="dialog-footer">
|
||||||
<el-button @click="visible = false">取 消</el-button>
|
<el-button @click="visible = false">取 消</el-button>
|
||||||
@@ -26,7 +40,11 @@ const setting = {
|
|||||||
methods:{
|
methods:{
|
||||||
onOpen(option,ext){
|
onOpen(option,ext){
|
||||||
console.log(option)
|
console.log(option)
|
||||||
this.formData = { ...option }
|
this.formData = {
|
||||||
|
...option,
|
||||||
|
fillRequired: !!option.fillRequired,
|
||||||
|
fillPlaceholder: option.fillPlaceholder || ""
|
||||||
|
}
|
||||||
this.ext = ext
|
this.ext = ext
|
||||||
this.visible = true
|
this.visible = true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ const subjectForm = {
|
|||||||
placeholder="请输入题目"
|
placeholder="请输入题目"
|
||||||
style="flex: 1">
|
style="flex: 1">
|
||||||
</el-input>
|
</el-input>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-setting"
|
||||||
|
size="mini"
|
||||||
|
style="margin-left: 8px;"
|
||||||
|
@click="openSubjectVisibleSetting(subjectIndex, subject)">
|
||||||
|
隐显逻辑
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="subject-meta">
|
<div class="subject-meta">
|
||||||
@@ -214,6 +222,87 @@ const subjectForm = {
|
|||||||
<setting ref="settingRef" @confirm="onSettingConfirm"></setting>
|
<setting ref="settingRef" @confirm="onSettingConfirm"></setting>
|
||||||
<txt-import ref="txtImportRef" @confirm="onTxtImportConfirm"></txt-import>
|
<txt-import ref="txtImportRef" @confirm="onTxtImportConfirm"></txt-import>
|
||||||
<bank ref="bankRef" @confirm="onBankConfirm"></bank>
|
<bank ref="bankRef" @confirm="onBankConfirm"></bank>
|
||||||
|
|
||||||
|
<el-dialog
|
||||||
|
title="设置题目隐显逻辑"
|
||||||
|
:visible.sync="subjectVisibleSetting.visible"
|
||||||
|
append-to-body
|
||||||
|
width="520px">
|
||||||
|
<el-form :model="subjectVisibleSetting.formData" label-width="110px">
|
||||||
|
<el-form-item label="启用逻辑">
|
||||||
|
<el-switch
|
||||||
|
v-model="subjectVisibleSetting.formData.enabled"
|
||||||
|
active-text="启用"
|
||||||
|
inactive-text="关闭">
|
||||||
|
</el-switch>
|
||||||
|
</el-form-item>
|
||||||
|
<template v-if="subjectVisibleSetting.formData.enabled">
|
||||||
|
<el-form-item label="处理方式">
|
||||||
|
<el-radio-group v-model="subjectVisibleSetting.formData.action">
|
||||||
|
<el-radio label="show">选中后显示本题</el-radio>
|
||||||
|
<el-radio label="hide">选中后隐藏本题</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="条件关系">
|
||||||
|
<el-radio-group v-model="subjectVisibleSetting.formData.logic">
|
||||||
|
<el-radio label="AND">并且</el-radio>
|
||||||
|
<el-radio label="OR">或者</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<div
|
||||||
|
v-for="(condition, conditionIndex) in subjectVisibleSetting.formData.conditions"
|
||||||
|
:key="conditionIndex"
|
||||||
|
class="subject-visible-condition">
|
||||||
|
<el-form-item :label="'条件' + (conditionIndex + 1)">
|
||||||
|
<div style="display: flex; gap: 8px;">
|
||||||
|
<el-select
|
||||||
|
v-model="condition.subjectId"
|
||||||
|
placeholder="请选择触发题目"
|
||||||
|
style="flex: 1;"
|
||||||
|
@change="subjectVisibleRuleSubjectChange(condition)">
|
||||||
|
<el-option
|
||||||
|
v-for="item in subjectVisibleRuleSubjects"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.title || '未填写题目'"
|
||||||
|
:value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-select
|
||||||
|
v-model="condition.optionId"
|
||||||
|
placeholder="请选择触发选项"
|
||||||
|
style="flex: 1;">
|
||||||
|
<el-option
|
||||||
|
v-for="item in getSubjectVisibleRuleOptions(condition.subjectId)"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.text || '未填写选项'"
|
||||||
|
:value="item.id">
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
icon="el-icon-delete"
|
||||||
|
size="mini"
|
||||||
|
@click="removeSubjectVisibleRuleCondition(conditionIndex)">
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<el-form-item label="">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="el-icon-plus"
|
||||||
|
size="small"
|
||||||
|
@click="addSubjectVisibleRuleCondition">
|
||||||
|
添加条件
|
||||||
|
</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="subjectVisibleSetting.visible = false">取 消</el-button>
|
||||||
|
<el-button type="primary" @click="onSubjectVisibleSettingConfirm">确 定</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
components: {
|
components: {
|
||||||
@@ -230,7 +319,32 @@ const subjectForm = {
|
|||||||
subjects: [],
|
subjects: [],
|
||||||
previewDialogVisible: false,
|
previewDialogVisible: false,
|
||||||
activity: {},
|
activity: {},
|
||||||
formRules: {}
|
formRules: {},
|
||||||
|
subjectVisibleSetting: {
|
||||||
|
visible: false,
|
||||||
|
subjectIndex: null,
|
||||||
|
formData: {
|
||||||
|
enabled: false,
|
||||||
|
action: "show",
|
||||||
|
logic: "AND",
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
subjectId: "",
|
||||||
|
optionId: ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
subjectVisibleRuleSubjects() {
|
||||||
|
if (this.subjectVisibleSetting.subjectIndex === null) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return this.subjects.filter((item, index) => {
|
||||||
|
return index < this.subjectVisibleSetting.subjectIndex && item.type !== "text"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -351,13 +465,113 @@ const subjectForm = {
|
|||||||
|
|
||||||
//选项设置确认
|
//选项设置确认
|
||||||
onSettingConfirm({option, ext}) {
|
onSettingConfirm({option, ext}) {
|
||||||
this.subjects[ext.subjectIndex].options[ext.optionIndex] = option
|
this.$set(this.subjects[ext.subjectIndex].options, ext.optionIndex, option)
|
||||||
console.log(this.subjects[ext.subjectIndex].options[ext.optionIndex])
|
console.log(this.subjects[ext.subjectIndex].options[ext.optionIndex])
|
||||||
|
|
||||||
// this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "isCorrect", option.isCorrect)
|
// this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "isCorrect", option.isCorrect)
|
||||||
// this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "hint", option.hint)
|
// this.$set(this.subjects[ext.subjectIndex].options[ext.optionIndex], "hint", option.hint)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//打开题目隐显逻辑设置,用于配置当前题目受前置选择题的哪个选项控制显示或隐藏
|
||||||
|
openSubjectVisibleSetting(subjectIndex, subject) {
|
||||||
|
const conditions = this.buildSubjectVisibleConditions(subject)
|
||||||
|
this.subjectVisibleSetting.subjectIndex = subjectIndex
|
||||||
|
this.subjectVisibleSetting.formData = {
|
||||||
|
enabled: !!subject.visibleRuleEnabled,
|
||||||
|
action: subject.visibleRuleAction || "show",
|
||||||
|
logic: subject.visibleRuleLogic || "AND",
|
||||||
|
conditions
|
||||||
|
}
|
||||||
|
this.subjectVisibleSetting.visible = true
|
||||||
|
},
|
||||||
|
|
||||||
|
//构建题目隐显逻辑条件,已有条件按实际数量回显;未配置时默认提供一条空条件
|
||||||
|
buildSubjectVisibleConditions(subject) {
|
||||||
|
let visibleRuleConditions = subject.visibleRuleConditions || []
|
||||||
|
if (typeof visibleRuleConditions === "string") {
|
||||||
|
try {
|
||||||
|
visibleRuleConditions = JSON.parse(visibleRuleConditions)
|
||||||
|
} catch (e) {
|
||||||
|
visibleRuleConditions = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const conditions = visibleRuleConditions || []
|
||||||
|
const result = conditions.map((condition) => {
|
||||||
|
return {
|
||||||
|
subjectId: condition.subjectId || "",
|
||||||
|
optionId: condition.optionId || ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (result.length === 0) {
|
||||||
|
result.push({
|
||||||
|
subjectId: "",
|
||||||
|
optionId: ""
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
|
||||||
|
//根据触发题目获取可选项,用于每条隐显条件选择触发选项
|
||||||
|
getSubjectVisibleRuleOptions(subjectId) {
|
||||||
|
const subject = this.subjects.find((item) => {
|
||||||
|
return item.id === subjectId
|
||||||
|
})
|
||||||
|
if (!subject || !subject.options) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return subject.options
|
||||||
|
},
|
||||||
|
|
||||||
|
//切换触发题目后清空当前条件的旧选项,避免保留其他题目的选项导致隐显条件错误
|
||||||
|
subjectVisibleRuleSubjectChange(condition) {
|
||||||
|
condition.optionId = ""
|
||||||
|
},
|
||||||
|
|
||||||
|
//添加一条隐显逻辑条件,多个条件通过条件关系字段统一按并且或或者计算
|
||||||
|
addSubjectVisibleRuleCondition() {
|
||||||
|
this.subjectVisibleSetting.formData.conditions.push({
|
||||||
|
subjectId: "",
|
||||||
|
optionId: ""
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
//删除一条隐显逻辑条件,至少保留一条条件用于继续配置
|
||||||
|
removeSubjectVisibleRuleCondition(conditionIndex) {
|
||||||
|
if (this.subjectVisibleSetting.formData.conditions.length === 1) {
|
||||||
|
this.$message.warning("至少保留一条条件")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.subjectVisibleSetting.formData.conditions.splice(conditionIndex, 1)
|
||||||
|
},
|
||||||
|
|
||||||
|
//保存题目隐显逻辑到当前题目对象,后续保存题目时随 subjects 一起提交
|
||||||
|
onSubjectVisibleSettingConfirm() {
|
||||||
|
const subjectIndex = this.subjectVisibleSetting.subjectIndex
|
||||||
|
if (subjectIndex === null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const formData = this.subjectVisibleSetting.formData
|
||||||
|
if (formData.enabled) {
|
||||||
|
for (let i = 0; i < formData.conditions.length; i++) {
|
||||||
|
const condition = formData.conditions[i]
|
||||||
|
if (!condition.subjectId || !condition.optionId) {
|
||||||
|
this.$message.warning("请选择条件" + (i + 1) + "的触发题目和触发选项")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$set(this.subjects[subjectIndex], "visibleRuleEnabled", formData.enabled)
|
||||||
|
this.$set(this.subjects[subjectIndex], "visibleRuleAction", formData.enabled ? formData.action : "show")
|
||||||
|
this.$set(this.subjects[subjectIndex], "visibleRuleLogic", formData.enabled ? formData.logic : "AND")
|
||||||
|
this.$set(this.subjects[subjectIndex], "visibleRuleConditions", formData.enabled ? formData.conditions.map((condition) => {
|
||||||
|
return {
|
||||||
|
subjectId: condition.subjectId,
|
||||||
|
optionId: condition.optionId
|
||||||
|
}
|
||||||
|
}) : [])
|
||||||
|
this.subjectVisibleSetting.visible = false
|
||||||
|
},
|
||||||
|
|
||||||
//从文本导入
|
//从文本导入
|
||||||
openTxtImport() {
|
openTxtImport() {
|
||||||
this.$refs.txtImportRef.visible = true;
|
this.$refs.txtImportRef.visible = true;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const answer = {
|
|||||||
<el-row type="flex" justify="end" class="mb10">
|
<el-row type="flex" justify="end" class="mb10">
|
||||||
<el-button type="primary" size="small" icon="el-icon-download" @click="exportUserAnswerXlsx">导出xlsx</el-button>
|
<el-button type="primary" size="small" icon="el-icon-download" @click="exportUserAnswerXlsx">导出xlsx</el-button>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-table :data="tableData">
|
<el-table :data="tableData" v-loading="tableLoading">
|
||||||
<el-table-column label="序号" type="index" width="70"></el-table-column>
|
<el-table-column label="序号" type="index" width="70"></el-table-column>
|
||||||
<el-table-column v-for="item in tableColumns" :key="item.prop" :label="item.label" :prop="item.prop"></el-table-column>
|
<el-table-column v-for="item in tableColumns" :key="item.prop" :label="item.label" :prop="item.prop"></el-table-column>
|
||||||
<el-table-column label="操作" fixed="right" width="100px">
|
<el-table-column label="操作" fixed="right" width="100px">
|
||||||
@@ -30,17 +30,24 @@ const answer = {
|
|||||||
onOpen(activityId) {
|
onOpen(activityId) {
|
||||||
this.activityId = activityId
|
this.activityId = activityId
|
||||||
this.dialogVisible = true
|
this.dialogVisible = true
|
||||||
|
this.tableColumns = []
|
||||||
|
this.tableData = []
|
||||||
|
this.pageForm.pageNumber = 1
|
||||||
|
this.pageForm.totalCount = 0
|
||||||
this.pageData()
|
this.pageData()
|
||||||
},
|
},
|
||||||
|
|
||||||
pageData() {
|
pageData() {
|
||||||
this.pageForm.activityId = this.activityId
|
this.pageForm.activityId = this.activityId
|
||||||
|
this.tableLoading = true
|
||||||
$.post("/platform/qsv/survey/userAnswer", this.pageForm).then((res) => {
|
$.post("/platform/qsv/survey/userAnswer", this.pageForm).then((res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.tableColumns = res.data.tableColumns
|
this.tableColumns = res.data.tableColumns
|
||||||
this.tableData = res.data.tableData.list
|
this.tableData = res.data.tableData.list
|
||||||
this.pageForm.totalCount = res.data.tableData.totalCount
|
this.pageForm.totalCount = res.data.tableData.totalCount
|
||||||
}
|
}
|
||||||
|
}).always(() => {
|
||||||
|
this.tableLoading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -53,7 +60,7 @@ const answer = {
|
|||||||
$.post("/platform/qsv/survey/deleteUserAnswer", { id }).then((res) => {
|
$.post("/platform/qsv/survey/deleteUserAnswer", { id }).then((res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
this.$message.success(res.msg)
|
this.$message.success(res.msg)
|
||||||
this.list()
|
this.pageData()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,6 +2,42 @@
|
|||||||
layout("/layouts/platform.html"){
|
layout("/layouts/platform.html"){
|
||||||
#-->
|
#-->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.survey-report-dialog {
|
||||||
|
margin-top: 40px !important;
|
||||||
|
height: calc(100vh - 80px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.survey-report-dialog .el-dialog__header {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.survey-report-dialog .el-dialog__body {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-top: 10px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.survey-report-toolbar {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.survey-report-body {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-right: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<div id="app" v-cloak>
|
<div id="app" v-cloak>
|
||||||
<guava>
|
<guava>
|
||||||
<el-card shadow="never">
|
<el-card shadow="never">
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
const report = {
|
const report = {
|
||||||
/*language=HTML*/
|
/*language=HTML*/
|
||||||
template: `
|
template: `
|
||||||
<el-dialog title="分析报告" :visible.sync="dialogVisible" width="50%">
|
<el-dialog title="分析报告" :visible.sync="dialogVisible" width="50%" custom-class="survey-report-dialog">
|
||||||
|
<div class="survey-report-toolbar">
|
||||||
<el-row type="flex" justify="end" class="mb10">
|
<el-row type="flex" justify="end" class="mb10">
|
||||||
<el-button type="primary" size="small" icon="el-icon-download" @click="exportReportXlsx">导出xlsx</el-button>
|
<el-button type="primary" size="small" icon="el-icon-download" @click="exportReportXlsx">导出xlsx</el-button>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
</div>
|
||||||
|
<div class="survey-report-body">
|
||||||
<div v-for="(subject,subjectIndex) in subjects" class="subject">
|
<div v-for="(subject,subjectIndex) in subjects" class="subject">
|
||||||
<div>
|
<div>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
第{{subjectIndex+1}}题: {{subject.title}}
|
第{{subjectIndex+1}}题: {{subject.title}}
|
||||||
<span class="type" v-if="subject.type==='text'">[填空题]</span>
|
<span class="type" v-if="subject.type==='text'">[填空题]</span>
|
||||||
<span class="type" v-else-if="subject.type==='radio'">[单选题]</span>
|
<span class="type" v-else-if="subject.type==='radio'">[单选题]</span>
|
||||||
<span class="type" v-else-if="subject.type==='text'">[多选题]</span>
|
<span class="type" v-else-if="subject.type==='checkbox'">[多选题]</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="subject.type==='text'">
|
<div v-if="subject.type==='text'">
|
||||||
{{subject.texts.join('、')}}
|
<el-button type="text" @click="openTextDetail(subject)">查看填写内容</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="subject.type==='radio' || subject.type==='checkbox'">
|
<div v-else-if="subject.type==='radio' || subject.type==='checkbox'">
|
||||||
@@ -35,7 +38,7 @@ const report = {
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -45,10 +48,23 @@ const report = {
|
|||||||
<el-table-column label="工号" prop="loginName"></el-table-column>
|
<el-table-column label="工号" prop="loginName"></el-table-column>
|
||||||
<el-table-column label="所属工会" prop="unionName"></el-table-column>
|
<el-table-column label="所属工会" prop="unionName"></el-table-column>
|
||||||
<el-table-column label="所属单位" prop="unitName"></el-table-column>
|
<el-table-column label="所属单位" prop="unitName"></el-table-column>
|
||||||
|
<el-table-column label="补充理由" prop="fillContent" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column label="选择时间" prop="attemptDate"></el-table-column>
|
<el-table-column label="选择时间" prop="attemptDate"></el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<el-dialog :title="textSubject.title || '填写内容'" :visible.sync="textVisible" width="50%" append-to-body>
|
||||||
|
<el-table :data="textAnswers" size="small">
|
||||||
|
<el-table-column label="序号" type="index" width="70"></el-table-column>
|
||||||
|
<el-table-column label="姓名" prop="userName" width="100"></el-table-column>
|
||||||
|
<el-table-column label="工号" prop="loginName" width="120"></el-table-column>
|
||||||
|
<el-table-column label="所属工会" prop="unionName" width="140"></el-table-column>
|
||||||
|
<el-table-column label="所属单位" prop="unitName" width="180" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="填写内容" prop="text" show-overflow-tooltip></el-table-column>
|
||||||
|
<el-table-column label="提交时间" prop="submitTime" width="160"></el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
`,
|
`,
|
||||||
dicts: ["ACTIVITY_QSV_CATEGORY"],
|
dicts: ["ACTIVITY_QSV_CATEGORY"],
|
||||||
@@ -59,7 +75,10 @@ const report = {
|
|||||||
report: null,
|
report: null,
|
||||||
subjects: [],
|
subjects: [],
|
||||||
optionVisible: false,
|
optionVisible: false,
|
||||||
optionUsers: []
|
optionUsers: [],
|
||||||
|
textVisible: false,
|
||||||
|
textSubject: {},
|
||||||
|
textAnswers: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -73,8 +92,6 @@ const report = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
openDetail(subjectId, optionId) {
|
openDetail(subjectId, optionId) {
|
||||||
console.log(subjectId)
|
|
||||||
console.log(optionId)
|
|
||||||
$.post("/platform/qsv/survey/selectOptionUsers", {
|
$.post("/platform/qsv/survey/selectOptionUsers", {
|
||||||
activityId: this.activityId,
|
activityId: this.activityId,
|
||||||
subjectId,
|
subjectId,
|
||||||
@@ -87,6 +104,13 @@ const report = {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
openTextDetail(subject) {
|
||||||
|
this.textSubject = subject
|
||||||
|
this.textAnswers = subject.textAnswers || (subject.texts || []).map((text) => {
|
||||||
|
return { text }
|
||||||
|
})
|
||||||
|
this.textVisible = true
|
||||||
|
},
|
||||||
exportReportXlsx(){
|
exportReportXlsx(){
|
||||||
this.$downLoad("/platform/qsv/survey/exportReportXlsx", { activityId: this.activityId })
|
this.$downLoad("/platform/qsv/survey/exportReportXlsx", { activityId: this.activityId })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,27 @@ layout("/layouts/platform_h5.html"){
|
|||||||
resize: none;
|
resize: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.option-fill-box {
|
||||||
|
border: 1px solid #e3e3e3;
|
||||||
|
margin: 0 16px 8px 46px;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option-fill-box input {
|
||||||
|
background-color: #fff;
|
||||||
|
border: none !important;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 18px;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
resize: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div id="app" v-cloak>
|
<div id="app" v-cloak>
|
||||||
@@ -87,7 +108,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
|
<div class="container" :style="{'padding-bottom': answerRecord.isFinish ? 0 : '84px'}">
|
||||||
<h2 class="title">{{ activity.title }}</h2>
|
<h2 class="title">{{ activity.title }}</h2>
|
||||||
<div v-if="!isFinished">
|
<div v-if="!isFinished">
|
||||||
<div v-for="(subject, index) in subjects" :key="index" class="subject">
|
<div v-for="(subject, index) in visibleSubjects" :key="subject.id" class="subject">
|
||||||
<p>{{index+1}}、{{ subject.title }}</p>
|
<p>{{index+1}}、{{ subject.title }}</p>
|
||||||
<div class="tag">
|
<div class="tag">
|
||||||
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
|
<van-tag v-if="subject.type === 'checkbox'" type="primary" size="large">多选</van-tag>
|
||||||
@@ -102,8 +123,8 @@ layout("/layouts/platform_h5.html"){
|
|||||||
v-if="['radio','checkbox'].includes(subject.type)"
|
v-if="['radio','checkbox'].includes(subject.type)"
|
||||||
>
|
>
|
||||||
<van-cell-group>
|
<van-cell-group>
|
||||||
|
<template v-for="(option,index) in subject.options">
|
||||||
<van-cell
|
<van-cell
|
||||||
v-for="(option,index) in subject.options"
|
|
||||||
clickable
|
clickable
|
||||||
:key="option.id"
|
:key="option.id"
|
||||||
:title="option.text"
|
:title="option.text"
|
||||||
@@ -121,12 +142,24 @@ layout("/layouts/platform_h5.html"){
|
|||||||
@click.stop="previewOptionImg(option.imgUrl)"
|
@click.stop="previewOptionImg(option.imgUrl)"
|
||||||
/>
|
/>
|
||||||
</van-cell>
|
</van-cell>
|
||||||
|
<div
|
||||||
|
class="option-fill-box"
|
||||||
|
:key="option.id + '-fill'"
|
||||||
|
v-if="isOptionFillVisible(subject, option)">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model="subject.optionFillContents[option.id]"
|
||||||
|
:placeholder="option.fillPlaceholder || '请填写补充内容'"
|
||||||
|
:readonly="answerRecord.isFinish"
|
||||||
|
@click.stop />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</van-cell-group>
|
</van-cell-group>
|
||||||
</van-checkbox-group>
|
</van-checkbox-group>
|
||||||
|
|
||||||
<!--填空题-->
|
<!--填空题-->
|
||||||
<div class="ui-input-box" v-if="subject.type==='text'">
|
<div class="ui-input-box" v-if="subject.type==='text'">
|
||||||
<input type="text" v-model="subject.userFillContent" :readonly="answerRecord.isFinish" />
|
<input type="text" v-model="subject.userFillContent" :placeholder="'请输入' + subject.title" :readonly="answerRecord.isFinish" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="button-control" v-if="!answerRecord.isFinish">
|
<div class="button-control" v-if="!answerRecord.isFinish">
|
||||||
@@ -158,6 +191,11 @@ layout("/layouts/platform_h5.html"){
|
|||||||
return this.$moment().unix() > this.$moment(this.activity.endTime).unix()
|
return this.$moment().unix() > this.$moment(this.activity.endTime).unix()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
},
|
||||||
|
visibleSubjects() {
|
||||||
|
return this.subjects.filter((subject) => {
|
||||||
|
return this.isSubjectVisible(subject)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -193,14 +231,106 @@ layout("/layouts/platform_h5.html"){
|
|||||||
const answer = this.answerRecord.extJson[subject.id]
|
const answer = this.answerRecord.extJson[subject.id]
|
||||||
|
|
||||||
if (["radio", "checkbox"].includes(subject.type)) {
|
if (["radio", "checkbox"].includes(subject.type)) {
|
||||||
this.$refs["subject" + subject.id][0].toggleAll(false)
|
this.$set(subject, "userSelectOptionIds", answer?.optionIds || [])
|
||||||
answer?.optionIds.forEach((optionId) => {
|
this.$set(subject, "optionFillContents", answer?.optionFillContents || {})
|
||||||
this.$nextTick(() => {
|
|
||||||
this.$refs["option" + optionId][0].toggle()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else if (subject.type === "text") {
|
} else if (subject.type === "text") {
|
||||||
subject.userFillContent = answer?.text
|
this.$set(subject, "userFillContent", answer?.text)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (!this.answerRecord.isFinish) {
|
||||||
|
this.clearHiddenSubjectAnswers()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
//判断题目是否显示,未配置隐显逻辑的题目默认显示;已配置的题目按条件关系计算后再执行显示或隐藏动作
|
||||||
|
isSubjectVisible(subject) {
|
||||||
|
if (!subject.visibleRuleEnabled) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const conditions = this.getVisibleRuleConditions(subject)
|
||||||
|
if (conditions.length === 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = conditions.map((condition) => {
|
||||||
|
const triggerSubject = this.subjects.find((item) => {
|
||||||
|
return item.id === condition.subjectId
|
||||||
|
})
|
||||||
|
return triggerSubject
|
||||||
|
&& triggerSubject.userSelectOptionIds
|
||||||
|
&& triggerSubject.userSelectOptionIds.includes(condition.optionId)
|
||||||
|
})
|
||||||
|
|
||||||
|
const matched = subject.visibleRuleLogic === "OR"
|
||||||
|
? results.some((item) => {
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
: results.every((item) => {
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
|
||||||
|
if (subject.visibleRuleAction === "hide") {
|
||||||
|
return !matched
|
||||||
|
}
|
||||||
|
return matched
|
||||||
|
},
|
||||||
|
|
||||||
|
//读取隐显逻辑条件,只使用后台保存的条件数组参与显示或隐藏判断
|
||||||
|
getVisibleRuleConditions(subject) {
|
||||||
|
let conditions = subject.visibleRuleConditions || []
|
||||||
|
if (typeof conditions === "string") {
|
||||||
|
try {
|
||||||
|
conditions = JSON.parse(conditions)
|
||||||
|
} catch (e) {
|
||||||
|
conditions = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conditions = conditions.filter((condition) => {
|
||||||
|
return condition.subjectId && condition.optionId
|
||||||
|
})
|
||||||
|
if (conditions.length > 0) {
|
||||||
|
return conditions
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
|
||||||
|
//清空当前隐藏题目的答案,避免隐藏题残留旧选项或填空内容参与后续提交
|
||||||
|
clearHiddenSubjectAnswers() {
|
||||||
|
this.subjects.forEach((subject) => {
|
||||||
|
if (this.isSubjectVisible(subject)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (["radio", "checkbox"].includes(subject.type)) {
|
||||||
|
this.$set(subject, "userSelectOptionIds", [])
|
||||||
|
this.$set(subject, "optionFillContents", {})
|
||||||
|
} else if (subject.type === "text") {
|
||||||
|
this.$set(subject, "userFillContent", null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
//判断选项是否已被选择,用于控制选项补充填写框显示和提交校验
|
||||||
|
isOptionSelected(subject, optionId) {
|
||||||
|
return subject.userSelectOptionIds && subject.userSelectOptionIds.includes(optionId)
|
||||||
|
},
|
||||||
|
|
||||||
|
//选中需要补充填写的选项后显示输入框,例如选择“否”后填写原因
|
||||||
|
isOptionFillVisible(subject, option) {
|
||||||
|
return option.fillRequired && this.isOptionSelected(subject, option.id)
|
||||||
|
},
|
||||||
|
|
||||||
|
//清空未选中选项的补充填写内容,避免取消选择后残留旧内容
|
||||||
|
clearUnselectedOptionFillContents(subject) {
|
||||||
|
if (!subject.optionFillContents) {
|
||||||
|
this.$set(subject, "optionFillContents", {})
|
||||||
|
}
|
||||||
|
if (!subject.options) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
subject.options.forEach((option) => {
|
||||||
|
if (!this.isOptionSelected(subject, option.id)) {
|
||||||
|
this.$delete(subject.optionFillContents, option.id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -215,6 +345,10 @@ layout("/layouts/platform_h5.html"){
|
|||||||
this.$refs["subject" + subject.id][0].toggleAll(false)
|
this.$refs["subject" + subject.id][0].toggleAll(false)
|
||||||
}
|
}
|
||||||
this.$refs["option" + optionId][0].toggle()
|
this.$refs["option" + optionId][0].toggle()
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.clearUnselectedOptionFillContents(subject)
|
||||||
|
this.clearHiddenSubjectAnswers()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
//预览图片
|
//预览图片
|
||||||
@@ -231,13 +365,20 @@ layout("/layouts/platform_h5.html"){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//提示那些题没有作答
|
//提示那些题没有作答
|
||||||
for (let i = 0; i < this.subjects.length; i++) {
|
for (let i = 0; i < this.visibleSubjects.length; i++) {
|
||||||
const subject = this.subjects[i]
|
const subject = this.visibleSubjects[i]
|
||||||
if (["radio", "checkbox"].includes(subject.type)) {
|
if (["radio", "checkbox"].includes(subject.type)) {
|
||||||
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
|
if (!subject.userSelectOptionIds || subject.userSelectOptionIds.length === 0) {
|
||||||
this.$toast.fail("第" + (i + 1) + "题未做答")
|
this.$toast.fail("第" + (i + 1) + "题未做答")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
for (let j = 0; j < subject.options.length; j++) {
|
||||||
|
const option = subject.options[j]
|
||||||
|
if (this.isOptionFillVisible(subject, option) && !subject.optionFillContents[option.id]) {
|
||||||
|
this.$toast.fail("请填写第" + (i + 1) + "题的补充内容")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if ("text" === subject.type) {
|
} else if ("text" === subject.type) {
|
||||||
if (!subject.userFillContent) {
|
if (!subject.userFillContent) {
|
||||||
this.$toast.fail("第" + (i + 1) + "题未作答")
|
this.$toast.fail("第" + (i + 1) + "题未作答")
|
||||||
@@ -255,11 +396,12 @@ layout("/layouts/platform_h5.html"){
|
|||||||
answer: JSON.stringify({
|
answer: JSON.stringify({
|
||||||
activityId: this.id,
|
activityId: this.id,
|
||||||
answerRecordId: this.answerRecordId,
|
answerRecordId: this.answerRecordId,
|
||||||
subjects: this.subjects.map((subject) => {
|
subjects: this.visibleSubjects.map((subject) => {
|
||||||
return {
|
return {
|
||||||
id: subject.id,
|
id: subject.id,
|
||||||
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : [],
|
userSelectOptionIds: ["checkbox", "radio"].includes(subject.type) ? subject.userSelectOptionIds : [],
|
||||||
userFillContent: subject.type === "text" ? subject.userFillContent : null
|
userFillContent: subject.type === "text" ? subject.userFillContent : null,
|
||||||
|
optionFillContents: ["checkbox", "radio"].includes(subject.type) ? subject.optionFillContents : {}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user