From b3d74d1a7a087b70d69c04c55cce526f966a6bfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=B2=85?= <907037276@qq.com> Date: Mon, 28 Sep 2026 16:38:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E4=BB=BB=E5=8A=A1=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=9B=9B=E7=B1=BB=E8=B5=84=E6=96=99=EF=BC=9Atraining?= =?UTF-8?q?=5Ftask=E4=B8=8E=E7=8F=AD=E7=BA=A7=E9=85=8D=E7=BD=AE=E8=A1=A8?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A1=88=E4=BE=8B=E8=A7=86=E9=A2=91/?= =?UTF-8?q?=E5=AE=9E=E8=AE=AD=E6=8C=87=E5=AF=BC=E6=89=8B=E5=86=8C/AI?= =?UTF-8?q?=E6=8E=92=E9=94=99=E6=8C=87=E5=AF=BC=E6=89=8B=E5=86=8C=E5=85=AD?= =?UTF-8?q?=E5=88=97(=E5=AD=98=E9=87=8F=E8=87=AA=E5=8A=A8=E8=A1=A5?= =?UTF-8?q?=E5=88=97)=EF=BC=8C=E5=AE=9E=E4=BD=93=E4=B8=8Emapper=E9=80=8F?= =?UTF-8?q?=E4=BC=A0=EF=BC=8CExcel=E5=AF=BC=E5=85=A5=E6=9C=AA=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E5=AD=97=E6=AE=B5=E4=BF=9D=E7=95=99=E5=8E=9F=E5=80=BC?= =?UTF-8?q?=EF=BC=8C=E9=BB=98=E8=AE=A4=E4=BB=BB=E5=8A=A1=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E7=8F=AD=E7=BA=A7=E6=9C=AA=E6=94=B9=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../linkCommerce/entity/TrainingTask.java | 66 ++++++++++++++ .../entity/TrainingTaskClassConfig.java | 66 ++++++++++++++ .../service/impl/TrainingTaskServiceImpl.java | 90 +++++++++++++++++++ .../mappers/TrainingTaskClassConfigMapper.xml | 28 +++++- .../resources/mappers/TrainingTaskMapper.xml | 28 +++++- 5 files changed, 276 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/TrainingTask.java b/src/main/java/com/sztzjy/linkCommerce/entity/TrainingTask.java index f17a7cf..5d299a0 100644 --- a/src/main/java/com/sztzjy/linkCommerce/entity/TrainingTask.java +++ b/src/main/java/com/sztzjy/linkCommerce/entity/TrainingTask.java @@ -41,6 +41,24 @@ public class TrainingTask { @ApiModelProperty("资料地址") private String materialUrl; + @ApiModelProperty("案例视频资料名称(内部字段沿用trainingData命名)") + private String trainingDataName; + + @ApiModelProperty("案例视频资料地址") + private String trainingDataUrl; + + @ApiModelProperty("实训指导手册名称") + private String guideManualName; + + @ApiModelProperty("实训指导手册地址") + private String guideManualUrl; + + @ApiModelProperty("AI排错指导手册名称(内部字段沿用aiManual命名)") + private String aiManualName; + + @ApiModelProperty("AI排错指导手册地址") + private String aiManualUrl; + @ApiModelProperty("排序") private Integer sort; @@ -152,6 +170,54 @@ public class TrainingTask { this.materialUrl = materialUrl == null ? null : materialUrl.trim(); } + public String getTrainingDataName() { + return trainingDataName; + } + + public void setTrainingDataName(String trainingDataName) { + this.trainingDataName = trainingDataName == null ? null : trainingDataName.trim(); + } + + public String getTrainingDataUrl() { + return trainingDataUrl; + } + + public void setTrainingDataUrl(String trainingDataUrl) { + this.trainingDataUrl = trainingDataUrl == null ? null : trainingDataUrl.trim(); + } + + public String getGuideManualName() { + return guideManualName; + } + + public void setGuideManualName(String guideManualName) { + this.guideManualName = guideManualName == null ? null : guideManualName.trim(); + } + + public String getGuideManualUrl() { + return guideManualUrl; + } + + public void setGuideManualUrl(String guideManualUrl) { + this.guideManualUrl = guideManualUrl == null ? null : guideManualUrl.trim(); + } + + public String getAiManualName() { + return aiManualName; + } + + public void setAiManualName(String aiManualName) { + this.aiManualName = aiManualName == null ? null : aiManualName.trim(); + } + + public String getAiManualUrl() { + return aiManualUrl; + } + + public void setAiManualUrl(String aiManualUrl) { + this.aiManualUrl = aiManualUrl == null ? null : aiManualUrl.trim(); + } + public Integer getSort() { return sort; } diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/TrainingTaskClassConfig.java b/src/main/java/com/sztzjy/linkCommerce/entity/TrainingTaskClassConfig.java index 0ddf4cb..df6331b 100644 --- a/src/main/java/com/sztzjy/linkCommerce/entity/TrainingTaskClassConfig.java +++ b/src/main/java/com/sztzjy/linkCommerce/entity/TrainingTaskClassConfig.java @@ -44,6 +44,24 @@ public class TrainingTaskClassConfig { @ApiModelProperty("Material URL") private String materialUrl; + @ApiModelProperty("Case video material name (legacy trainingData naming)") + private String trainingDataName; + + @ApiModelProperty("Case video material URL") + private String trainingDataUrl; + + @ApiModelProperty("Guide manual name") + private String guideManualName; + + @ApiModelProperty("Guide manual URL") + private String guideManualUrl; + + @ApiModelProperty("AI troubleshooting manual name (legacy aiManual naming)") + private String aiManualName; + + @ApiModelProperty("AI troubleshooting manual URL") + private String aiManualUrl; + @ApiModelProperty("Sort order") private Integer sort; @@ -163,6 +181,54 @@ public class TrainingTaskClassConfig { this.materialUrl = materialUrl == null ? null : materialUrl.trim(); } + public String getTrainingDataName() { + return trainingDataName; + } + + public void setTrainingDataName(String trainingDataName) { + this.trainingDataName = trainingDataName == null ? null : trainingDataName.trim(); + } + + public String getTrainingDataUrl() { + return trainingDataUrl; + } + + public void setTrainingDataUrl(String trainingDataUrl) { + this.trainingDataUrl = trainingDataUrl == null ? null : trainingDataUrl.trim(); + } + + public String getGuideManualName() { + return guideManualName; + } + + public void setGuideManualName(String guideManualName) { + this.guideManualName = guideManualName == null ? null : guideManualName.trim(); + } + + public String getGuideManualUrl() { + return guideManualUrl; + } + + public void setGuideManualUrl(String guideManualUrl) { + this.guideManualUrl = guideManualUrl == null ? null : guideManualUrl.trim(); + } + + public String getAiManualName() { + return aiManualName; + } + + public void setAiManualName(String aiManualName) { + this.aiManualName = aiManualName == null ? null : aiManualName.trim(); + } + + public String getAiManualUrl() { + return aiManualUrl; + } + + public void setAiManualUrl(String aiManualUrl) { + this.aiManualUrl = aiManualUrl == null ? null : aiManualUrl.trim(); + } + public Integer getSort() { return sort; } diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImpl.java index ac18e92..166619a 100644 --- a/src/main/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImpl.java +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/TrainingTaskServiceImpl.java @@ -135,7 +135,20 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { if (existing == null) { throw new IllegalArgumentException("实训任务不存在"); } + // Excel 导入模板不含三类新资料列,未提交(null)时保留库里已有资料;页面编辑始终显式传值(可为空串以清除)。 + String incomingTrainingDataName = task.getTrainingDataName(); + String incomingTrainingDataUrl = task.getTrainingDataUrl(); + String incomingGuideManualName = task.getGuideManualName(); + String incomingGuideManualUrl = task.getGuideManualUrl(); + String incomingAiManualName = task.getAiManualName(); + String incomingAiManualUrl = task.getAiManualUrl(); normalizeTask(task); + if (incomingTrainingDataName == null) task.setTrainingDataName(existing.getTrainingDataName()); + if (incomingTrainingDataUrl == null) task.setTrainingDataUrl(existing.getTrainingDataUrl()); + if (incomingGuideManualName == null) task.setGuideManualName(existing.getGuideManualName()); + if (incomingGuideManualUrl == null) task.setGuideManualUrl(existing.getGuideManualUrl()); + if (incomingAiManualName == null) task.setAiManualName(existing.getAiManualName()); + if (incomingAiManualUrl == null) task.setAiManualUrl(existing.getAiManualUrl()); TrainingTask builtInTask = requireBuiltInTask(existing.getTaskKey()); task.setId(id); task.setTaskKey(existing.getTaskKey()); @@ -610,6 +623,30 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { update.setMaterialUrl(updatedTask.getMaterialUrl()); changed = true; } + if (shouldSynchronize(classTask.getTrainingDataName(), previousTask.getTrainingDataName(), updatedTask.getTrainingDataName())) { + update.setTrainingDataName(updatedTask.getTrainingDataName()); + changed = true; + } + if (shouldSynchronize(classTask.getTrainingDataUrl(), previousTask.getTrainingDataUrl(), updatedTask.getTrainingDataUrl())) { + update.setTrainingDataUrl(updatedTask.getTrainingDataUrl()); + changed = true; + } + if (shouldSynchronize(classTask.getGuideManualName(), previousTask.getGuideManualName(), updatedTask.getGuideManualName())) { + update.setGuideManualName(updatedTask.getGuideManualName()); + changed = true; + } + if (shouldSynchronize(classTask.getGuideManualUrl(), previousTask.getGuideManualUrl(), updatedTask.getGuideManualUrl())) { + update.setGuideManualUrl(updatedTask.getGuideManualUrl()); + changed = true; + } + if (shouldSynchronize(classTask.getAiManualName(), previousTask.getAiManualName(), updatedTask.getAiManualName())) { + update.setAiManualName(updatedTask.getAiManualName()); + changed = true; + } + if (shouldSynchronize(classTask.getAiManualUrl(), previousTask.getAiManualUrl(), updatedTask.getAiManualUrl())) { + update.setAiManualUrl(updatedTask.getAiManualUrl()); + changed = true; + } if (changed) { update.setUpdateTime(new Date()); trainingTaskClassConfigMapper.updateByPrimaryKeySelective(update); @@ -680,6 +717,12 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { task.setStepOneQuestions(config.getStepOneQuestions()); task.setMaterialName(config.getMaterialName()); task.setMaterialUrl(config.getMaterialUrl()); + task.setTrainingDataName(config.getTrainingDataName()); + task.setTrainingDataUrl(config.getTrainingDataUrl()); + task.setGuideManualName(config.getGuideManualName()); + task.setGuideManualUrl(config.getGuideManualUrl()); + task.setAiManualName(config.getAiManualName()); + task.setAiManualUrl(config.getAiManualUrl()); task.setSort(config.getSort()); task.setEnabled(config.getEnabled()); task.setCreatedBy(config.getCreatedBy()); @@ -702,6 +745,12 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { config.setStepOneQuestions(task.getStepOneQuestions()); config.setMaterialName(task.getMaterialName()); config.setMaterialUrl(task.getMaterialUrl()); + config.setTrainingDataName(task.getTrainingDataName()); + config.setTrainingDataUrl(task.getTrainingDataUrl()); + config.setGuideManualName(task.getGuideManualName()); + config.setGuideManualUrl(task.getGuideManualUrl()); + config.setAiManualName(task.getAiManualName()); + config.setAiManualUrl(task.getAiManualUrl()); config.setSort(task.getSort()); config.setEnabled(task.getEnabled()); config.setCreatedBy(operatorId); @@ -725,6 +774,12 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { "step_one_questions text NULL COMMENT '第一步选择题JSON数组'," + "material_name varchar(255) NULL COMMENT '资料名称'," + "material_url varchar(500) NULL COMMENT '资料地址'," + + "training_data_name varchar(255) NULL COMMENT '案例视频资料名称'," + + "training_data_url varchar(500) NULL COMMENT '案例视频资料地址'," + + "guide_manual_name varchar(255) NULL COMMENT '实训指导手册名称'," + + "guide_manual_url varchar(500) NULL COMMENT '实训指导手册地址'," + + "ai_manual_name varchar(255) NULL COMMENT 'AI排错指导手册名称'," + + "ai_manual_url varchar(500) NULL COMMENT 'AI排错指导手册地址'," + "sort int DEFAULT 0 COMMENT '排序'," + "enabled bit(1) DEFAULT b'1' COMMENT '是否启用'," + "created_by varchar(64) NULL COMMENT '创建人'," + @@ -737,6 +792,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='实训任务配置'"); jdbcTemplate.execute("ALTER TABLE training_task CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); ensureTextColumn("training_task", "step_one_questions", "第一步选择题JSON数组"); + ensureMaterialColumns("training_task"); trainingTaskTableChecked = true; } @@ -758,6 +814,12 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { "step_one_questions text NULL," + "material_name varchar(255) NULL," + "material_url varchar(500) NULL," + + "training_data_name varchar(255) NULL," + + "training_data_url varchar(500) NULL," + + "guide_manual_name varchar(255) NULL," + + "guide_manual_url varchar(500) NULL," + + "ai_manual_name varchar(255) NULL," + + "ai_manual_url varchar(500) NULL," + "sort int DEFAULT 0," + "enabled bit(1) DEFAULT b'1'," + "created_by varchar(64) NULL," + @@ -769,6 +831,7 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { "KEY idx_training_task_class_created_by (created_by)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Class scoped training task config'"); ensureTextColumn("training_task_class_config", "step_one_questions", "第一步选择题JSON数组"); + ensureMaterialColumns("training_task_class_config"); trainingTaskClassConfigTableChecked = true; } @@ -788,6 +851,27 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { + " text NULL COMMENT '" + comment + "' AFTER steps"); } + /** 补齐四类资料列:早期只建了 material_name/material_url 的部署需要追加后三类资料列。 */ + private void ensureMaterialColumns(String tableName) { + 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 = 'ai_manual_url'", + Integer.class, tableName); + if (count != null && count > 0) { + return; + } + jdbcTemplate.execute("ALTER TABLE " + tableName + + " ADD COLUMN training_data_name varchar(255) NULL AFTER material_url," + + " ADD COLUMN training_data_url varchar(500) NULL AFTER training_data_name," + + " ADD COLUMN guide_manual_name varchar(255) NULL AFTER training_data_url," + + " ADD COLUMN guide_manual_url varchar(500) NULL AFTER guide_manual_name," + + " ADD COLUMN ai_manual_name varchar(255) NULL AFTER guide_manual_url," + + " ADD COLUMN ai_manual_url varchar(500) NULL AFTER ai_manual_name"); + } + TrainingTask buildTask(TrainingTaskImportDTO row, int rowNumber, List errors) { String projectName = StringUtils.trimToEmpty(row.getProjectName()); String taskKey = StringUtils.trimToEmpty(row.getTaskKey()); @@ -862,6 +946,12 @@ public class TrainingTaskServiceImpl implements TrainingTaskService { task.setStepOneQuestions(normalizeStepOneQuestions(task.getTaskKey(), task.getStepOneQuestions())); task.setMaterialName(StringUtils.trimToEmpty(task.getMaterialName())); task.setMaterialUrl(StringUtils.trimToEmpty(task.getMaterialUrl())); + task.setTrainingDataName(StringUtils.trimToEmpty(task.getTrainingDataName())); + task.setTrainingDataUrl(StringUtils.trimToEmpty(task.getTrainingDataUrl())); + task.setGuideManualName(StringUtils.trimToEmpty(task.getGuideManualName())); + task.setGuideManualUrl(StringUtils.trimToEmpty(task.getGuideManualUrl())); + task.setAiManualName(StringUtils.trimToEmpty(task.getAiManualName())); + task.setAiManualUrl(StringUtils.trimToEmpty(task.getAiManualUrl())); if (task.getEnabled() == null) { task.setEnabled(Boolean.TRUE); } diff --git a/src/main/resources/mappers/TrainingTaskClassConfigMapper.xml b/src/main/resources/mappers/TrainingTaskClassConfigMapper.xml index fe1a58e..92e7f58 100644 --- a/src/main/resources/mappers/TrainingTaskClassConfigMapper.xml +++ b/src/main/resources/mappers/TrainingTaskClassConfigMapper.xml @@ -15,6 +15,12 @@ + + + + + + @@ -24,7 +30,9 @@ id, teaching_class_id, task_key, project_name, task_name, knowledge, background, objectives, requirements, - steps, step_one_questions, material_name, material_url, sort, enabled, created_by, create_time, update_time + steps, step_one_questions, material_name, material_url, + training_data_name, training_data_url, guide_manual_name, guide_manual_url, ai_manual_name, ai_manual_url, + sort, enabled, created_by, create_time, update_time @@ -79,6 +87,12 @@ step_one_questions, material_name, material_url, + training_data_name, + training_data_url, + guide_manual_name, + guide_manual_url, + ai_manual_name, + ai_manual_url, sort, enabled, created_by, @@ -98,6 +112,12 @@ #{stepOneQuestions}, #{materialName,jdbcType=VARCHAR}, #{materialUrl,jdbcType=VARCHAR}, + #{trainingDataName,jdbcType=VARCHAR}, + #{trainingDataUrl,jdbcType=VARCHAR}, + #{guideManualName,jdbcType=VARCHAR}, + #{guideManualUrl,jdbcType=VARCHAR}, + #{aiManualName,jdbcType=VARCHAR}, + #{aiManualUrl,jdbcType=VARCHAR}, #{sort,jdbcType=INTEGER}, #{enabled,jdbcType=BIT}, #{createdBy,jdbcType=VARCHAR}, @@ -120,6 +140,12 @@ step_one_questions = #{stepOneQuestions}, material_name = #{materialName,jdbcType=VARCHAR}, material_url = #{materialUrl,jdbcType=VARCHAR}, + training_data_name = #{trainingDataName,jdbcType=VARCHAR}, + training_data_url = #{trainingDataUrl,jdbcType=VARCHAR}, + guide_manual_name = #{guideManualName,jdbcType=VARCHAR}, + guide_manual_url = #{guideManualUrl,jdbcType=VARCHAR}, + ai_manual_name = #{aiManualName,jdbcType=VARCHAR}, + ai_manual_url = #{aiManualUrl,jdbcType=VARCHAR}, sort = #{sort,jdbcType=INTEGER}, enabled = #{enabled,jdbcType=BIT}, created_by = #{createdBy,jdbcType=VARCHAR},