feat: configure first-step choice questions

bugfix/ai-assessment-evidence-rescore
chenyuan 1 month ago
parent 2de6b89ca9
commit 1e8ffce76b

@ -32,6 +32,9 @@ public class TrainingTask {
@ApiModelProperty("步骤名称JSON数组") @ApiModelProperty("步骤名称JSON数组")
private String steps; private String steps;
@ApiModelProperty("第一步选择题JSON数组")
private String stepOneQuestions;
@ApiModelProperty("资料名称") @ApiModelProperty("资料名称")
private String materialName; private String materialName;
@ -125,6 +128,14 @@ public class TrainingTask {
this.steps = steps == null ? null : steps.trim(); this.steps = steps == null ? null : steps.trim();
} }
public String getStepOneQuestions() {
return stepOneQuestions;
}
public void setStepOneQuestions(String stepOneQuestions) {
this.stepOneQuestions = stepOneQuestions == null ? null : stepOneQuestions.trim();
}
public String getMaterialName() { public String getMaterialName() {
return materialName; return materialName;
} }

@ -35,6 +35,9 @@ public class TrainingTaskClassConfig {
@ApiModelProperty("Step names JSON array") @ApiModelProperty("Step names JSON array")
private String steps; private String steps;
@ApiModelProperty("Step-one choice questions JSON array")
private String stepOneQuestions;
@ApiModelProperty("Material name") @ApiModelProperty("Material name")
private String materialName; private String materialName;
@ -136,6 +139,14 @@ public class TrainingTaskClassConfig {
this.steps = steps == null ? null : steps.trim(); this.steps = steps == null ? null : steps.trim();
} }
public String getStepOneQuestions() {
return stepOneQuestions;
}
public void setStepOneQuestions(String stepOneQuestions) {
this.stepOneQuestions = stepOneQuestions == null ? null : stepOneQuestions.trim();
}
public String getMaterialName() { public String getMaterialName() {
return materialName; return materialName;
} }

@ -46,6 +46,9 @@ import java.util.stream.Collectors;
public class TrainingTaskServiceImpl implements TrainingTaskService { public class TrainingTaskServiceImpl implements TrainingTaskService {
private static final Pattern SPLIT_PATTERN = Pattern.compile("[;;||]"); private static final Pattern SPLIT_PATTERN = Pattern.compile("[;;||]");
private static final String COMPREHENSIVE_CASE_TRAINING_TASK_KEY = "comprehensive-case-training"; private static final String COMPREHENSIVE_CASE_TRAINING_TASK_KEY = "comprehensive-case-training";
private static final Set<String> STEP_ONE_CHOICE_TASK_KEYS = new LinkedHashSet<>(Arrays.asList(
"new-product-survey", "industry-demand-analysis", "competitive-environment-analysis"));
private static final List<String> STEP_ONE_CHOICE_OPTION_KEYS = Arrays.asList("A", "B", "C", "D", "E", "F");
@Autowired @Autowired
public TrainingTaskMapper trainingTaskMapper; public TrainingTaskMapper trainingTaskMapper;
@ -140,6 +143,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
task.setSort(existing.getSort()); task.setSort(existing.getSort());
task.setEnabled(existing.getEnabled()); task.setEnabled(existing.getEnabled());
task.setSteps(normalizeSteps(task.getSteps(), builtInTask)); task.setSteps(normalizeSteps(task.getSteps(), builtInTask));
task.setStepOneQuestions(normalizeStepOneQuestions(existing.getTaskKey(), task.getStepOneQuestions()));
task.setUpdateTime(new Date()); task.setUpdateTime(new Date());
trainingTaskMapper.updateByPrimaryKeySelective(task); trainingTaskMapper.updateByPrimaryKeySelective(task);
synchronizeClassTaskDefaults(existing, task); synchronizeClassTaskDefaults(existing, task);
@ -276,6 +280,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
task.setSort(baseTask.getSort()); task.setSort(baseTask.getSort());
task.setEnabled(task.getEnabled() == null ? Boolean.TRUE : task.getEnabled()); task.setEnabled(task.getEnabled() == null ? Boolean.TRUE : task.getEnabled());
task.setSteps(normalizeSteps(task.getSteps(), builtInTask)); task.setSteps(normalizeSteps(task.getSteps(), builtInTask));
task.setStepOneQuestions(normalizeStepOneQuestions(baseTask.getTaskKey(), task.getStepOneQuestions()));
TrainingTaskClassConfig existing = trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey(teachingClassId, normalizedTaskKey); TrainingTaskClassConfig existing = trainingTaskClassConfigMapper.selectByTeachingClassAndTaskKey(teachingClassId, normalizedTaskKey);
TrainingTaskClassConfig config = toConfig(teachingClassId, task, operatorId); TrainingTaskClassConfig config = toConfig(teachingClassId, task, operatorId);
@ -593,6 +598,10 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
update.setSteps(updatedTask.getSteps()); update.setSteps(updatedTask.getSteps());
changed = true; changed = true;
} }
if (shouldSynchronize(classTask.getStepOneQuestions(), previousTask.getStepOneQuestions(), updatedTask.getStepOneQuestions())) {
update.setStepOneQuestions(updatedTask.getStepOneQuestions());
changed = true;
}
if (shouldSynchronize(classTask.getMaterialName(), previousTask.getMaterialName(), updatedTask.getMaterialName())) { if (shouldSynchronize(classTask.getMaterialName(), previousTask.getMaterialName(), updatedTask.getMaterialName())) {
update.setMaterialName(updatedTask.getMaterialName()); update.setMaterialName(updatedTask.getMaterialName());
changed = true; changed = true;
@ -668,6 +677,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
task.setObjectives(config.getObjectives()); task.setObjectives(config.getObjectives());
task.setRequirements(config.getRequirements()); task.setRequirements(config.getRequirements());
task.setSteps(config.getSteps()); task.setSteps(config.getSteps());
task.setStepOneQuestions(config.getStepOneQuestions());
task.setMaterialName(config.getMaterialName()); task.setMaterialName(config.getMaterialName());
task.setMaterialUrl(config.getMaterialUrl()); task.setMaterialUrl(config.getMaterialUrl());
task.setSort(config.getSort()); task.setSort(config.getSort());
@ -689,6 +699,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
config.setObjectives(task.getObjectives()); config.setObjectives(task.getObjectives());
config.setRequirements(task.getRequirements()); config.setRequirements(task.getRequirements());
config.setSteps(task.getSteps()); config.setSteps(task.getSteps());
config.setStepOneQuestions(task.getStepOneQuestions());
config.setMaterialName(task.getMaterialName()); config.setMaterialName(task.getMaterialName());
config.setMaterialUrl(task.getMaterialUrl()); config.setMaterialUrl(task.getMaterialUrl());
config.setSort(task.getSort()); config.setSort(task.getSort());
@ -711,6 +722,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
"objectives text NULL COMMENT '实训目标JSON数组'," + "objectives text NULL COMMENT '实训目标JSON数组'," +
"requirements text NULL COMMENT '实训要求'," + "requirements text NULL COMMENT '实训要求'," +
"steps text NULL COMMENT '步骤名称JSON数组'," + "steps text NULL COMMENT '步骤名称JSON数组'," +
"step_one_questions text NULL COMMENT '第一步选择题JSON数组'," +
"material_name varchar(255) NULL COMMENT '资料名称'," + "material_name varchar(255) NULL COMMENT '资料名称'," +
"material_url varchar(500) NULL COMMENT '资料地址'," + "material_url varchar(500) NULL COMMENT '资料地址'," +
"sort int DEFAULT 0 COMMENT '排序'," + "sort int DEFAULT 0 COMMENT '排序'," +
@ -724,6 +736,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
"KEY idx_training_task_sort (sort)" + "KEY idx_training_task_sort (sort)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='实训任务配置'"); ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='实训任务配置'");
jdbcTemplate.execute("ALTER TABLE training_task CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); jdbcTemplate.execute("ALTER TABLE training_task CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
ensureTextColumn("training_task", "step_one_questions", "第一步选择题JSON数组");
trainingTaskTableChecked = true; trainingTaskTableChecked = true;
} }
@ -742,6 +755,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
"objectives text NULL," + "objectives text NULL," +
"requirements text NULL," + "requirements text NULL," +
"steps text NULL," + "steps text NULL," +
"step_one_questions text NULL," +
"material_name varchar(255) NULL," + "material_name varchar(255) NULL," +
"material_url varchar(500) NULL," + "material_url varchar(500) NULL," +
"sort int DEFAULT 0," + "sort int DEFAULT 0," +
@ -754,9 +768,26 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
"KEY idx_training_task_class_enabled_sort (teaching_class_id, enabled, sort)," + "KEY idx_training_task_class_enabled_sort (teaching_class_id, enabled, sort)," +
"KEY idx_training_task_class_created_by (created_by)" + "KEY idx_training_task_class_created_by (created_by)" +
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Class scoped training task config'"); ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Class scoped training task config'");
ensureTextColumn("training_task_class_config", "step_one_questions", "第一步选择题JSON数组");
trainingTaskClassConfigTableChecked = true; trainingTaskClassConfigTableChecked = true;
} }
/** Add the field for deployments that already created the task tables before this feature existed. */
private void ensureTextColumn(String tableName, String columnName, String comment) {
if (jdbcTemplate == null) {
return;
}
Integer count = jdbcTemplate.queryForObject(
"SELECT COUNT(1) FROM information_schema.COLUMNS " +
"WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?",
Integer.class, tableName, columnName);
if (count != null && count > 0) {
return;
}
jdbcTemplate.execute("ALTER TABLE " + tableName + " ADD COLUMN " + columnName
+ " text NULL COMMENT '" + comment + "' AFTER steps");
}
TrainingTask buildTask(TrainingTaskImportDTO row, int rowNumber, List<String> errors) { TrainingTask buildTask(TrainingTaskImportDTO row, int rowNumber, List<String> errors) {
String projectName = StringUtils.trimToEmpty(row.getProjectName()); String projectName = StringUtils.trimToEmpty(row.getProjectName());
String taskKey = StringUtils.trimToEmpty(row.getTaskKey()); String taskKey = StringUtils.trimToEmpty(row.getTaskKey());
@ -828,6 +859,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
task.setObjectives(normalizeJsonArray(task.getObjectives())); task.setObjectives(normalizeJsonArray(task.getObjectives()));
task.setRequirements(StringUtils.trimToEmpty(task.getRequirements())); task.setRequirements(StringUtils.trimToEmpty(task.getRequirements()));
task.setSteps(normalizeJsonArray(task.getSteps())); task.setSteps(normalizeJsonArray(task.getSteps()));
task.setStepOneQuestions(normalizeStepOneQuestions(task.getTaskKey(), task.getStepOneQuestions()));
task.setMaterialName(StringUtils.trimToEmpty(task.getMaterialName())); task.setMaterialName(StringUtils.trimToEmpty(task.getMaterialName()));
task.setMaterialUrl(StringUtils.trimToEmpty(task.getMaterialUrl())); task.setMaterialUrl(StringUtils.trimToEmpty(task.getMaterialUrl()));
if (task.getEnabled() == null) { if (task.getEnabled() == null) {
@ -936,6 +968,62 @@ public class TrainingTaskServiceImpl implements TrainingTaskService {
return toJsonArray(splitList(trimmed)); return toJsonArray(splitList(trimmed));
} }
private String normalizeStepOneQuestions(String taskKey, String value) {
if (!STEP_ONE_CHOICE_TASK_KEYS.contains(StringUtils.trimToEmpty(taskKey))) {
return "[]";
}
if (StringUtils.isBlank(value)) {
return "[]";
}
try {
List<JSONObject> source = JSON.parseArray(value, JSONObject.class);
if (source == null || source.isEmpty()) {
return "[]";
}
List<JSONObject> normalized = new ArrayList<>();
for (int questionIndex = 0; questionIndex < source.size(); questionIndex++) {
JSONObject sourceQuestion = source.get(questionIndex);
String title = StringUtils.trimToEmpty(sourceQuestion == null ? null : sourceQuestion.getString("title"));
if (StringUtils.isBlank(title)) {
throw new IllegalArgumentException("第 " + (questionIndex + 1) + " 道选择题题干不能为空");
}
List<?> sourceOptions = sourceQuestion == null ? Collections.emptyList() : sourceQuestion.getJSONArray("options");
List<JSONObject> options = new ArrayList<>();
for (int optionIndex = 0; optionIndex < sourceOptions.size() && optionIndex < STEP_ONE_CHOICE_OPTION_KEYS.size(); optionIndex++) {
Object rawOption = sourceOptions.get(optionIndex);
String content = rawOption instanceof JSONObject
? StringUtils.trimToEmpty(((JSONObject) rawOption).getString("content"))
: StringUtils.trimToEmpty(String.valueOf(rawOption));
if (StringUtils.isNotBlank(content)) {
JSONObject option = new JSONObject();
option.put("key", STEP_ONE_CHOICE_OPTION_KEYS.get(options.size()));
option.put("content", content);
options.add(option);
}
}
if (options.size() < 2) {
throw new IllegalArgumentException("第 " + (questionIndex + 1) + " 道选择题至少需要两个选项");
}
String answer = StringUtils.upperCase(StringUtils.trimToEmpty(sourceQuestion.getString("answer")));
boolean validAnswer = options.stream().anyMatch(option -> answer.equals(option.getString("key")));
if (!validAnswer) {
throw new IllegalArgumentException("请设置第 " + (questionIndex + 1) + " 道选择题的正确答案");
}
JSONObject question = new JSONObject();
question.put("id", StringUtils.defaultIfBlank(sourceQuestion.getString("id"), "step-one-question-" + (questionIndex + 1)));
question.put("title", title);
question.put("options", options);
question.put("answer", answer);
normalized.add(question);
}
return JSON.toJSONString(normalized);
} catch (IllegalArgumentException e) {
throw e;
} catch (Exception e) {
throw new IllegalArgumentException("第一步选择题配置格式不正确");
}
}
private String toJsonArray(List<String> list) { private String toJsonArray(List<String> list) {
return JSON.toJSONString(list == null ? Collections.emptyList() : list); return JSON.toJSONString(list == null ? Collections.emptyList() : list);
} }

@ -12,6 +12,7 @@
<result column="objectives" jdbcType="LONGVARCHAR" property="objectives" /> <result column="objectives" jdbcType="LONGVARCHAR" property="objectives" />
<result column="requirements" jdbcType="LONGVARCHAR" property="requirements" /> <result column="requirements" jdbcType="LONGVARCHAR" property="requirements" />
<result column="steps" jdbcType="LONGVARCHAR" property="steps" /> <result column="steps" jdbcType="LONGVARCHAR" property="steps" />
<result column="step_one_questions" jdbcType="LONGVARCHAR" property="stepOneQuestions" />
<result column="material_name" jdbcType="VARCHAR" property="materialName" /> <result column="material_name" jdbcType="VARCHAR" property="materialName" />
<result column="material_url" jdbcType="VARCHAR" property="materialUrl" /> <result column="material_url" jdbcType="VARCHAR" property="materialUrl" />
<result column="sort" jdbcType="INTEGER" property="sort" /> <result column="sort" jdbcType="INTEGER" property="sort" />
@ -23,7 +24,7 @@
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, teaching_class_id, task_key, project_name, task_name, knowledge, background, objectives, requirements, id, teaching_class_id, task_key, project_name, task_name, knowledge, background, objectives, requirements,
steps, material_name, material_url, sort, enabled, created_by, create_time, update_time steps, step_one_questions, material_name, material_url, sort, enabled, created_by, create_time, update_time
</sql> </sql>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap"> <select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
@ -80,6 +81,7 @@
<if test="objectives != null">objectives,</if> <if test="objectives != null">objectives,</if>
<if test="requirements != null">requirements,</if> <if test="requirements != null">requirements,</if>
<if test="steps != null">steps,</if> <if test="steps != null">steps,</if>
<if test="stepOneQuestions != null">step_one_questions,</if>
<if test="materialName != null">material_name,</if> <if test="materialName != null">material_name,</if>
<if test="materialUrl != null">material_url,</if> <if test="materialUrl != null">material_url,</if>
<if test="sort != null">sort,</if> <if test="sort != null">sort,</if>
@ -99,6 +101,7 @@
<if test="objectives != null">#{objectives},</if> <if test="objectives != null">#{objectives},</if>
<if test="requirements != null">#{requirements},</if> <if test="requirements != null">#{requirements},</if>
<if test="steps != null">#{steps},</if> <if test="steps != null">#{steps},</if>
<if test="stepOneQuestions != null">#{stepOneQuestions},</if>
<if test="materialName != null">#{materialName,jdbcType=VARCHAR},</if> <if test="materialName != null">#{materialName,jdbcType=VARCHAR},</if>
<if test="materialUrl != null">#{materialUrl,jdbcType=VARCHAR},</if> <if test="materialUrl != null">#{materialUrl,jdbcType=VARCHAR},</if>
<if test="sort != null">#{sort,jdbcType=INTEGER},</if> <if test="sort != null">#{sort,jdbcType=INTEGER},</if>
@ -119,6 +122,7 @@
<if test="objectives != null">objectives = #{objectives},</if> <if test="objectives != null">objectives = #{objectives},</if>
<if test="requirements != null">requirements = #{requirements},</if> <if test="requirements != null">requirements = #{requirements},</if>
<if test="steps != null">steps = #{steps},</if> <if test="steps != null">steps = #{steps},</if>
<if test="stepOneQuestions != null">step_one_questions = #{stepOneQuestions},</if>
<if test="materialName != null">material_name = #{materialName,jdbcType=VARCHAR},</if> <if test="materialName != null">material_name = #{materialName,jdbcType=VARCHAR},</if>
<if test="materialUrl != null">material_url = #{materialUrl,jdbcType=VARCHAR},</if> <if test="materialUrl != null">material_url = #{materialUrl,jdbcType=VARCHAR},</if>
<if test="sort != null">sort = #{sort,jdbcType=INTEGER},</if> <if test="sort != null">sort = #{sort,jdbcType=INTEGER},</if>

@ -11,6 +11,7 @@
<result column="objectives" jdbcType="LONGVARCHAR" property="objectives" /> <result column="objectives" jdbcType="LONGVARCHAR" property="objectives" />
<result column="requirements" jdbcType="LONGVARCHAR" property="requirements" /> <result column="requirements" jdbcType="LONGVARCHAR" property="requirements" />
<result column="steps" jdbcType="LONGVARCHAR" property="steps" /> <result column="steps" jdbcType="LONGVARCHAR" property="steps" />
<result column="step_one_questions" jdbcType="LONGVARCHAR" property="stepOneQuestions" />
<result column="material_name" jdbcType="VARCHAR" property="materialName" /> <result column="material_name" jdbcType="VARCHAR" property="materialName" />
<result column="material_url" jdbcType="VARCHAR" property="materialUrl" /> <result column="material_url" jdbcType="VARCHAR" property="materialUrl" />
<result column="sort" jdbcType="INTEGER" property="sort" /> <result column="sort" jdbcType="INTEGER" property="sort" />
@ -22,7 +23,7 @@
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, task_key, project_name, task_name, knowledge, background, objectives, requirements, id, task_key, project_name, task_name, knowledge, background, objectives, requirements,
steps, material_name, material_url, sort, enabled, created_by, create_time, update_time steps, step_one_questions, material_name, material_url, sort, enabled, created_by, create_time, update_time
</sql> </sql>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap"> <select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
@ -75,6 +76,7 @@
<if test="objectives != null">objectives,</if> <if test="objectives != null">objectives,</if>
<if test="requirements != null">requirements,</if> <if test="requirements != null">requirements,</if>
<if test="steps != null">steps,</if> <if test="steps != null">steps,</if>
<if test="stepOneQuestions != null">step_one_questions,</if>
<if test="materialName != null">material_name,</if> <if test="materialName != null">material_name,</if>
<if test="materialUrl != null">material_url,</if> <if test="materialUrl != null">material_url,</if>
<if test="sort != null">sort,</if> <if test="sort != null">sort,</if>
@ -93,6 +95,7 @@
<if test="objectives != null">#{objectives},</if> <if test="objectives != null">#{objectives},</if>
<if test="requirements != null">#{requirements},</if> <if test="requirements != null">#{requirements},</if>
<if test="steps != null">#{steps},</if> <if test="steps != null">#{steps},</if>
<if test="stepOneQuestions != null">#{stepOneQuestions},</if>
<if test="materialName != null">#{materialName,jdbcType=VARCHAR},</if> <if test="materialName != null">#{materialName,jdbcType=VARCHAR},</if>
<if test="materialUrl != null">#{materialUrl,jdbcType=VARCHAR},</if> <if test="materialUrl != null">#{materialUrl,jdbcType=VARCHAR},</if>
<if test="sort != null">#{sort,jdbcType=INTEGER},</if> <if test="sort != null">#{sort,jdbcType=INTEGER},</if>
@ -114,6 +117,7 @@
<if test="objectives != null">objectives = #{objectives},</if> <if test="objectives != null">objectives = #{objectives},</if>
<if test="requirements != null">requirements = #{requirements},</if> <if test="requirements != null">requirements = #{requirements},</if>
<if test="steps != null">steps = #{steps},</if> <if test="steps != null">steps = #{steps},</if>
<if test="stepOneQuestions != null">step_one_questions = #{stepOneQuestions},</if>
<if test="materialName != null">material_name = #{materialName,jdbcType=VARCHAR},</if> <if test="materialName != null">material_name = #{materialName,jdbcType=VARCHAR},</if>
<if test="materialUrl != null">material_url = #{materialUrl,jdbcType=VARCHAR},</if> <if test="materialUrl != null">material_url = #{materialUrl,jdbcType=VARCHAR},</if>
<if test="sort != null">sort = #{sort,jdbcType=INTEGER},</if> <if test="sort != null">sort = #{sort,jdbcType=INTEGER},</if>

Loading…
Cancel
Save